diff options
| author | Zoltan Ujhelyi | 2017-06-29 09:02:22 +0000 |
|---|---|---|
| committer | Zoltan Ujhelyi | 2017-07-11 09:46:21 +0000 |
| commit | 0dff346884f3c638e4e962eb1ea7ce2253982707 (patch) | |
| tree | eece42149dd67e581e46f2752a2e132456dbc190 | |
| parent | 6e8603fa71bf000c110b14124330de6c8b150b0b (diff) | |
| download | org.eclipse.viatra-0dff346884f3c638e4e962eb1ea7ce2253982707.tar.gz org.eclipse.viatra-0dff346884f3c638e4e962eb1ea7ce2253982707.tar.xz org.eclipse.viatra-0dff346884f3c638e4e962eb1ea7ce2253982707.zip | |
[469149] Initial version of generic local search backend
Change-Id: Ib4951c4178bb87e38dbc42d0a5db06c17dc71adc
Signed-off-by: Zoltan Ujhelyi <ujhelyiz@incquerylabs.com>
18 files changed, 1398 insertions, 903 deletions
diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/.settings/.api_filters b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/.settings/.api_filters index 00ea71416..5a3996d18 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/.settings/.api_filters +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/.settings/.api_filters @@ -27,8 +27,20 @@ <message_argument value="SearchContext"/> </message_arguments> </filter> + <filter comment="Internal API implementation" id="640712815"> + <message_arguments> + <message_argument value="ICache"/> + <message_argument value="SearchContext"/> + <message_argument value="getValue(Object, Class<? extends T>, IProvider<T>)"/> + </message_arguments> + </filter> </resource> <resource path="src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackend.java" type="org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend"> + <filter comment="Internal API update" id="337764418"> + <message_arguments> + <message_argument value="org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend"/> + </message_arguments> + </filter> <filter comment="Internal API usage" id="640708718"> <message_arguments> <message_argument value="PurgableCache()"/> @@ -73,10 +85,10 @@ </filter> </resource> <resource path="src/org/eclipse/viatra/query/runtime/localsearch/plan/IPlanProvider.java" type="org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider"> - <filter comment="Internal API modification" id="403804204"> + <filter comment="Internal API update" id="403804204"> <message_arguments> <message_argument value="org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider"/> - <message_argument value="getPlan(IQueryBackendContext, LocalSearchHints, MatcherReference)"/> + <message_argument value="getPlan(IQueryBackendContext, IOperationCompiler, LocalSearchHints, MatcherReference)"/> </message_arguments> </filter> <filter comment="Internal API modification" id="405901410"> diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/META-INF/MANIFEST.MF b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/META-INF/MANIFEST.MF index f50909db3..8153c9516 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/META-INF/MANIFEST.MF +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/META-INF/MANIFEST.MF @@ -12,19 +12,15 @@ Require-Bundle: org.eclipse.viatra.query.runtime.base;bundle-version="[1.7.0,1.8 org.eclipse.viatra.query.runtime.base.itc;bundle-version="[1.7.0,1.8.0)" Export-Package: org.eclipse.viatra.query.runtime.localsearch, org.eclipse.viatra.query.runtime.localsearch.exceptions, - org.eclipse.viatra.query.runtime.localsearch.matcher; - uses:="com.google.common.collect", - org.eclipse.viatra.query.runtime.localsearch.matcher.integration; - uses:="com.google.common.collect", + org.eclipse.viatra.query.runtime.localsearch.matcher;uses:="com.google.common.collect", + org.eclipse.viatra.query.runtime.localsearch.matcher.integration;uses:="com.google.common.collect", org.eclipse.viatra.query.runtime.localsearch.operations, org.eclipse.viatra.query.runtime.localsearch.operations.check, org.eclipse.viatra.query.runtime.localsearch.operations.extend, - org.eclipse.viatra.query.runtime.localsearch.plan; - uses:="com.google.common.collect", - org.eclipse.viatra.query.runtime.localsearch.planner; - uses:="com.google.common.base", - org.eclipse.viatra.query.runtime.localsearch.planner.cost; - uses:="com.google.common.base", + org.eclipse.viatra.query.runtime.localsearch.plan;uses:="com.google.common.collect", + org.eclipse.viatra.query.runtime.localsearch.planner;uses:="com.google.common.base", + org.eclipse.viatra.query.runtime.localsearch.planner.compiler, + org.eclipse.viatra.query.runtime.localsearch.planner.cost;uses:="com.google.common.base", org.eclipse.viatra.query.runtime.localsearch.planner.cost.impl, org.eclipse.viatra.query.runtime.localsearch.profiler Import-Package: com.google.common.base;version="15.0.0", diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java new file mode 100644 index 000000000..bf511625e --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java @@ -0,0 +1,375 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.matcher.integration; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.Callable; + +import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; +import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame; +import org.eclipse.viatra.query.runtime.localsearch.exceptions.LocalSearchException; +import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext; +import org.eclipse.viatra.query.runtime.localsearch.matcher.LocalSearchMatcher; +import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; +import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanDescriptor; +import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider; +import org.eclipse.viatra.query.runtime.localsearch.plan.SearchPlan; +import org.eclipse.viatra.query.runtime.localsearch.plan.SearchPlanExecutor; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; +import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody; +import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.backend.IUpdateable; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryHintOption; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; +import org.eclipse.viatra.query.runtime.matchers.context.IndexingService; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; +import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; +import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.IFlattenCallPredicate; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public abstract class AbstractLocalSearchResultProvider implements IQueryResultProvider { + + protected final LocalSearchBackend backend; + protected final IQueryBackendContext backendContext; + protected final IQueryRuntimeContext runtimeContext; + protected final PQuery query; + protected final QueryEvaluationHint userHints; + protected final IPlanProvider planProvider; + protected final ISearchContext searchContext; + + /** + * @throws QueryProcessingException + * @since 1.5 + */ + public AbstractLocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query, + IPlanProvider planProvider, QueryEvaluationHint userHints) throws QueryProcessingException { + this.backend = backend; + this.backendContext = context; + this.query = query; + + this.planProvider = planProvider; + this.userHints = userHints; + this.runtimeContext = context.getRuntimeContext(); + this.searchContext = new ISearchContext.SearchContext(backendContext, userHints, backend.getCache()); + } + + protected abstract IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext, LocalSearchHints configuration); + + private IQueryRuntimeContext getRuntimeContext() { + return ((LocalSearchBackend)backend).getRuntimeContext(); + } + + private LocalSearchMatcher createMatcher(IPlanDescriptor plan, final ISearchContext searchContext) { + Collection<SearchPlanForBody> compiledPlans = Lists.newArrayList(plan.getPlan()); + + Collection<SearchPlanExecutor> executors = Collections2.transform(compiledPlans, + new Function<SearchPlanForBody, SearchPlanExecutor>() { + + @Override + public SearchPlanExecutor apply(SearchPlanForBody input) { + final SearchPlan plan = new SearchPlan(); + plan.addOperations(input.getCompiledOperations()); + + return new SearchPlanExecutor(plan, searchContext, input.getVariableKeys()); + } + }); + + final Collection<Integer> parameterSizes = Collections2.transform(compiledPlans, + new Function<SearchPlanForBody, Integer>() { + + @Override + public Integer apply(SearchPlanForBody input) { + PBody body = input.getBody(); + return body.getUniqueVariables().size(); + // return Math.max(input.getSymbolicParameters().size(), input.getUniqueVariables().size()); + } + }); + + return new LocalSearchMatcher(plan, executors, + Collections.max(parameterSizes)); + } + + private IPlanDescriptor createPlan(MatcherReference key, IPlanProvider planProvider) throws QueryProcessingException { + LocalSearchHints configuration = overrideDefaultHints(key.getQuery()); + IOperationCompiler compiler = getOperationCompiler(backendContext, configuration); + IPlanDescriptor plan = planProvider.getPlan(backendContext, compiler, configuration, key); + return plan; + } + + private LocalSearchHints overrideDefaultHints(PQuery pQuery) { + return LocalSearchHints.getDefaultOverriddenBy( + computeOverridingHints(pQuery)); + } + + /** + * Combine with {@link QueryHintOption#getValueOrDefault(QueryEvaluationHint)} to access + * hint settings not covered by {@link LocalSearchHints} + */ + private QueryEvaluationHint computeOverridingHints(PQuery pQuery) { + return backendContext.getHintProvider().getQueryEvaluationHint(pQuery).overrideBy(userHints); + } + + private Iterator<MatcherReference> computeExpectedAdornments() { + return Iterators.transform(overrideDefaultHints(query).getAdornmentProvider().getAdornments(query).iterator(), new Function<Set<PParameter>, MatcherReference>() { + + @Override + public MatcherReference apply(Set<PParameter> input) { + return new MatcherReference(query, input, userHints); + } + }); + } + + /** + * Prepare this result provider. This phase is separated from the constructor to allow the backend to cache its instance before + * requesting preparation for its dependencies. + * @since 1.5 + */ + public void prepare() throws QueryProcessingException { + try { + runtimeContext.coalesceTraversals(new Callable<Void>() { + + @Override + public Void call() throws Exception { + indexInitializationBeforePlanning(); + prepareDirectDependencies(); + runtimeContext.executeAfterTraversal(new Runnable() { + + @Override + public void run() { + try { + preparePlansForExpectedAdornments(); + } catch (QueryProcessingException e) { + throw new RuntimeException(e); + } + } + }); + return null; + } + }); + } catch (InvocationTargetException e) { + throw new QueryProcessingException("Error while building required indexes: %s", new String[]{e.getTargetException().getMessage()}, "Error while building required indexes.", query, e); + } + } + + protected void preparePlansForExpectedAdornments() throws QueryProcessingException { + // Plan for possible adornments + Iterator<MatcherReference> iterator = computeExpectedAdornments(); + while(iterator.hasNext()){ + LocalSearchHints configuration = overrideDefaultHints(query); + IOperationCompiler compiler = getOperationCompiler(backendContext, configuration); + IPlanDescriptor plan = planProvider.getPlan(backendContext, compiler, configuration, iterator.next()); + // Index keys + try { + indexKeys(plan.getIteratedKeys()); + } catch (InvocationTargetException e) { + throw new QueryProcessingException(e.getMessage(), null, e.getMessage(), query, e); + } + //Prepare dependencies + for(SearchPlanForBody body: plan.getPlan()){ + for(MatcherReference dependency : body.getDependencies()){ + try { + searchContext.getMatcher(dependency); + } catch (LocalSearchException e) { + throw new QueryProcessingException("Could not prepare dependency {1}", new String[]{dependency.toString()}, e.getMessage(), query, e); + } + } + } + } + + } + + protected void prepareDirectDependencies() throws QueryProcessingException { + // Do not prepare for any adornment at this point + IAdornmentProvider adornmentProvider = new IAdornmentProvider() { + + @Override + public Iterable<Set<PParameter>> getAdornments(PQuery query) { + return Collections.emptySet(); + } + }; + @SuppressWarnings("rawtypes") + QueryEvaluationHint hints = new QueryEvaluationHint(Collections.<QueryHintOption, Object>singletonMap(LocalSearchHintOptions.ADORNMENT_PROVIDER, adornmentProvider), null); + for(PQuery dep : getDirectPositiveDependencies()){ + backendContext.getResultProviderAccess().getResultProvider(dep, hints); + } + } + + /** + * This method is called before planning start to allow indexing. It is important to note that this method is called + * inside a coalesceTraversals block, meaning (1) it is safe to add multiple registration requests as necessary, but + * (2) no value or statistics is available from the index. + * + * @throws QueryProcessingException + */ + protected void indexInitializationBeforePlanning() throws QueryProcessingException { + // By default, no indexing is necessary + } + + private Set<PQuery> getDirectPositiveDependencies() { + IFlattenCallPredicate flattenPredicate = overrideDefaultHints(query).getFlattenCallPredicate(); + Queue<PQuery> queue = new LinkedList<PQuery>(); + Set<PQuery> visited = new HashSet<PQuery>(); + Set<PQuery> result = new HashSet<PQuery>(); + queue.add(query); + + while(!queue.isEmpty()){ + PQuery next = queue.poll(); + visited.add(next); + for(PBody body : next.getDisjunctBodies().getBodies()){ + for(PositivePatternCall ppc : body.getConstraintsOfType(PositivePatternCall.class)){ + PQuery dep = ppc.getSupplierKey(); + if (flattenPredicate.shouldFlatten(ppc)){ + if (!visited.contains(dep)){ + queue.add(dep); + } + }else{ + result.add(dep); + } + } + } + } + return result; + } + + private LocalSearchMatcher initializeMatcher(Object[] parameters) { + try { + return newLocalSearchMatcher(parameters); + } catch (QueryProcessingException | ViatraQueryException e) { + throw new RuntimeException(e); + } + + } + + public LocalSearchMatcher newLocalSearchMatcher(Object[] parameters) throws ViatraQueryException, QueryProcessingException { + + final Set<PParameter> adornment = Sets.newHashSet(); + for (int i = 0; i < parameters.length; i++) { + if (parameters[i] != null) { + adornment.add(query.getParameters().get(i)); + } + } + + final MatcherReference reference = new MatcherReference(query, adornment, userHints); + + IPlanDescriptor plan = createPlan(reference, planProvider); + if (overrideDefaultHints(reference.getQuery()).isUseBase()){ + try { + indexKeys(plan.getIteratedKeys()); + } catch (InvocationTargetException e) { + throw new ViatraQueryException("Could not index keys","Could not index keys", e); + } + } + + LocalSearchMatcher matcher = createMatcher(plan, searchContext); + matcher.addAdapters(backend.getAdapters()); + return matcher; + } + + private void indexKeys(final Iterable<IInputKey> keys) throws InvocationTargetException { + final IQueryRuntimeContext qrc = getRuntimeContext(); + qrc.coalesceTraversals(new Callable<Void>() { + + @Override + public Void call() throws Exception { + for(IInputKey key : keys){ + qrc.ensureIndexed(key, IndexingService.INSTANCES); + } + return null; + } + }); + } + + @Override + public Tuple getOneArbitraryMatch(Object[] parameters) { + try { + final LocalSearchMatcher matcher = initializeMatcher(parameters); + final MatchingFrame frame = matcher.editableMatchingFrame(); + frame.setParameterValues(parameters); + return matcher.getOneArbitraryMatch(frame); + } catch (LocalSearchException e) { + throw new RuntimeException(e); + } + } + + @Override + public int countMatches(Object[] parameters) { + try { + final LocalSearchMatcher matcher = initializeMatcher(parameters); + final MatchingFrame frame = matcher.editableMatchingFrame(); + frame.setParameterValues(parameters); + return matcher.countMatches(frame); + } catch (LocalSearchException e) { + throw new RuntimeException(e); + } + } + + @Override + public Collection<? extends Tuple> getAllMatches(Object[] parameters) { + try { + final LocalSearchMatcher matcher = initializeMatcher(parameters); + final MatchingFrame frame = matcher.editableMatchingFrame(); + frame.setParameterValues(parameters); + return matcher.getAllMatches(frame); + } catch (LocalSearchException e) { + throw new RuntimeException(e); + } + } + + @Override + public IQueryBackend getQueryBackend() { + return backend; + } + + @Override + public void addUpdateListener(IUpdateable listener, Object listenerTag, boolean fireNow) { + // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED); + } + + @Override + public void removeUpdateListener(Object listenerTag) { + // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED); + } + + /** + * @since 1.4 + */ + public IMatcherCapability getCapabilites() { + LocalSearchHints configuration = overrideDefaultHints(query); + return configuration; + } + +}
\ No newline at end of file diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java new file mode 100644 index 000000000..093dc0f1e --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Marton Bur, 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, Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.matcher.integration; + +import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.GenericOperationCompiler; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.context.IndexingService; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; +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.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public class GenericLocalSearchResultProvider extends AbstractLocalSearchResultProvider { + + public GenericLocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query, + IPlanProvider planProvider, QueryEvaluationHint userHints) throws QueryProcessingException { + super(backend, context, query, planProvider, userHints); + } + + @Override + protected void indexInitializationBeforePlanning() throws QueryProcessingException { + super.indexInitializationBeforePlanning(); + + for (PBody body : query.getDisjunctBodies().getBodies()) { + for (PConstraint constraint : body.getConstraints()) { + if (constraint instanceof TypeConstraint) { + runtimeContext.ensureIndexed(((TypeConstraint) constraint).getSupplierKey(), IndexingService.INSTANCES); + } + } + } + } + + @Override + protected IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext, + LocalSearchHints configuration) { + return new GenericOperationCompiler(runtimeContext); + } + +} diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackend.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackend.java index 0441b7f7b..24e3674d1 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackend.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackend.java @@ -41,19 +41,23 @@ import com.google.common.collect.Table; /** * @author Marton Bur, Zoltan Ujhelyi - * + * @noextend This class is not intended to be subclassed by clients. */ -public class LocalSearchBackend implements IQueryBackend { +public abstract class LocalSearchBackend implements IQueryBackend { IQueryBackendContext context; IPlanProvider planProvider; private final Set<ILocalSearchAdapter> adapters = Sets.newHashSet(); // Cache - private final Table<EDataType, EClass, Set<EAttribute>> eAttributesByTypeForEClass; + /* + * @deprecated Use generalCache instead + */ + @Deprecated + private final Table<EDataType, EClass, Set<EAttribute>> eAttributesByTypeForEClass = HashBasedTable.create(); private final PurgableCache generalCache; - private final Multimap<PQuery, LocalSearchResultProvider> resultProviderCache = ArrayListMultimap.create(); + private final Multimap<PQuery, AbstractLocalSearchResultProvider> resultProviderCache = ArrayListMultimap.create(); /** * @since 1.5 @@ -61,7 +65,6 @@ public class LocalSearchBackend implements IQueryBackend { public LocalSearchBackend(IQueryBackendContext context) { super(); this.context = context; - this.eAttributesByTypeForEClass = HashBasedTable.create(); this.generalCache = new PurgableCache(); this.planProvider = new CachingPlanProvider(context.getLogger()); } @@ -84,18 +87,24 @@ public class LocalSearchBackend implements IQueryBackend { throws QueryProcessingException { IMatcherCapability requestedCapability = getHintProvider().getQueryEvaluationHint(query).overrideBy(hints).calculateRequiredCapability(query); - for(LocalSearchResultProvider existingResultProvider : resultProviderCache.get(query)){ + for(AbstractLocalSearchResultProvider existingResultProvider : resultProviderCache.get(query)){ if (requestedCapability.canBeSubstitute(existingResultProvider.getCapabilites())){ return existingResultProvider; } } - LocalSearchResultProvider resultProvider = new LocalSearchResultProvider(this, context, query, planProvider, hints); + AbstractLocalSearchResultProvider resultProvider = initializeResultProvider(query, hints); resultProviderCache.put(query, resultProvider); resultProvider.prepare(); return resultProvider; } + /** + * @throws QueryProcessingException + * @since 1.7 + */ + protected abstract AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints) throws QueryProcessingException; + @Override public void dispose() { eAttributesByTypeForEClass.clear(); @@ -113,6 +122,11 @@ public class LocalSearchBackend implements IQueryBackend { return null; } + /** + * + * @deprecated use the general caching mechanism instead + */ + @Deprecated public Table<EDataType, EClass, Set<EAttribute>> geteAttributesByTypeForEClass() { return eAttributesByTypeForEClass; } diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackendFactory.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackendFactory.java index 25490b5e5..0d73caa92 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackendFactory.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchBackendFactory.java @@ -15,6 +15,7 @@ import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; /** @@ -30,7 +31,13 @@ public enum LocalSearchBackendFactory implements IQueryBackendFactory { */ @Override public IQueryBackend create(IQueryBackendContext context) { - return new LocalSearchBackend(context); + return new LocalSearchBackend(context) { + + @Override + protected AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints) throws QueryProcessingException { + return new LocalSearchResultProvider(this, context, query, planProvider, hints); + } + }; } @Override diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java new file mode 100644 index 000000000..5630994fb --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Marton Bur, 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, Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.matcher.integration; + +import java.util.Set; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +import com.google.common.collect.Table; + +/** + * @author Marton Bur, Zoltan Ujhelyi + * @since 1.7 + * + */ +public enum LocalSearchGenericBackendFactory implements IQueryBackendFactory { + + INSTANCE; + + /** + * @since 1.5 + */ + @Override + public IQueryBackend create(IQueryBackendContext context) { + return new LocalSearchBackend(context) { + + @Override + protected AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints) throws QueryProcessingException { + return new GenericLocalSearchResultProvider(this, context, query, planProvider, hints); + } + + @Override + public Table<EDataType, EClass, Set<EAttribute>> geteAttributesByTypeForEClass() { + throw new UnsupportedOperationException("geteAttributesByTypeForEClass() is a legacy call not supported by the generic LS backend."); + } + + + }; + } + + @Override + public Class<? extends IQueryBackend> getBackendClass() { + return LocalSearchBackend.class; + } + + /** + * @since 1.4 + */ + @Override + public IMatcherCapability calculateRequiredCapability(PQuery query, QueryEvaluationHint hint) { + return LocalSearchHints.parse(hint); + } + +} diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchHints.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchHints.java index da84b3f58..ea7c1af9a 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchHints.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchHints.java @@ -23,6 +23,7 @@ import org.eclipse.viatra.query.runtime.localsearch.planner.cost.ICostFunction; import org.eclipse.viatra.query.runtime.localsearch.planner.cost.impl.IndexerBasedConstraintCostFunction; import org.eclipse.viatra.query.runtime.localsearch.planner.cost.impl.VariableBindingBasedCostFunction; import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import org.eclipse.viatra.query.runtime.matchers.backend.QueryHintOption; import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.DefaultFlattenCallPredicate; @@ -55,6 +56,8 @@ public final class LocalSearchHints implements IMatcherCapability { private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE; + private IQueryBackendFactory backendFactory = null; + private LocalSearchHints() {} /** @@ -74,6 +77,7 @@ public final class LocalSearchHints implements IMatcherCapability { result.costFunction = PLANNER_COST_FUNCTION.getDefaultValue(); result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getDefaultValue(); result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue(); + result.backendFactory = LocalSearchBackendFactory.INSTANCE; return result; } @@ -88,6 +92,7 @@ public final class LocalSearchHints implements IMatcherCapability { result.costFunction = new IndexerBasedConstraintCostFunction(); result.flattenCallPredicate = new DefaultFlattenCallPredicate(); result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue(); + result.backendFactory = LocalSearchBackendFactory.INSTANCE; return result; } @@ -101,6 +106,22 @@ public final class LocalSearchHints implements IMatcherCapability { result.costFunction = new VariableBindingBasedCostFunction(); result.flattenCallPredicate = new NeverFlattenCallPredicate(); result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue(); + result.backendFactory = LocalSearchBackendFactory.INSTANCE; + return result; + } + + /** + * Initializes the generic (not EMF specific) search backend with the default settings + * @since 1.7 + */ + public static LocalSearchHints getDefaultGeneric(){ + LocalSearchHints result = new LocalSearchHints(); + result.useBase = false; + result.rowCount = 4; + result.costFunction = new VariableBindingBasedCostFunction(); + result.flattenCallPredicate = new NeverFlattenCallPredicate(); + result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue(); + result.backendFactory = LocalSearchGenericBackendFactory.INSTANCE; return result; } @@ -138,7 +159,7 @@ public final class LocalSearchHints implements IMatcherCapability { if (traceCollector != null){ normalizationTraceCollector.insertOverridingValue(map, traceCollector); } - return new QueryEvaluationHint(map, LocalSearchBackendFactory.INSTANCE); + return new QueryEvaluationHint(map, backendFactory); } public boolean isUseBase() { diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java index fa2b98ef8..c379b0e57 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java @@ -10,125 +10,23 @@ *******************************************************************************/ package org.eclipse.viatra.query.runtime.localsearch.matcher.integration; -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.Callable; - -import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; -import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame; -import org.eclipse.viatra.query.runtime.localsearch.exceptions.LocalSearchException; -import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext; -import org.eclipse.viatra.query.runtime.localsearch.matcher.LocalSearchMatcher; -import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; -import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanDescriptor; import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider; -import org.eclipse.viatra.query.runtime.localsearch.plan.SearchPlan; -import org.eclipse.viatra.query.runtime.localsearch.plan.SearchPlanExecutor; -import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody; -import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendHintProvider; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; -import org.eclipse.viatra.query.runtime.matchers.backend.IUpdateable; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.EMFOperationCompiler; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; -import org.eclipse.viatra.query.runtime.matchers.backend.QueryHintOption; -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; -import org.eclipse.viatra.query.runtime.matchers.context.IQueryResultProviderAccess; -import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; import org.eclipse.viatra.query.runtime.matchers.context.IndexingService; import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; -import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; -import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; -import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.IFlattenCallPredicate; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; - -import com.google.common.base.Function; -import com.google.common.collect.Collections2; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; /** * @author Marton Bur, Zoltan Ujhelyi * */ -public class LocalSearchResultProvider implements IQueryResultProvider { - - private final LocalSearchBackend backend; - private final IQueryBackendHintProvider hintProvider; - private final IQueryRuntimeContext runtimeContext; - private final PQuery query; - private final IQueryResultProviderAccess resultProviderAccess; - private final QueryEvaluationHint userHints; - - private final IPlanProvider planProvider; - private final ISearchContext searchContext; - - private IQueryRuntimeContext getRuntimeContext(){ - return ((LocalSearchBackend)backend).getRuntimeContext(); - } - - private LocalSearchMatcher createMatcher(IPlanDescriptor plan, final ISearchContext searchContext){ - Collection<SearchPlanForBody> compiledPlans = Lists.newArrayList(plan.getPlan()); - - Collection<SearchPlanExecutor> executors = Collections2.transform(compiledPlans, - new Function<SearchPlanForBody, SearchPlanExecutor>() { - - @Override - public SearchPlanExecutor apply(SearchPlanForBody input) { - final SearchPlan plan = new SearchPlan(); - plan.addOperations(input.getCompiledOperations()); - - return new SearchPlanExecutor(plan, searchContext, input.getVariableKeys()); - } - }); - - final Collection<Integer> parameterSizes = Collections2.transform(compiledPlans, - new Function<SearchPlanForBody, Integer>() { - - @Override - public Integer apply(SearchPlanForBody input) { - PBody body = input.getBody(); - return body.getUniqueVariables().size(); - // return Math.max(input.getSymbolicParameters().size(), input.getUniqueVariables().size()); - } - }); - - return new LocalSearchMatcher(plan, executors, - Collections.max(parameterSizes)); - } - - private IPlanDescriptor createPlan(MatcherReference key, IPlanProvider planProvider) throws QueryProcessingException { - LocalSearchHints configuration = overrideDefaultHints(key.getQuery()); - IPlanDescriptor plan = planProvider.getPlan(backend.getBackendContext(), configuration, key); - return plan; - } - - - private LocalSearchHints overrideDefaultHints(PQuery pQuery) { - return LocalSearchHints.getDefaultOverriddenBy( - computeOverridingHints(pQuery)); - } - - /** - * Combine with {@link QueryHintOption#getValueOrDefault(QueryEvaluationHint)} to access - * hint settings not covered by {@link LocalSearchHints} - */ - private QueryEvaluationHint computeOverridingHints(PQuery pQuery) { - return hintProvider.getQueryEvaluationHint(pQuery).overrideBy(userHints); - } +public class LocalSearchResultProvider extends AbstractLocalSearchResultProvider { /** - * @throws QueryProcessingException + * @throws QueryProcessingException * @since 1.5 */ public LocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query, @@ -136,239 +34,24 @@ public class LocalSearchResultProvider implements IQueryResultProvider { this(backend, context, query, planProvider, null); } - private Iterator<MatcherReference> computeExpectedAdornments(){ - return Iterators.transform(overrideDefaultHints(query).getAdornmentProvider().getAdornments(query).iterator(), new Function<Set<PParameter>, MatcherReference>() { - - @Override - public MatcherReference apply(Set<PParameter> input) { - return new MatcherReference(query, input, userHints); - } - }); - } - /** - * @throws QueryProcessingException + * @throws QueryProcessingException * @since 1.5 */ public LocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query, IPlanProvider planProvider, QueryEvaluationHint userHints) throws QueryProcessingException { - this.backend = backend; - this.resultProviderAccess = context.getResultProviderAccess(); - this.hintProvider = context.getHintProvider(); - this.query = query; - - this.planProvider = planProvider; - this.userHints = userHints; - this.runtimeContext = context.getRuntimeContext(); - - this.searchContext = new ISearchContext.SearchContext(context, userHints, backend.getCache()); - } - - /** - * Prepare this result provider. This phase is separated from the constructor to allow the backend to cache its instance before - * requesting preparation for its dependencies. - * @since 1.5 - */ - public void prepare() throws QueryProcessingException{ - try { - runtimeContext.coalesceTraversals(new Callable<Void>() { - - @Override - public Void call() throws Exception { - runtimeContext.ensureWildcardIndexing(IndexingService.STATISTICS); - prepareDirectDependencies(); - runtimeContext.executeAfterTraversal(new Runnable() { - - @Override - public void run() { - try { - preparePlansForExpectedAdornments(); - } catch (QueryProcessingException e) { - throw new RuntimeException(e); - } - } - }); - return null; - } - }); - } catch (InvocationTargetException e) { - throw new QueryProcessingException("Error while building required indexes: %s", new String[]{e.getTargetException().getMessage()}, "Error while building required indexes.", query, e); - } - } - - private void preparePlansForExpectedAdornments() throws QueryProcessingException{ - // Plan for possible adornments - Iterator<MatcherReference> iterator = computeExpectedAdornments(); - while(iterator.hasNext()){ - IPlanDescriptor plan = planProvider.getPlan(backend.getBackendContext(), overrideDefaultHints(query), iterator.next()); - // Index keys - try { - indexKeys(plan.getIteratedKeys()); - } catch (InvocationTargetException e) { - throw new QueryProcessingException(e.getMessage(), null, e.getMessage(), query, e); - } - //Prepare dependencies - for(SearchPlanForBody body: plan.getPlan()){ - for(MatcherReference dependency : body.getDependencies()){ - try { - searchContext.getMatcher(dependency); - } catch (LocalSearchException e) { - throw new QueryProcessingException("Could not prepare dependency {1}", new String[]{dependency.toString()}, e.getMessage(), query, e); - } - } - } - } - - } - - private void prepareDirectDependencies() throws QueryProcessingException{ - // Do not prepare for any adornment at this point - IAdornmentProvider adornmentProvider = new IAdornmentProvider() { - - @Override - public Iterable<Set<PParameter>> getAdornments(PQuery query) { - return Collections.emptySet(); - } - }; - @SuppressWarnings("rawtypes") - QueryEvaluationHint hints = new QueryEvaluationHint(Collections.<QueryHintOption, Object>singletonMap(LocalSearchHintOptions.ADORNMENT_PROVIDER, adornmentProvider), null); - for(PQuery dep : getDirectPositiveDependencies()){ - resultProviderAccess.getResultProvider(dep, hints); - } - } - - private Set<PQuery> getDirectPositiveDependencies(){ - IFlattenCallPredicate flattenPredicate = overrideDefaultHints(query).getFlattenCallPredicate(); - Queue<PQuery> queue = new LinkedList<PQuery>(); - Set<PQuery> visited = new HashSet<PQuery>(); - Set<PQuery> result = new HashSet<PQuery>(); - queue.add(query); - - while(!queue.isEmpty()){ - PQuery next = queue.poll(); - visited.add(next); - for(PBody body : next.getDisjunctBodies().getBodies()){ - for(PositivePatternCall ppc : body.getConstraintsOfType(PositivePatternCall.class)){ - PQuery dep = ppc.getSupplierKey(); - if (flattenPredicate.shouldFlatten(ppc)){ - if (!visited.contains(dep)){ - queue.add(dep); - } - }else{ - result.add(dep); - } - } - } - } - return result; - } - - private LocalSearchMatcher initializeMatcher(Object[] parameters) { - try { - return newLocalSearchMatcher(parameters); - } catch (QueryProcessingException | ViatraQueryException e) { - throw new RuntimeException(e); - } - - } - - public LocalSearchMatcher newLocalSearchMatcher(Object[] parameters) - throws ViatraQueryException, QueryProcessingException { - - final Set<PParameter> adornment = Sets.newHashSet(); - for (int i = 0; i < parameters.length; i++) { - if (parameters[i] != null) { - adornment.add(query.getParameters().get(i)); - } - } - - final MatcherReference reference = new MatcherReference(query, adornment, userHints); - - IPlanDescriptor plan = createPlan(reference, planProvider); - if (overrideDefaultHints(reference.getQuery()).isUseBase()){ - try { - indexKeys(plan.getIteratedKeys()); - } catch (InvocationTargetException e) { - throw new ViatraQueryException("Could not index keys","Could not index keys", e); - } - } - - LocalSearchMatcher matcher = createMatcher(plan, searchContext); - matcher.addAdapters(backend.getAdapters()); - return matcher; - } - - private void indexKeys(final Iterable<IInputKey> keys) throws InvocationTargetException{ - final IQueryRuntimeContext qrc = getRuntimeContext(); - qrc.coalesceTraversals(new Callable<Void>() { - - @Override - public Void call() throws Exception { - for(IInputKey key : keys){ - qrc.ensureIndexed(key, IndexingService.INSTANCES); - } - return null; - } - }); - } - - @Override - public Tuple getOneArbitraryMatch(Object[] parameters) { - try { - final LocalSearchMatcher matcher = initializeMatcher(parameters); - final MatchingFrame frame = matcher.editableMatchingFrame(); - frame.setParameterValues(parameters); - return matcher.getOneArbitraryMatch(frame); - } catch (LocalSearchException e) { - throw new RuntimeException(e); - } - } - - @Override - public int countMatches(Object[] parameters) { - try { - final LocalSearchMatcher matcher = initializeMatcher(parameters); - final MatchingFrame frame = matcher.editableMatchingFrame(); - frame.setParameterValues(parameters); - return matcher.countMatches(frame); - } catch (LocalSearchException e) { - throw new RuntimeException(e); - } - } - - @Override - public Collection<? extends Tuple> getAllMatches(Object[] parameters) { - try { - final LocalSearchMatcher matcher = initializeMatcher(parameters); - final MatchingFrame frame = matcher.editableMatchingFrame(); - frame.setParameterValues(parameters); - return matcher.getAllMatches(frame); - } catch (LocalSearchException e) { - throw new RuntimeException(e); - } + super(backend, context, query, planProvider, userHints); } @Override - public IQueryBackend getQueryBackend() { - return backend; + protected void indexInitializationBeforePlanning() throws QueryProcessingException { + super.indexInitializationBeforePlanning(); + runtimeContext.ensureWildcardIndexing(IndexingService.STATISTICS); } @Override - public void addUpdateListener(IUpdateable listener, Object listenerTag, boolean fireNow) { - // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED); - } - - @Override - public void removeUpdateListener(Object listenerTag) { - // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED); - } - - /** - * @since 1.4 - */ - public IMatcherCapability getCapabilites() { - LocalSearchHints configuration = overrideDefaultHints(query); - return configuration; + protected IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext, + LocalSearchHints configuration) { + return new EMFOperationCompiler(runtimeContext, configuration.isUseBase()); } - } diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/CachingPlanProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/CachingPlanProvider.java index 5cf34a649..43fefd5e2 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/CachingPlanProvider.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/CachingPlanProvider.java @@ -17,6 +17,8 @@ import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints; import org.eclipse.viatra.query.runtime.localsearch.planner.LocalSearchPlanner; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.EMFOperationCompiler; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody; import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; @@ -47,11 +49,12 @@ public class CachingPlanProvider implements IPlanProvider { @Deprecated public IPlanDescriptor getPlan(LocalSearchBackend backend, final LocalSearchHints configuration, MatcherReference key) throws QueryProcessingException { - return getPlan(backend.getBackendContext(), configuration, key); + IOperationCompiler compiler = new EMFOperationCompiler(backend.getRuntimeContext(), configuration.isUseBase()); + return getPlan(backend.getBackendContext(), compiler, configuration, key); } @Override - public IPlanDescriptor getPlan(IQueryBackendContext backend, final LocalSearchHints configuration, MatcherReference key) + public IPlanDescriptor getPlan(IQueryBackendContext backend, IOperationCompiler compiler, final LocalSearchHints configuration, MatcherReference key) throws QueryProcessingException { if (cache.containsKey(key)){ @@ -59,7 +62,7 @@ public class CachingPlanProvider implements IPlanProvider { return cache.get(key).iterator().next(); }else{ - LocalSearchPlanner planner = new LocalSearchPlanner(backend, logger, configuration); + LocalSearchPlanner planner = new LocalSearchPlanner(backend, compiler, logger, configuration); Collection<SearchPlanForBody> plansForBodies = planner.plan(key.getQuery(), key.getAdornment()); diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/IPlanProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/IPlanProvider.java index 029671f61..6d759d30c 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/IPlanProvider.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/plan/IPlanProvider.java @@ -12,6 +12,7 @@ package org.eclipse.viatra.query.runtime.localsearch.plan; import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; @@ -25,6 +26,6 @@ public interface IPlanProvider { /** * @since 1.7 */ - public IPlanDescriptor getPlan(IQueryBackendContext backend, LocalSearchHints configuration, MatcherReference key) throws QueryProcessingException; + public IPlanDescriptor getPlan(IQueryBackendContext backend, IOperationCompiler compiler, LocalSearchHints configuration, MatcherReference key) throws QueryProcessingException; } diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/ILocalSearchPlanner.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/ILocalSearchPlanner.java new file mode 100644 index 000000000..1cd3e68ca --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/ILocalSearchPlanner.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.planner; + +import java.util.Collection; +import java.util.Set; + +import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + */ +public interface ILocalSearchPlanner { + + /** + * 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 boundParameters + * a set of bound parameters + * @return a mapping between ISearchOperation list and a mapping, that holds a PVariable-Integer mapping for the + * list of ISearchOperations + * @throws QueryProcessingException + */ + Collection<SearchPlanForBody> plan(PQuery querySpec, Set<PParameter> boundParameters) + throws QueryProcessingException; + +}
\ No newline at end of file diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/LocalSearchPlanner.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/LocalSearchPlanner.java index 8f7c122a8..8559a52bb 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/LocalSearchPlanner.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/LocalSearchPlanner.java @@ -19,6 +19,8 @@ import org.apache.log4j.Logger; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints; import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.EMFOperationCompiler; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody; import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; @@ -43,13 +45,14 @@ import com.google.common.collect.Sets; * @author Marton Bur * @noreference This class is not intended to be referenced by clients. */ -public class LocalSearchPlanner { +public class LocalSearchPlanner implements ILocalSearchPlanner { // Externally set tools for planning private final PDisjunctionRewriter preprocessor; private final LocalSearchRuntimeBasedStrategy plannerStrategy; private final IQueryRuntimeContext runtimeContext; private final LocalSearchHints configuration; + private final IOperationCompiler operationCompiler; private final IQueryBackendContext context; // private final LocalSearchBackend backend; @@ -59,16 +62,19 @@ public class LocalSearchPlanner { */ @Deprecated public LocalSearchPlanner(LocalSearchBackend backend, Logger logger, final LocalSearchHints configuration) { - this(backend.getBackendContext(), logger, configuration); + this(backend.getBackendContext(), + new EMFOperationCompiler(backend.getRuntimeContext(), configuration.isUseBase()), logger, + configuration); } /** * @since 1.7 */ - public LocalSearchPlanner(IQueryBackendContext backendContext, Logger logger, final LocalSearchHints configuration) { + public LocalSearchPlanner(IQueryBackendContext backendContext, IOperationCompiler compiler, Logger logger, final LocalSearchHints configuration) { this.runtimeContext = backendContext.getRuntimeContext(); this.configuration = configuration; + this.operationCompiler = compiler; PQueryFlattener flattener = new PQueryFlattener(configuration.getFlattenCallPredicate()); /* * TODO https://bugs.eclipse.org/bugs/show_bug.cgi?id=439358: The normalizer is initialized with the false @@ -102,6 +108,7 @@ public class LocalSearchPlanner { * list of ISearchOperations * @throws QueryProcessingException */ + @Override public Collection<SearchPlanForBody> plan(PQuery querySpec, Set<PParameter> boundParameters) throws QueryProcessingException { // 1. Preparation @@ -117,7 +124,6 @@ public class LocalSearchPlanner { SubPlan plan = plannerStrategy.plan(normalizedBody, boundVariables, context, configuration); // 3. PConstraint -> POperation compilation step // * Pay extra caution to extend operations, when more than one variables are unbound - POperationCompiler operationCompiler = new POperationCompiler(runtimeContext, configuration.isUseBase()); List<ISearchOperation> compiledOperations = operationCompiler.compile(plan, boundParameters); // Store the variable mappings for the plans for debug purposes (traceability information) SearchPlanForBody compiledPlan = new SearchPlanForBody(normalizedBody, diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/POperationCompiler.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/POperationCompiler.java index 2d8f393f1..a2b2f3cdd 100644 --- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/POperationCompiler.java +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/POperationCompiler.java @@ -10,563 +10,24 @@ *******************************************************************************/ package org.eclipse.viatra.query.runtime.localsearch.planner; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.viatra.query.runtime.emf.EMFQueryRuntimeContext; -import org.eclipse.viatra.query.runtime.emf.types.EClassTransitiveInstancesKey; -import org.eclipse.viatra.query.runtime.emf.types.EClassUnscopedTransitiveInstancesKey; -import org.eclipse.viatra.query.runtime.emf.types.EDataTypeInSlotsKey; -import org.eclipse.viatra.query.runtime.emf.types.EStructuralFeatureInstancesKey; -import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; -import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.AggregatorCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.BinaryTransitiveClosureCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.CheckConstant; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.CheckPositivePatternCall; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.CountCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.ExpressionCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.ExpressionEvalCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.InequalityCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfClassCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfDataTypeCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfJavaClassCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.NACOperation; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.StructuralFeatureCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.check.nobase.ScopeCheck; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.AggregatorExtend; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.CountOperation; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExpressionEval; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendBinaryTransitiveClosure; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendConstant; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendPositivePatternCall; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureSource; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureTarget; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverContainers; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverEClassInstances; -import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverEDatatypeInstances; -import org.eclipse.viatra.query.runtime.localsearch.planner.util.CompilerHelper; -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.EMFOperationCompiler; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; -import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; -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.planning.operations.PApply; -import org.eclipse.viatra.query.runtime.matchers.planning.operations.POperation; -import org.eclipse.viatra.query.runtime.matchers.planning.operations.PProject; -import org.eclipse.viatra.query.runtime.matchers.planning.operations.PStart; -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.basicdeferred.AggregatorConstraint; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.PatternCallBasedDeferred; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.PatternMatchCounter; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.ConstantValue; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; -import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; -import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; - -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; /** * An EMF specific plan compiler for the local search-based pattern matcher * * @author Marton Bur * @noreference This class is not intended to be referenced by clients. + * @deprecated Use the refactored {@link EMFOperationCompiler} instead */ -public class POperationCompiler { - - /** - * - */ - private static final String UNSUPPORTED_TYPE_MESSAGE = "Unsupported type: "; - private List<ISearchOperation> operations; - private Set<MatcherReference> dependencies = Sets.newHashSet(); - private Map<PConstraint, Set<Integer>> variableBindings; - private Map<PVariable, Integer> variableMappings; - private final boolean baseIndexAvailable; - private final EMFQueryRuntimeContext runtimeContext; - - private class FrameMapping{ - final Map<PParameter, Integer> mapping = Maps.newHashMap(); - final Set<PParameter> adornment = Sets.newHashSet(); - - public FrameMapping(PatternCallBasedDeferred constraint, Map<PVariable, Integer> variableMapping) { - final Set<Integer> bindings = variableBindings.get(constraint); - int keySize = constraint.getActualParametersTuple().getSize(); - for (int i = 0; i < keySize; i++) { - PParameter symbolicParameter = constraint.getReferredQuery().getParameters().get(i); - PVariable parameter = (PVariable) constraint.getActualParametersTuple().get(i); - mapping.put(symbolicParameter, variableMapping.get(parameter)); - if (bindings.contains(variableMapping.get(parameter))) { - adornment.add(symbolicParameter); - } - } - } - - public FrameMapping(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping){ - final Set<Integer> bindings = variableBindings.get(pCall); - int keySize = pCall.getVariablesTuple().getSize(); - for (int i = 0; i < keySize; i++) { - PParameter symbolicParameter = pCall.getReferredQuery().getParameters().get(i); - PVariable parameter = (PVariable) pCall.getVariablesTuple().get(i); - mapping.put(symbolicParameter, variableMapping.get(parameter)); - if (bindings.contains(variableMapping.get(parameter))) { - adornment.add(symbolicParameter); - } - } - } - } +@Deprecated +public class POperationCompiler extends EMFOperationCompiler { public POperationCompiler(IQueryRuntimeContext runtimeContext) { - this(runtimeContext, false); + super(runtimeContext, false); } public POperationCompiler(IQueryRuntimeContext runtimeContext, boolean baseIndexAvailable) { - this.runtimeContext = (EMFQueryRuntimeContext) runtimeContext; - this.baseIndexAvailable = baseIndexAvailable; - } - - /** - * Compiles a plan of <code>POperation</code>s to a list of type <code>List<ISearchOperation></code> - * - * @param plan - * @param boundParameters - * @return an ordered list of POperations that make up the compiled search plan - * @throws QueryProcessingException - */ - public List<ISearchOperation> compile(SubPlan plan, Set<PParameter> boundParameters) throws QueryProcessingException { - - variableMappings = CompilerHelper.createVariableMapping(plan); - variableBindings = CompilerHelper.cacheVariableBindings(plan, variableMappings, boundParameters); - - operations = Lists.newArrayList(); - - List<POperation> operationList = CompilerHelper.createOperationsList(plan); - for (POperation pOperation : operationList) { - compile(pOperation, variableMappings); - } - - return operations; - } - - private void compile(POperation pOperation, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - - if (pOperation instanceof PApply) { - PApply pApply = (PApply) pOperation; - PConstraint pConstraint = pApply.getPConstraint(); - - if (isCheck(pConstraint, variableMapping)) { - // check - createCheckDispatcher(pConstraint, variableMapping); - } else { - // extend - createExtendDispatcher(pConstraint, variableMapping); - } - - } else if (pOperation instanceof PStart) { - // nop - } else if (pOperation instanceof PProject) { - // nop - } else { - throw new QueryProcessingException("PStart, PApply or PProject was expected, received: " + pOperation.getClass(), null,"Unexpected POperation type", null); - } - - } - - private boolean isCheck(PConstraint pConstraint, final Map<PVariable, Integer> variableMapping){ - if (pConstraint instanceof NegativePatternCall){ - return true; - }else if (pConstraint instanceof PositivePatternCall){ - // Positive pattern call is check if all non-single used variables are bound - return variableBindings.get(pConstraint).containsAll(Collections2.transform(Sets.filter(pConstraint.getAffectedVariables(), new Predicate<PVariable>() { - - @Override - public boolean apply(PVariable input) { - return input.getReferringConstraints().size() > 1; - } - }), new Function<PVariable, Integer>() { - - @Override - public Integer apply(PVariable input) { - return variableMapping.get(input); - } - - })); - }else if (pConstraint instanceof AggregatorConstraint){ - PVariable outputvar = ((AggregatorConstraint) pConstraint).getResultVariable(); - return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); - }else if (pConstraint instanceof PatternMatchCounter){ - PVariable outputvar = ((PatternMatchCounter) pConstraint).getResultVariable(); - return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); - }else if (pConstraint instanceof ExpressionEvaluation){ - PVariable outputvar = ((ExpressionEvaluation) pConstraint).getOutputVariable(); - return outputvar == null || variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); - } else { - // In other cases, all variables shall be bound to be a check - Set<PVariable> affectedVariables = pConstraint.getAffectedVariables(); - Set<Integer> varIndices = Sets.newHashSet(); - for (PVariable variable : affectedVariables) { - varIndices.add(variableMapping.get(variable)); - } - return variableBindings.get(pConstraint).containsAll(varIndices); - } - } - - private void createCheckDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - - - // DeferredPConstraint subclasses - - // Equalities are normalized - - if (pConstraint instanceof Inequality) { - createCheck((Inequality) pConstraint, variableMapping); - } else if (pConstraint instanceof PositivePatternCall){ - createCheck((PositivePatternCall) pConstraint, variableMapping); - } else if (pConstraint instanceof NegativePatternCall) { - createCheck((NegativePatternCall) pConstraint,variableMapping); - } else if (pConstraint instanceof AggregatorConstraint) { - createCheck((AggregatorConstraint) pConstraint, variableMapping); - } else if (pConstraint instanceof PatternMatchCounter) { - createCheck((PatternMatchCounter) pConstraint, variableMapping); - } else if (pConstraint instanceof ExpressionEvaluation) { - createCheck((ExpressionEvaluation) pConstraint, variableMapping); - } else if (pConstraint instanceof TypeFilterConstraint) { - createCheck((TypeFilterConstraint) pConstraint,variableMapping); - } else if (pConstraint instanceof ExportedParameter) { - // Nothing to do here - } else - - // EnumerablePConstraint subclasses - - if (pConstraint instanceof BinaryTransitiveClosure) { - createCheck((BinaryTransitiveClosure) pConstraint, variableMapping); - } else if (pConstraint instanceof ConstantValue) { - createCheck((ConstantValue) pConstraint, variableMapping); - } else if (pConstraint instanceof TypeConstraint) { - createCheck((TypeConstraint) pConstraint,variableMapping); - } else { - String msg = "Unsupported Check constraint: "+pConstraint.toString(); - throw new QueryProcessingException(msg, null, msg, null); - } - - } - - /** - * @param pConstraint - * @param variableMapping - */ - private void createCheck(PatternMatchCounter counter, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(counter, variableMapping); - - PQuery referredQuery = counter.getReferredQuery(); - MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); - operations.add(new CountCheck(matcherReference, mapping.mapping, variableMapping.get(counter.getResultVariable()))); - dependencies.add(matcherReference); - } - - private void createCheck(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(pCall, variableMapping); - MatcherReference matcherReference = new MatcherReference(pCall.getReferredQuery(), mapping.adornment); - operations.add(new CheckPositivePatternCall(matcherReference, mapping.mapping)); - dependencies.add(matcherReference); - } - - private void createCheck(ConstantValue constant, Map<PVariable, Integer> variableMapping) { - int position = variableMapping.get(constant.getVariablesTuple().get(0)); - operations.add(new CheckConstant(position, constant.getSupplierKey())); - } - - private void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - final IInputKey inputKey = typeConstraint.getInputKey(); - if (inputKey instanceof JavaTransitiveInstancesKey) { - operations.add(new InstanceOfJavaClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((JavaTransitiveInstancesKey) inputKey).getInstanceClass())); - } else if (inputKey instanceof EDataTypeInSlotsKey) { // TODO probably only occurs as TypeConstraint - operations.add(new InstanceOfDataTypeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), - ((EDataTypeInSlotsKey) inputKey).getEmfKey())); - } else if (inputKey instanceof EClassUnscopedTransitiveInstancesKey) { - operations.add(new InstanceOfClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((EClassUnscopedTransitiveInstancesKey) inputKey).getEmfKey())); - } else { - String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey; - throw new QueryProcessingException(msg, null, msg, null); - } - } - - private void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - final IInputKey inputKey = typeConstraint.getSupplierKey(); - if (inputKey instanceof EClassTransitiveInstancesKey) { - operations.add(new InstanceOfClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((EClassTransitiveInstancesKey) inputKey).getEmfKey())); - operations.add(new ScopeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), runtimeContext.getEmfScope())); - } else if (inputKey instanceof EStructuralFeatureInstancesKey) { - int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0)); - int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1)); - operations.add(new StructuralFeatureCheck(sourcePosition, targetPosition, - ((EStructuralFeatureInstancesKey) inputKey).getEmfKey())); - } else if (inputKey instanceof EDataTypeInSlotsKey) { - operations.add(new InstanceOfDataTypeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), - ((EDataTypeInSlotsKey) inputKey).getEmfKey())); - } else { - String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey; - throw new QueryProcessingException(msg, null, msg, null); - } - } - - private void createCheck(BinaryTransitiveClosure binaryTransitiveColsure, Map<PVariable, Integer> variableMapping) { - int sourcePosition = variableMapping.get(binaryTransitiveColsure.getVariablesTuple().get(0)); - int targetPosition = variableMapping.get(binaryTransitiveColsure.getVariablesTuple().get(1)); - - PQuery referredQuery = binaryTransitiveColsure.getReferredQuery(); - - operations.add(new BinaryTransitiveClosureCheck(new MatcherReference(referredQuery, ImmutableSet.of(referredQuery.getParameters().get(0), referredQuery.getParameters().get(1))), sourcePosition, targetPosition)); - //The second parameter is NOT bound during execution! - Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(0)); - dependencies.add(new MatcherReference(referredQuery, adornment)); - } - - - private void createCheck(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) { - // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway - Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames(); - Map<String, Integer> nameMap = Maps.newHashMap(); - - for (String pVariableName : inputParameterNames) { - PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName); - nameMap.put(pVariableName, variableMapping.get(pVariable)); - } - - // output variable can be null; if null it is an ExpressionCheck - if(expressionEvaluation.getOutputVariable() == null){ - operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap)); - } else { - operations.add(new ExpressionEvalCheck(expressionEvaluation.getEvaluator(), nameMap, variableMapping.get(expressionEvaluation.getOutputVariable()))); - } - } - - private void createCheck(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(aggregator, variableMapping); - - PQuery referredQuery = aggregator.getReferredQuery(); - MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); - operations.add(new AggregatorCheck(matcherReference, aggregator, mapping.mapping, variableMapping.get(aggregator.getResultVariable()))); - dependencies.add(matcherReference); - } - - private void createCheck(NegativePatternCall negativePatternCall, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(negativePatternCall, variableMapping); - PQuery referredQuery = negativePatternCall.getReferredQuery(); - MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); - operations.add(new NACOperation(matcherReference, mapping.mapping)); - dependencies.add(matcherReference); - } - - private void createCheck(Inequality inequality, Map<PVariable, Integer> variableMapping) { - operations.add(new InequalityCheck(variableMapping.get(inequality.getWho()), variableMapping.get(inequality.getWithWhom()))); - } - - - private void createExtendDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - - // DeferredPConstraint subclasses - - // Equalities are normalized - if (pConstraint instanceof PositivePatternCall) { - createExtend((PositivePatternCall)pConstraint, variableMapping); - } else if (pConstraint instanceof AggregatorConstraint) { - createExtend((AggregatorConstraint) pConstraint, variableMapping); - } else if (pConstraint instanceof PatternMatchCounter) { - createExtend((PatternMatchCounter) pConstraint, variableMapping); - } else if (pConstraint instanceof ExpressionEvaluation) { - createExtend((ExpressionEvaluation) pConstraint, variableMapping); - } else if (pConstraint instanceof ExportedParameter) { - // ExportedParameters are compiled to NOP - } else - - // EnumerablePConstraint subclasses - - if (pConstraint instanceof ConstantValue) { - createExtend((ConstantValue) pConstraint, variableMapping); - } else if (pConstraint instanceof TypeConstraint) { - createExtend((TypeConstraint) pConstraint, variableMapping); - } else if (pConstraint instanceof BinaryTransitiveClosure) { - createExtend((BinaryTransitiveClosure)pConstraint, variableMapping); - } else { - String msg = "Unsupported Extend constraint: "+pConstraint.toString(); - throw new QueryProcessingException(msg, null, msg, null); - } - } - - private void createExtend(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(pCall, variableMapping); - MatcherReference matcherReference = new MatcherReference(pCall.getReferredQuery(), mapping.adornment); - operations.add(new ExtendPositivePatternCall(matcherReference, mapping.mapping)); - dependencies.add(matcherReference); - } - - private void createExtend(BinaryTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { - int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0)); - int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1)); - - PQuery referredQuery = binaryTransitiveClosure.getReferredQuery(); - - boolean sourceBound = variableBindings.get(binaryTransitiveClosure).contains(sourcePosition); - boolean targetBound = variableBindings.get(binaryTransitiveClosure).contains(targetPosition); - - if (sourceBound && !targetBound) { - Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(0)); - operations.add(new ExtendBinaryTransitiveClosure.Forward(new MatcherReference(referredQuery, adornment), sourcePosition, targetPosition)); - dependencies.add(new MatcherReference(referredQuery, adornment)); - } else if (!sourceBound && targetBound) { - Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(1)); - operations.add(new ExtendBinaryTransitiveClosure.Backward(new MatcherReference(referredQuery, adornment), sourcePosition, targetPosition)); - dependencies.add(new MatcherReference(referredQuery, adornment)); - } else { - String msg = "Binary transitive closure not supported with two unbound parameters"; - throw new QueryProcessingException(msg, null, msg, binaryTransitiveClosure.getPSystem().getPattern()); - } - } - - private void createExtend(ConstantValue constant, Map<PVariable, Integer> variableMapping) { - int position = variableMapping.get(constant.getVariablesTuple().get(0)); - operations.add(new ExtendConstant(position, constant.getSupplierKey())); - } - - private void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) { - final IInputKey inputKey = typeConstraint.getSupplierKey(); - if (inputKey instanceof EDataTypeInSlotsKey) { - if(baseIndexAvailable){ - operations.add(new IterateOverEDatatypeInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)), ((EDataTypeInSlotsKey) inputKey).getEmfKey())); - } else { - int position = variableMapping.get(typeConstraint.getVariableInTuple(0)); - operations - .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEDatatypeInstances(position, - ((EDataTypeInSlotsKey) inputKey).getEmfKey(), runtimeContext.getEmfScope())); - operations.add(new ScopeCheck(position, runtimeContext.getEmfScope())); - } - } else if (inputKey instanceof EClassTransitiveInstancesKey) { - if(baseIndexAvailable){ - operations.add(new IterateOverEClassInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)), - ((EClassTransitiveInstancesKey) inputKey).getEmfKey())); - } else { - int position = variableMapping.get(typeConstraint.getVariableInTuple(0)); - operations - .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances( - position, - ((EClassTransitiveInstancesKey) inputKey).getEmfKey(), runtimeContext.getEmfScope())); - operations.add(new ScopeCheck(position, runtimeContext.getEmfScope())); - } - } else if (inputKey instanceof EStructuralFeatureInstancesKey) { - final EStructuralFeature feature = ((EStructuralFeatureInstancesKey) inputKey).getEmfKey(); - - int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0)); - int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1)); - - boolean fromBound = variableBindings.get(typeConstraint).contains(sourcePosition); - boolean toBound = variableBindings.get(typeConstraint).contains(targetPosition); - - if (fromBound && !toBound) { - if (baseIndexAvailable) { - operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature)); - } else { - operations - .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureTarget( - sourcePosition, targetPosition, feature)); - operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope())); - } - } - else if(!fromBound && toBound){ - if (feature instanceof EReference && ((EReference)feature).isContainment()) { - // The iterate is also used to traverse a single container (third parameter) - operations.add(new IterateOverContainers(sourcePosition, targetPosition, false)); - operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); - } else if(baseIndexAvailable){ - operations.add(new ExtendToEStructuralFeatureSource(sourcePosition, targetPosition, feature)); - } else { - operations.add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureSource( - sourcePosition, targetPosition, feature)); - operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); - } - } else { - // TODO Elaborate solution based on the navigability of edges - // As of now a static solution is implemented - if (baseIndexAvailable) { - operations.add(new IterateOverEClassInstances(sourcePosition, feature.getEContainingClass())); - operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature)); - } else { - operations - .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances( - sourcePosition, feature.getEContainingClass(), runtimeContext.getEmfScope())); - operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); - operations - .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureTarget( - sourcePosition, targetPosition, feature)); - operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope())); - } - } - - } else { - throw new IllegalArgumentException(UNSUPPORTED_TYPE_MESSAGE + inputKey); - } - } - - private void createExtend(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) { - // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway - Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames(); - Map<String, Integer> nameMap = Maps.newHashMap(); - - for (String pVariableName : inputParameterNames) { - PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName); - nameMap.put(pVariableName, variableMapping.get(pVariable)); - } - - // output variable can be null; if null it is an ExpressionCheck - if(expressionEvaluation.getOutputVariable() == null){ - operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap)); - } else { - operations.add(new ExpressionEval(expressionEvaluation.getEvaluator(), nameMap, variableMapping.get(expressionEvaluation.getOutputVariable()))); - } - } - - private void createExtend(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(aggregator, variableMapping); - - PQuery referredQuery = aggregator.getReferredQuery(); - MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); - operations.add(new AggregatorExtend(matcherReference, aggregator, mapping.mapping, variableMapping.get(aggregator.getResultVariable()))); - dependencies.add(matcherReference); - } - - private void createExtend(PatternMatchCounter patternMatchCounter, Map<PVariable, Integer> variableMapping) { - FrameMapping mapping = new FrameMapping(patternMatchCounter, variableMapping); - - PQuery referredQuery = patternMatchCounter.getReferredQuery(); - MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); - operations.add(new CountOperation(matcherReference, mapping.mapping, variableMapping.get(patternMatchCounter.getResultVariable()))); - dependencies.add(matcherReference); - } - - public Set<MatcherReference> getDependencies() { - return dependencies; - } - /** - * @return the cached variable bindings for the previously created plan - */ - public Map<PVariable, Integer> getVariableMappings() { - return variableMappings; + super(runtimeContext, baseIndexAvailable); } } diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java new file mode 100644 index 000000000..468c3f879 --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java @@ -0,0 +1,438 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.planner.compiler; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.viatra.query.runtime.emf.EMFQueryRuntimeContext; +import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; +import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.AggregatorCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.BinaryTransitiveClosureCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.CheckConstant; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.CheckPositivePatternCall; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.CountCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.ExpressionCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.ExpressionEvalCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.InequalityCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.NACOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.AggregatorExtend; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.CountOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExpressionEval; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendBinaryTransitiveClosure; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendConstant; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendPositivePatternCall; +import org.eclipse.viatra.query.runtime.localsearch.planner.util.CompilerHelper; +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.planning.operations.PApply; +import org.eclipse.viatra.query.runtime.matchers.planning.operations.POperation; +import org.eclipse.viatra.query.runtime.matchers.planning.operations.PProject; +import org.eclipse.viatra.query.runtime.matchers.planning.operations.PStart; +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.basicdeferred.AggregatorConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.PatternCallBasedDeferred; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.PatternMatchCounter; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.ConstantValue; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public abstract class AbstractOperationCompiler implements IOperationCompiler { + + public class FrameMapping{ + public final Map<PParameter, Integer> mapping = Maps.newHashMap(); + public final Set<PParameter> adornment = Sets.newHashSet(); + + public FrameMapping(PatternCallBasedDeferred constraint, Map<PVariable, Integer> variableMapping) { + final Set<Integer> bindings = variableBindings.get(constraint); + int keySize = constraint.getActualParametersTuple().getSize(); + for (int i = 0; i < keySize; i++) { + PParameter symbolicParameter = constraint.getReferredQuery().getParameters().get(i); + PVariable parameter = (PVariable) constraint.getActualParametersTuple().get(i); + mapping.put(symbolicParameter, variableMapping.get(parameter)); + if (bindings.contains(variableMapping.get(parameter))) { + adornment.add(symbolicParameter); + } + } + } + + public FrameMapping(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping){ + final Set<Integer> bindings = variableBindings.get(pCall); + int keySize = pCall.getVariablesTuple().getSize(); + for (int i = 0; i < keySize; i++) { + PParameter symbolicParameter = pCall.getReferredQuery().getParameters().get(i); + PVariable parameter = (PVariable) pCall.getVariablesTuple().get(i); + mapping.put(symbolicParameter, variableMapping.get(parameter)); + if (bindings.contains(variableMapping.get(parameter))) { + adornment.add(symbolicParameter); + } + } + } + } + + protected static final String UNSUPPORTED_TYPE_MESSAGE = "Unsupported type: "; + + protected abstract void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping); + + protected abstract void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException; + + protected abstract void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException; + + protected List<ISearchOperation> operations; + protected Set<MatcherReference> dependencies = Sets.newHashSet(); + protected Map<PConstraint, Set<Integer>> variableBindings; + private Map<PVariable, Integer> variableMappings; + protected final EMFQueryRuntimeContext runtimeContext; + + public AbstractOperationCompiler(IQueryRuntimeContext runtimeContext) { + this.runtimeContext = (EMFQueryRuntimeContext) runtimeContext; + } + + /** + * Compiles a plan of <code>POperation</code>s to a list of type <code>List<ISearchOperation></code> + * + * @param plan + * @param boundParameters + * @return an ordered list of POperations that make up the compiled search plan + * @throws QueryProcessingException + */ + @Override + public List<ISearchOperation> compile(SubPlan plan, Set<PParameter> boundParameters) throws QueryProcessingException { + + variableMappings = CompilerHelper.createVariableMapping(plan); + variableBindings = CompilerHelper.cacheVariableBindings(plan, variableMappings, boundParameters); + + operations = Lists.newArrayList(); + + List<POperation> operationList = CompilerHelper.createOperationsList(plan); + for (POperation pOperation : operationList) { + compile(pOperation, variableMappings); + } + + return operations; + } + + private void compile(POperation pOperation, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + + if (pOperation instanceof PApply) { + PApply pApply = (PApply) pOperation; + PConstraint pConstraint = pApply.getPConstraint(); + + if (isCheck(pConstraint, variableMapping)) { + // check + createCheckDispatcher(pConstraint, variableMapping); + } else { + // extend + createExtendDispatcher(pConstraint, variableMapping); + } + + } else if (pOperation instanceof PStart) { + // nop + } else if (pOperation instanceof PProject) { + // nop + } else { + throw new QueryProcessingException("PStart, PApply or PProject was expected, received: " + pOperation.getClass(), null,"Unexpected POperation type", null); + } + + } + + private void createCheckDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + + + // DeferredPConstraint subclasses + + // Equalities are normalized + + if (pConstraint instanceof Inequality) { + createCheck((Inequality) pConstraint, variableMapping); + } else if (pConstraint instanceof PositivePatternCall){ + createCheck((PositivePatternCall) pConstraint, variableMapping); + } else if (pConstraint instanceof NegativePatternCall) { + createCheck((NegativePatternCall) pConstraint,variableMapping); + } else if (pConstraint instanceof AggregatorConstraint) { + createCheck((AggregatorConstraint) pConstraint, variableMapping); + } else if (pConstraint instanceof PatternMatchCounter) { + createCheck((PatternMatchCounter) pConstraint, variableMapping); + } else if (pConstraint instanceof ExpressionEvaluation) { + createCheck((ExpressionEvaluation) pConstraint, variableMapping); + } else if (pConstraint instanceof TypeFilterConstraint) { + createCheck((TypeFilterConstraint) pConstraint,variableMapping); + } else if (pConstraint instanceof ExportedParameter) { + // Nothing to do here + } else + + // EnumerablePConstraint subclasses + + if (pConstraint instanceof BinaryTransitiveClosure) { + createCheck((BinaryTransitiveClosure) pConstraint, variableMapping); + } else if (pConstraint instanceof ConstantValue) { + createCheck((ConstantValue) pConstraint, variableMapping); + } else if (pConstraint instanceof TypeConstraint) { + createCheck((TypeConstraint) pConstraint,variableMapping); + } else { + String msg = "Unsupported Check constraint: "+pConstraint.toString(); + throw new QueryProcessingException(msg, null, msg, null); + } + + } + + protected void createExtendDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + + // DeferredPConstraint subclasses + + // Equalities are normalized + if (pConstraint instanceof PositivePatternCall) { + createExtend((PositivePatternCall)pConstraint, variableMapping); + } else if (pConstraint instanceof AggregatorConstraint) { + createExtend((AggregatorConstraint) pConstraint, variableMapping); + } else if (pConstraint instanceof PatternMatchCounter) { + createExtend((PatternMatchCounter) pConstraint, variableMapping); + } else if (pConstraint instanceof ExpressionEvaluation) { + createExtend((ExpressionEvaluation) pConstraint, variableMapping); + } else if (pConstraint instanceof ExportedParameter) { + // ExportedParameters are compiled to NOP + } else + + // EnumerablePConstraint subclasses + + if (pConstraint instanceof ConstantValue) { + createExtend((ConstantValue) pConstraint, variableMapping); + } else if (pConstraint instanceof TypeConstraint) { + createExtend((TypeConstraint) pConstraint, variableMapping); + } else if (pConstraint instanceof BinaryTransitiveClosure) { + createExtend((BinaryTransitiveClosure)pConstraint, variableMapping); + } else { + String msg = "Unsupported Extend constraint: "+pConstraint.toString(); + throw new QueryProcessingException(msg, null, msg, null); + } + } + + private boolean isCheck(PConstraint pConstraint, final Map<PVariable, Integer> variableMapping) { + if (pConstraint instanceof NegativePatternCall){ + return true; + }else if (pConstraint instanceof PositivePatternCall){ + // Positive pattern call is check if all non-single used variables are bound + return variableBindings.get(pConstraint).containsAll(Collections2.transform(Sets.filter(pConstraint.getAffectedVariables(), new Predicate<PVariable>() { + + @Override + public boolean apply(PVariable input) { + return input.getReferringConstraints().size() > 1; + } + }), new Function<PVariable, Integer>() { + + @Override + public Integer apply(PVariable input) { + return variableMapping.get(input); + } + + })); + }else if (pConstraint instanceof AggregatorConstraint){ + PVariable outputvar = ((AggregatorConstraint) pConstraint).getResultVariable(); + return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); + }else if (pConstraint instanceof PatternMatchCounter){ + PVariable outputvar = ((PatternMatchCounter) pConstraint).getResultVariable(); + return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); + }else if (pConstraint instanceof ExpressionEvaluation){ + PVariable outputvar = ((ExpressionEvaluation) pConstraint).getOutputVariable(); + return outputvar == null || variableBindings.get(pConstraint).contains(variableMapping.get(outputvar)); + } else { + // In other cases, all variables shall be bound to be a check + Set<PVariable> affectedVariables = pConstraint.getAffectedVariables(); + Set<Integer> varIndices = Sets.newHashSet(); + for (PVariable variable : affectedVariables) { + varIndices.add(variableMapping.get(variable)); + } + return variableBindings.get(pConstraint).containsAll(varIndices); + } + } + + @Override + public Set<MatcherReference> getDependencies() { + return dependencies; + } + + /** + * @return the cached variable bindings for the previously created plan + */ + @Override + public Map<PVariable, Integer> getVariableMappings() { + return variableMappings; + } + + protected void createCheck(PatternMatchCounter counter, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(counter, variableMapping); + + PQuery referredQuery = counter.getReferredQuery(); + MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); + operations.add(new CountCheck(matcherReference, mapping.mapping, variableMapping.get(counter.getResultVariable()))); + dependencies.add(matcherReference); + } + + protected void createCheck(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(pCall, variableMapping); + MatcherReference matcherReference = new MatcherReference(pCall.getReferredQuery(), mapping.adornment); + operations.add(new CheckPositivePatternCall(matcherReference, mapping.mapping)); + dependencies.add(matcherReference); + } + + protected void createCheck(ConstantValue constant, Map<PVariable, Integer> variableMapping) { + int position = variableMapping.get(constant.getVariablesTuple().get(0)); + operations.add(new CheckConstant(position, constant.getSupplierKey())); + } + + protected void createCheck(BinaryTransitiveClosure binaryTransitiveColsure, Map<PVariable, Integer> variableMapping) { + int sourcePosition = variableMapping.get(binaryTransitiveColsure.getVariablesTuple().get(0)); + int targetPosition = variableMapping.get(binaryTransitiveColsure.getVariablesTuple().get(1)); + + PQuery referredQuery = binaryTransitiveColsure.getReferredQuery(); + + operations.add(new BinaryTransitiveClosureCheck(new MatcherReference(referredQuery, ImmutableSet.of(referredQuery.getParameters().get(0), referredQuery.getParameters().get(1))), sourcePosition, targetPosition)); + //The second parameter is NOT bound during execution! + Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(0)); + dependencies.add(new MatcherReference(referredQuery, adornment)); + } + + protected void createCheck(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) { + // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway + Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames(); + Map<String, Integer> nameMap = Maps.newHashMap(); + + for (String pVariableName : inputParameterNames) { + PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName); + nameMap.put(pVariableName, variableMapping.get(pVariable)); + } + + // output variable can be null; if null it is an ExpressionCheck + if(expressionEvaluation.getOutputVariable() == null){ + operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap)); + } else { + operations.add(new ExpressionEvalCheck(expressionEvaluation.getEvaluator(), nameMap, variableMapping.get(expressionEvaluation.getOutputVariable()))); + } + } + + protected void createCheck(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(aggregator, variableMapping); + + PQuery referredQuery = aggregator.getReferredQuery(); + MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); + operations.add(new AggregatorCheck(matcherReference, aggregator, mapping.mapping, variableMapping.get(aggregator.getResultVariable()))); + dependencies.add(matcherReference); + } + + protected void createCheck(NegativePatternCall negativePatternCall, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(negativePatternCall, variableMapping); + PQuery referredQuery = negativePatternCall.getReferredQuery(); + MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); + operations.add(new NACOperation(matcherReference, mapping.mapping)); + dependencies.add(matcherReference); + } + + protected void createCheck(Inequality inequality, Map<PVariable, Integer> variableMapping) { + operations.add(new InequalityCheck(variableMapping.get(inequality.getWho()), variableMapping.get(inequality.getWithWhom()))); + } + + protected void createExtend(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(pCall, variableMapping); + MatcherReference matcherReference = new MatcherReference(pCall.getReferredQuery(), mapping.adornment); + operations.add(new ExtendPositivePatternCall(matcherReference, mapping.mapping)); + dependencies.add(matcherReference); + } + + protected void createExtend(BinaryTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0)); + int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1)); + + PQuery referredQuery = binaryTransitiveClosure.getReferredQuery(); + + boolean sourceBound = variableBindings.get(binaryTransitiveClosure).contains(sourcePosition); + boolean targetBound = variableBindings.get(binaryTransitiveClosure).contains(targetPosition); + + if (sourceBound && !targetBound) { + Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(0)); + operations.add(new ExtendBinaryTransitiveClosure.Forward(new MatcherReference(referredQuery, adornment), sourcePosition, targetPosition)); + dependencies.add(new MatcherReference(referredQuery, adornment)); + } else if (!sourceBound && targetBound) { + Set<PParameter> adornment = ImmutableSet.of(referredQuery.getParameters().get(1)); + operations.add(new ExtendBinaryTransitiveClosure.Backward(new MatcherReference(referredQuery, adornment), sourcePosition, targetPosition)); + dependencies.add(new MatcherReference(referredQuery, adornment)); + } else { + String msg = "Binary transitive closure not supported with two unbound parameters"; + throw new QueryProcessingException(msg, null, msg, binaryTransitiveClosure.getPSystem().getPattern()); + } + } + + protected void createExtend(ConstantValue constant, Map<PVariable, Integer> variableMapping) { + int position = variableMapping.get(constant.getVariablesTuple().get(0)); + operations.add(new ExtendConstant(position, constant.getSupplierKey())); + } + + protected void createExtend(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) { + // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway + Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames(); + Map<String, Integer> nameMap = Maps.newHashMap(); + + for (String pVariableName : inputParameterNames) { + PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName); + nameMap.put(pVariableName, variableMapping.get(pVariable)); + } + + // output variable can be null; if null it is an ExpressionCheck + if(expressionEvaluation.getOutputVariable() == null){ + operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap)); + } else { + operations.add(new ExpressionEval(expressionEvaluation.getEvaluator(), nameMap, variableMapping.get(expressionEvaluation.getOutputVariable()))); + } + } + + protected void createExtend(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(aggregator, variableMapping); + + PQuery referredQuery = aggregator.getReferredQuery(); + MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); + operations.add(new AggregatorExtend(matcherReference, aggregator, mapping.mapping, variableMapping.get(aggregator.getResultVariable()))); + dependencies.add(matcherReference); + } + + protected void createExtend(PatternMatchCounter patternMatchCounter, Map<PVariable, Integer> variableMapping) { + FrameMapping mapping = new FrameMapping(patternMatchCounter, variableMapping); + + PQuery referredQuery = patternMatchCounter.getReferredQuery(); + MatcherReference matcherReference = new MatcherReference(referredQuery, mapping.adornment); + operations.add(new CountOperation(matcherReference, mapping.mapping, variableMapping.get(patternMatchCounter.getResultVariable()))); + dependencies.add(matcherReference); + } + +}
\ No newline at end of file diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/EMFOperationCompiler.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/EMFOperationCompiler.java new file mode 100644 index 000000000..4d7789dc6 --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/EMFOperationCompiler.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.planner.compiler; + +import java.util.Map; + +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.viatra.query.runtime.emf.types.EClassTransitiveInstancesKey; +import org.eclipse.viatra.query.runtime.emf.types.EClassUnscopedTransitiveInstancesKey; +import org.eclipse.viatra.query.runtime.emf.types.EDataTypeInSlotsKey; +import org.eclipse.viatra.query.runtime.emf.types.EStructuralFeatureInstancesKey; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfClassCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfDataTypeCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.InstanceOfJavaClassCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.StructuralFeatureCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.check.nobase.ScopeCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureSource; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureTarget; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverContainers; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverEClassInstances; +import org.eclipse.viatra.query.runtime.localsearch.operations.extend.IterateOverEDatatypeInstances; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; +import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; +import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException; +import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; + +/** + * Operation compiler implementation that uses EMF-specific operations. + * + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public class EMFOperationCompiler extends AbstractOperationCompiler { + + private boolean baseIndexAvailable; + + public EMFOperationCompiler(IQueryRuntimeContext runtimeContext) { + this(runtimeContext, false); + } + + public EMFOperationCompiler(IQueryRuntimeContext runtimeContext, boolean baseIndexAvailable) { + super(runtimeContext); + this.baseIndexAvailable = baseIndexAvailable; + } + + @Override + protected void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + final IInputKey inputKey = typeConstraint.getInputKey(); + if (inputKey instanceof JavaTransitiveInstancesKey) { + operations.add(new InstanceOfJavaClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((JavaTransitiveInstancesKey) inputKey).getInstanceClass())); + } else if (inputKey instanceof EDataTypeInSlotsKey) { // TODO probably only occurs as TypeConstraint + operations.add(new InstanceOfDataTypeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), + ((EDataTypeInSlotsKey) inputKey).getEmfKey())); + } else if (inputKey instanceof EClassUnscopedTransitiveInstancesKey) { + operations.add(new InstanceOfClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((EClassUnscopedTransitiveInstancesKey) inputKey).getEmfKey())); + } else { + String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey; + throw new QueryProcessingException(msg, null, msg, null); + } + } + + @Override + protected void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) throws QueryProcessingException { + final IInputKey inputKey = typeConstraint.getSupplierKey(); + if (inputKey instanceof EClassTransitiveInstancesKey) { + operations.add(new InstanceOfClassCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), ((EClassTransitiveInstancesKey) inputKey).getEmfKey())); + operations.add(new ScopeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), runtimeContext.getEmfScope())); + } else if (inputKey instanceof EStructuralFeatureInstancesKey) { + int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0)); + int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1)); + operations.add(new StructuralFeatureCheck(sourcePosition, targetPosition, + ((EStructuralFeatureInstancesKey) inputKey).getEmfKey())); + } else if (inputKey instanceof EDataTypeInSlotsKey) { + operations.add(new InstanceOfDataTypeCheck(variableMapping.get(typeConstraint.getVariablesTuple().get(0)), + ((EDataTypeInSlotsKey) inputKey).getEmfKey())); + } else { + String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey; + throw new QueryProcessingException(msg, null, msg, null); + } + } + + @Override + public void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) { + final IInputKey inputKey = typeConstraint.getSupplierKey(); + if (inputKey instanceof EDataTypeInSlotsKey) { + if(baseIndexAvailable){ + operations.add(new IterateOverEDatatypeInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)), ((EDataTypeInSlotsKey) inputKey).getEmfKey())); + } else { + int position = variableMapping.get(typeConstraint.getVariableInTuple(0)); + operations + .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEDatatypeInstances(position, + ((EDataTypeInSlotsKey) inputKey).getEmfKey(), runtimeContext.getEmfScope())); + operations.add(new ScopeCheck(position, runtimeContext.getEmfScope())); + } + } else if (inputKey instanceof EClassTransitiveInstancesKey) { + if(baseIndexAvailable){ + operations.add(new IterateOverEClassInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)), + ((EClassTransitiveInstancesKey) inputKey).getEmfKey())); + } else { + int position = variableMapping.get(typeConstraint.getVariableInTuple(0)); + operations + .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances( + position, + ((EClassTransitiveInstancesKey) inputKey).getEmfKey(), runtimeContext.getEmfScope())); + operations.add(new ScopeCheck(position, runtimeContext.getEmfScope())); + } + } else if (inputKey instanceof EStructuralFeatureInstancesKey) { + final EStructuralFeature feature = ((EStructuralFeatureInstancesKey) inputKey).getEmfKey(); + + int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0)); + int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1)); + + boolean fromBound = variableBindings.get(typeConstraint).contains(sourcePosition); + boolean toBound = variableBindings.get(typeConstraint).contains(targetPosition); + + if (fromBound && !toBound) { + if (baseIndexAvailable) { + operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature)); + } else { + operations + .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureTarget( + sourcePosition, targetPosition, feature)); + operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope())); + } + } + else if(!fromBound && toBound){ + if (feature instanceof EReference && ((EReference)feature).isContainment()) { + // The iterate is also used to traverse a single container (third parameter) + operations.add(new IterateOverContainers(sourcePosition, targetPosition, false)); + operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); + } else if(baseIndexAvailable){ + operations.add(new ExtendToEStructuralFeatureSource(sourcePosition, targetPosition, feature)); + } else { + operations.add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureSource( + sourcePosition, targetPosition, feature)); + operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); + } + } else { + // TODO Elaborate solution based on the navigability of edges + // As of now a static solution is implemented + if (baseIndexAvailable) { + operations.add(new IterateOverEClassInstances(sourcePosition, feature.getEContainingClass())); + operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature)); + } else { + operations + .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances( + sourcePosition, feature.getEContainingClass(), runtimeContext.getEmfScope())); + operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope())); + operations + .add(new org.eclipse.viatra.query.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureTarget( + sourcePosition, targetPosition, feature)); + operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope())); + } + } + + } else { + throw new IllegalArgumentException(UNSUPPORTED_TYPE_MESSAGE + inputKey); + } + } + +} diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/GenericOperationCompiler.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/GenericOperationCompiler.java new file mode 100644 index 000000000..8ba698d90 --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/GenericOperationCompiler.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.planner.compiler; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeCheck; +import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtend; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +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.psystem.PVariable; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public class GenericOperationCompiler extends AbstractOperationCompiler { + + public GenericOperationCompiler(IQueryRuntimeContext runtimeContext) { + super(runtimeContext); + } + + @Override + protected void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) + throws QueryProcessingException { + IInputKey inputKey = typeConstraint.getInputKey(); + Tuple tuple = typeConstraint.getVariablesTuple(); + Integer[] positions = new Integer[tuple.getSize()]; + for (int i = 0; i < tuple.getSize(); i++) { + PVariable variable = (PVariable) tuple.get(i); + positions[i] = variableMapping.get(variable); + } + operations.add(new GenericTypeCheck(inputKey, positions)); + + } + + @Override + protected void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) + throws QueryProcessingException { + IInputKey inputKey = typeConstraint.getSupplierKey(); + Tuple tuple = typeConstraint.getVariablesTuple(); + Integer[] positions = new Integer[tuple.getSize()]; + for (int i = 0; i < tuple.getSize(); i++) { + PVariable variable = (PVariable) tuple.get(i); + positions[i] = variableMapping.get(variable); + } + operations.add(new GenericTypeCheck(inputKey, positions)); + } + + @Override + protected void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) { + IInputKey inputKey = typeConstraint.getSupplierKey(); + Tuple tuple = typeConstraint.getVariablesTuple(); + + Integer[] positions = new Integer[tuple.getSize()]; + Set<Integer> boundVariables = new HashSet<>(); + for (int i = 0; i < tuple.getSize(); i++) { + PVariable variable = (PVariable) tuple.get(i); + Integer position = variableMapping.get(variable); + positions[i] = position; + if (variableBindings.get(typeConstraint).contains(position)) { + boundVariables.add(position); + } + } + operations.add(new GenericTypeExtend(inputKey, positions, boundVariables)); + + } + + + +} diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/IOperationCompiler.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/IOperationCompiler.java new file mode 100644 index 000000000..cc8974d7b --- /dev/null +++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/planner/compiler/IOperationCompiler.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * 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: + * Zoltan Ujhelyi - initial API and implementation + *******************************************************************************/ +package org.eclipse.viatra.query.runtime.localsearch.planner.compiler; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.viatra.query.runtime.localsearch.matcher.MatcherReference; +import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; +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.PVariable; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; + +/** + * An operation compiler is responsible for creating executable search plans from the subplan structure. + * + * @author Zoltan Ujhelyi + * @since 1.7 + * + */ +public interface IOperationCompiler { + + /** + * Compiles a plan of <code>POperation</code>s to a list of type <code>List<ISearchOperation></code> + * + * @param plan + * @param boundParameters + * @return an ordered list of POperations that make up the compiled search plan + * @throws QueryProcessingException + */ + List<ISearchOperation> compile(SubPlan plan, Set<PParameter> boundParameters) throws QueryProcessingException; + + Set<MatcherReference> getDependencies(); + + /** + * @return the cached variable bindings for the previously created plan + */ + Map<PVariable, Integer> getVariableMappings(); + +}
\ No newline at end of file |
