aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java390
1 files changed, 390 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java
new file mode 100644
index 00000000..da2fb432
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/plancompiler/CompilerHelper.java
@@ -0,0 +1,390 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.rete.construction.plancompiler;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.LinkedHashSet;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.Map;
19import java.util.Map.Entry;
20import java.util.Set;
21import java.util.SortedSet;
22import java.util.TreeSet;
23
24import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
25import tools.refinery.viatra.runtime.matchers.context.IInputKey;
26import tools.refinery.viatra.runtime.matchers.context.IPosetComparator;
27import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
28import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
29import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
30import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
31import tools.refinery.viatra.runtime.matchers.psystem.PBody;
32import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
33import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
34import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
35import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
36import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
37import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration;
38import tools.refinery.viatra.runtime.rete.recipes.EqualityFilterRecipe;
39import tools.refinery.viatra.runtime.rete.recipes.IndexerBasedAggregatorRecipe;
40import tools.refinery.viatra.runtime.rete.recipes.IndexerRecipe;
41import tools.refinery.viatra.runtime.rete.recipes.JoinRecipe;
42import tools.refinery.viatra.runtime.rete.recipes.Mask;
43import tools.refinery.viatra.runtime.rete.recipes.MonotonicityInfo;
44import tools.refinery.viatra.runtime.rete.recipes.ProductionRecipe;
45import tools.refinery.viatra.runtime.rete.recipes.ProjectionIndexerRecipe;
46import tools.refinery.viatra.runtime.rete.recipes.RecipesFactory;
47import tools.refinery.viatra.runtime.rete.recipes.ReteNodeRecipe;
48import tools.refinery.viatra.runtime.rete.recipes.SingleColumnAggregatorRecipe;
49import tools.refinery.viatra.runtime.rete.recipes.TrimmerRecipe;
50import tools.refinery.viatra.runtime.rete.recipes.helper.RecipesHelper;
51import tools.refinery.viatra.runtime.rete.traceability.CompiledQuery;
52import tools.refinery.viatra.runtime.rete.traceability.CompiledSubPlan;
53import tools.refinery.viatra.runtime.rete.traceability.PlanningTrace;
54import tools.refinery.viatra.runtime.rete.traceability.RecipeTraceInfo;
55import tools.refinery.viatra.runtime.rete.util.ReteHintOptions;
56
57/**
58 * @author Bergmann Gabor
59 *
60 */
61public class CompilerHelper {
62
63 private CompilerHelper() {/*Utility class constructor*/}
64
65 static final RecipesFactory FACTORY = RecipesFactory.eINSTANCE;
66
67 /**
68 * Makes sure that all variables in the tuple are different so that it can be used as {@link CompiledSubPlan}. If a
69 * variable occurs multiple times, equality checks are applied and then the results are trimmed so that duplicates
70 * are hidden. If no manipulation is necessary, the original trace is returned.
71 *
72 * <p>
73 * to be used whenever a constraint introduces new variables.
74 */
75 public static PlanningTrace checkAndTrimEqualVariables(SubPlan plan, final PlanningTrace coreTrace) {
76 // are variables in the constraint all different?
77 final List<PVariable> coreVariablesTuple = coreTrace.getVariablesTuple();
78 final int constraintArity = coreVariablesTuple.size();
79 final int distinctVariables = coreTrace.getPosMapping().size();
80 if (constraintArity == distinctVariables) {
81 // all variables occur exactly once in tuple
82 return coreTrace;
83 } else { // apply equality checks and trim
84
85 // find the positions in the tuple for each variable
86 Map<PVariable, SortedSet<Integer>> posMultimap = new HashMap<PVariable, SortedSet<Integer>>();
87 List<PVariable> trimmedVariablesTuple = new ArrayList<PVariable>(distinctVariables);
88 int[] trimIndices = new int[distinctVariables];
89 for (int i = 0; i < constraintArity; ++i) {
90 final PVariable variable = coreVariablesTuple.get(i);
91 SortedSet<Integer> indexSet = posMultimap.get(variable);
92 if (indexSet == null) { // first occurrence of variable
93 indexSet = new TreeSet<Integer>();
94 posMultimap.put(variable, indexSet);
95
96 // this is the first occurrence, set up trimming
97 trimIndices[trimmedVariablesTuple.size()] = i;
98 trimmedVariablesTuple.add(variable);
99 }
100 indexSet.add(i);
101 }
102
103 // construct equality checks for each variable occurring multiple times
104 PlanningTrace lastTrace = coreTrace;
105 for (Entry<PVariable, SortedSet<Integer>> entry : posMultimap.entrySet()) {
106 if (entry.getValue().size() > 1) {
107 EqualityFilterRecipe equalityFilterRecipe = FACTORY.createEqualityFilterRecipe();
108 equalityFilterRecipe.setParent(lastTrace.getRecipe());
109 equalityFilterRecipe.getIndices().addAll(entry.getValue());
110 lastTrace = new PlanningTrace(plan, coreVariablesTuple, equalityFilterRecipe, lastTrace);
111 }
112 }
113
114 // trim so that each variable occurs only once
115 TrimmerRecipe trimmerRecipe = FACTORY.createTrimmerRecipe();
116 trimmerRecipe.setParent(lastTrace.getRecipe());
117 trimmerRecipe.setMask(tools.refinery.viatra.runtime.rete.recipes.helper.RecipesHelper
118 .mask(constraintArity, trimIndices));
119 return new PlanningTrace(plan, trimmedVariablesTuple, trimmerRecipe, lastTrace);
120 }
121 }
122
123 /**
124 * Extracts the variable list representation of the variables tuple.
125 */
126 public static List<PVariable> convertVariablesTuple(EnumerablePConstraint constraint) {
127 return convertVariablesTuple(constraint.getVariablesTuple());
128 }
129
130 /**
131 * Extracts the variable list representation of the variables tuple.
132 */
133 public static List<PVariable> convertVariablesTuple(Tuple variablesTuple) {
134 List<PVariable> result = new ArrayList<PVariable>();
135 for (Object o : variablesTuple.getElements())
136 result.add((PVariable) o);
137 return result;
138 }
139
140 /**
141 * Returns a compiled indexer trace according to a mask
142 */
143 public static RecipeTraceInfo makeIndexerTrace(SubPlan planToCompile, PlanningTrace parentTrace, TupleMask mask) {
144 final ReteNodeRecipe parentRecipe = parentTrace.getRecipe();
145 if (parentRecipe instanceof IndexerBasedAggregatorRecipe
146 || parentRecipe instanceof SingleColumnAggregatorRecipe)
147 throw new IllegalArgumentException(
148 "Cannot take projection indexer of aggregator node at plan " + planToCompile);
149 IndexerRecipe recipe = RecipesHelper.projectionIndexerRecipe(parentRecipe, toRecipeMask(mask));
150 // final List<PVariable> maskedVariables = mask.transform(parentTrace.getVariablesTuple());
151 return new PlanningTrace(planToCompile, /* maskedVariables */ parentTrace.getVariablesTuple(), recipe,
152 parentTrace);
153 // TODO add specialized indexer trace info?
154 }
155
156 /**
157 * Creates a trimmer that keeps selected variables only.
158 */
159 protected static TrimmerRecipe makeTrimmerRecipe(final PlanningTrace compiledParent,
160 List<PVariable> projectedVariables) {
161 final Mask projectionMask = makeProjectionMask(compiledParent, projectedVariables);
162 final TrimmerRecipe trimmerRecipe = ReteRecipeCompiler.FACTORY.createTrimmerRecipe();
163 trimmerRecipe.setParent(compiledParent.getRecipe());
164 trimmerRecipe.setMask(projectionMask);
165 return trimmerRecipe;
166 }
167
168 public static Mask makeProjectionMask(final PlanningTrace compiledParent, Iterable<PVariable> projectedVariables) {
169 List<Integer> projectionSourceIndices = new ArrayList<Integer>();
170 for (PVariable pVariable : projectedVariables) {
171 projectionSourceIndices.add(compiledParent.getPosMapping().get(pVariable));
172 }
173 final Mask projectionMask = RecipesHelper.mask(compiledParent.getRecipe().getArity(), projectionSourceIndices);
174 return projectionMask;
175 }
176
177 /**
178 * @since 1.6
179 */
180 public static final class PosetTriplet {
181 public Mask coreMask;
182 public Mask posetMask;
183 public IPosetComparator comparator;
184 }
185
186 /**
187 * @since 1.6
188 */
189 public static PosetTriplet computePosetInfo(List<PVariable> variables, PBody body, IQueryMetaContext context) {
190 Map<PVariable, Set<IInputKey>> typeMap = TypeHelper.inferUnaryTypesFor(variables, body.getConstraints(),
191 context);
192 List<Set<IInputKey>> keys = new LinkedList<Set<IInputKey>>();
193
194 for (int i = 0; i < variables.size(); i++) {
195 keys.add(typeMap.get(variables.get(i)));
196 }
197
198 return computePosetInfo(keys, context);
199 }
200
201 /**
202 * @since 1.6
203 */
204 public static PosetTriplet computePosetInfo(List<PParameter> parameters, IQueryMetaContext context) {
205 List<Set<IInputKey>> keys = new LinkedList<Set<IInputKey>>();
206 for (int i = 0; i < parameters.size(); i++) {
207 IInputKey key = parameters.get(i).getDeclaredUnaryType();
208 if (key == null) {
209 keys.add(Collections.emptySet());
210 } else {
211 keys.add(Collections.singleton(parameters.get(i).getDeclaredUnaryType()));
212 }
213 }
214 return computePosetInfo(keys, context);
215 }
216
217
218
219 /**
220 * @since 1.6
221 */
222 public static PosetTriplet computePosetInfo(Iterable<Set<IInputKey>> keys, IQueryMetaContext context) {
223 PosetTriplet result = new PosetTriplet();
224 List<Integer> coreIndices = new ArrayList<Integer>();
225 List<Integer> posetIndices = new ArrayList<Integer>();
226 List<IInputKey> filtered = new ArrayList<IInputKey>();
227 boolean posetKey = false;
228 int index = -1;
229
230 for (Set<IInputKey> _keys : keys) {
231 ++index;
232 posetKey = false;
233
234 for (IInputKey key : _keys) {
235 if (key != null && context.isPosetKey(key)) {
236 posetKey = true;
237 filtered.add(key);
238 break;
239 }
240 }
241
242 if (posetKey) {
243 posetIndices.add(index);
244 } else {
245 coreIndices.add(index);
246 }
247 }
248
249 result.comparator = context.getPosetComparator(filtered);
250 result.coreMask = RecipesHelper.mask(index + 1, coreIndices);
251 result.posetMask = RecipesHelper.mask(index + 1, posetIndices);
252
253 return result;
254 }
255
256 /**
257 * Creates a recipe for a production node and the corresponding trace.
258 * <p> PRE: in case this is a recursion cutoff point (see {@link RecursionCutoffPoint})
259 * and bodyFinalTraces will be filled later,
260 * the object yielded now by bodyFinalTraces.values() must return up-to-date results later
261 * @since 2.4
262 */
263 public static CompiledQuery makeQueryTrace(PQuery query, Map<PBody, RecipeTraceInfo> bodyFinalTraces,
264 Collection<ReteNodeRecipe> bodyFinalRecipes, QueryEvaluationHint hint, IQueryMetaContext context,
265 boolean deleteAndRederiveEvaluation, TimelyConfiguration timelyEvaluation) {
266 ProductionRecipe recipe = ReteRecipeCompiler.FACTORY.createProductionRecipe();
267
268 // temporary solution to support the deprecated option for now
269 boolean deleteAndRederiveEvaluationDep = deleteAndRederiveEvaluation || ReteHintOptions.deleteRederiveEvaluation.getValueOrDefault(hint);
270
271 recipe.setDeleteRederiveEvaluation(deleteAndRederiveEvaluationDep);
272
273 if (deleteAndRederiveEvaluationDep || (timelyEvaluation != null)) {
274 PosetTriplet triplet = computePosetInfo(query.getParameters(), context);
275 if (triplet.comparator != null) {
276 MonotonicityInfo info = FACTORY.createMonotonicityInfo();
277 info.setCoreMask(triplet.coreMask);
278 info.setPosetMask(triplet.posetMask);
279 info.setPosetComparator(triplet.comparator);
280 recipe.setOptionalMonotonicityInfo(info);
281 }
282 }
283
284 recipe.setPattern(query);
285 recipe.setPatternFQN(query.getFullyQualifiedName());
286 recipe.setTraceInfo(recipe.getPatternFQN());
287 recipe.getParents().addAll(bodyFinalRecipes);
288 for (int i = 0; i < query.getParameterNames().size(); ++i) {
289 recipe.getMappedIndices().put(query.getParameterNames().get(i), i);
290 }
291
292 return new CompiledQuery(recipe, bodyFinalTraces, query);
293 }
294
295 /**
296 * Calculated index mappings for a join, based on the common variables of the two parent subplans.
297 *
298 * @author Gabor Bergmann
299 *
300 */
301 public static class JoinHelper {
302 private TupleMask primaryMask;
303 private TupleMask secondaryMask;
304 private TupleMask complementerMask;
305 private RecipeTraceInfo primaryIndexer;
306 private RecipeTraceInfo secondaryIndexer;
307 private JoinRecipe naturalJoinRecipe;
308 private List<PVariable> naturalJoinVariablesTuple;
309
310 /**
311 * @pre enforceVariableCoincidences() has been called on both sides.
312 */
313 public JoinHelper(SubPlan planToCompile, PlanningTrace primaryCompiled, PlanningTrace callTrace) {
314 super();
315
316 Set<PVariable> primaryVariables = new LinkedHashSet<PVariable>(primaryCompiled.getVariablesTuple());
317 Set<PVariable> secondaryVariables = new LinkedHashSet<PVariable>(callTrace.getVariablesTuple());
318 int oldNodes = 0;
319 Set<Integer> introducingSecondaryIndices = new TreeSet<Integer>();
320 for (PVariable var : secondaryVariables) {
321 if (primaryVariables.contains(var))
322 oldNodes++;
323 else
324 introducingSecondaryIndices.add(callTrace.getPosMapping().get(var));
325 }
326 List<Integer> primaryIndices = new ArrayList<Integer>(oldNodes);
327 List<Integer> secondaryIndices = new ArrayList<Integer>(oldNodes);
328 for (PVariable var : secondaryVariables) {
329 if (primaryVariables.contains(var)) {
330 primaryIndices.add(primaryCompiled.getPosMapping().get(var));
331 secondaryIndices.add(callTrace.getPosMapping().get(var));
332 }
333 }
334 Collection<Integer> complementerIndices = introducingSecondaryIndices;
335
336 primaryMask = TupleMask.fromSelectedIndices(primaryCompiled.getVariablesTuple().size(), primaryIndices);
337 secondaryMask = TupleMask.fromSelectedIndices(callTrace.getVariablesTuple().size(), secondaryIndices);
338 complementerMask = TupleMask.fromSelectedIndices(callTrace.getVariablesTuple().size(), complementerIndices);
339
340 primaryIndexer = makeIndexerTrace(planToCompile, primaryCompiled, primaryMask);
341 secondaryIndexer = makeIndexerTrace(planToCompile, callTrace, secondaryMask);
342
343 naturalJoinRecipe = FACTORY.createJoinRecipe();
344 naturalJoinRecipe.setLeftParent((ProjectionIndexerRecipe) primaryIndexer.getRecipe());
345 naturalJoinRecipe.setRightParent((IndexerRecipe) secondaryIndexer.getRecipe());
346 naturalJoinRecipe.setRightParentComplementaryMask(CompilerHelper.toRecipeMask(complementerMask));
347
348 naturalJoinVariablesTuple = new ArrayList<PVariable>(primaryCompiled.getVariablesTuple());
349 for (int complementerIndex : complementerMask.indices)
350 naturalJoinVariablesTuple.add(callTrace.getVariablesTuple().get(complementerIndex));
351 }
352
353 public TupleMask getPrimaryMask() {
354 return primaryMask;
355 }
356
357 public TupleMask getSecondaryMask() {
358 return secondaryMask;
359 }
360
361 public TupleMask getComplementerMask() {
362 return complementerMask;
363 }
364
365 public RecipeTraceInfo getPrimaryIndexer() {
366 return primaryIndexer;
367 }
368
369 public RecipeTraceInfo getSecondaryIndexer() {
370 return secondaryIndexer;
371 }
372
373 public JoinRecipe getNaturalJoinRecipe() {
374 return naturalJoinRecipe;
375 }
376
377 public List<PVariable> getNaturalJoinVariablesTuple() {
378 return naturalJoinVariablesTuple;
379 }
380
381 }
382
383 /**
384 * @since 1.4
385 */
386 public static Mask toRecipeMask(TupleMask mask) {
387 return RecipesHelper.mask(mask.sourceWidth, mask.indices);
388 }
389
390}