aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java')
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java430
1 files changed, 430 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java
new file mode 100644
index 00000000..73312dc9
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java
@@ -0,0 +1,430 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
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.localsearch.planner.compiler;
10
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Map;
16import java.util.Set;
17import java.util.stream.Collectors;
18import java.util.stream.Stream;
19
20import tools.refinery.viatra.runtime.localsearch.matcher.CallWithAdornment;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.localsearch.operations.check.AggregatorCheck;
23import tools.refinery.viatra.runtime.localsearch.operations.check.BinaryTransitiveClosureCheck;
24import tools.refinery.viatra.runtime.localsearch.operations.check.CheckConstant;
25import tools.refinery.viatra.runtime.localsearch.operations.check.CheckPositivePatternCall;
26import tools.refinery.viatra.runtime.localsearch.operations.check.CountCheck;
27import tools.refinery.viatra.runtime.localsearch.operations.check.ExpressionCheck;
28import tools.refinery.viatra.runtime.localsearch.operations.check.ExpressionEvalCheck;
29import tools.refinery.viatra.runtime.localsearch.operations.check.InequalityCheck;
30import tools.refinery.viatra.runtime.localsearch.operations.check.NACOperation;
31import tools.refinery.viatra.runtime.localsearch.operations.extend.AggregatorExtend;
32import tools.refinery.viatra.runtime.localsearch.operations.extend.CountOperation;
33import tools.refinery.viatra.runtime.localsearch.operations.extend.ExpressionEval;
34import tools.refinery.viatra.runtime.localsearch.operations.extend.ExtendBinaryTransitiveClosure;
35import tools.refinery.viatra.runtime.localsearch.operations.extend.ExtendConstant;
36import tools.refinery.viatra.runtime.localsearch.operations.extend.ExtendPositivePatternCall;
37import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
38import tools.refinery.viatra.runtime.localsearch.planner.util.CompilerHelper;
39import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
40import tools.refinery.viatra.runtime.matchers.context.IInputKey;
41import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
42import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
43import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
44import tools.refinery.viatra.runtime.matchers.planning.operations.PApply;
45import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
46import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
47import tools.refinery.viatra.runtime.matchers.planning.operations.PStart;
48import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
49import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
50import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint;
51import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
52import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
53import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Inequality;
54import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.NegativePatternCall;
55import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.PatternMatchCounter;
56import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
57import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryReflexiveTransitiveClosure;
58import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
59import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
60import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
61import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
62import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
63
64/**
65 * @author Zoltan Ujhelyi
66 * @since 1.7
67 *
68 */
69public abstract class AbstractOperationCompiler implements IOperationCompiler {
70
71 protected static final String UNSUPPORTED_TYPE_MESSAGE = "Unsupported type: ";
72
73 protected abstract void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping);
74
75 /**
76 * @throws ViatraQueryRuntimeException
77 */
78 protected abstract void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping);
79
80 /**
81 * @throws ViatraQueryRuntimeException
82 */
83 protected abstract void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping);
84
85 /**
86 * @since 2.0
87 * @throws ViatraQueryRuntimeException
88 */
89 protected abstract void createUnaryTypeCheck(IInputKey type, int position);
90
91 protected List<ISearchOperation> operations;
92 protected Set<CallWithAdornment> dependencies = new HashSet<>();
93 protected Map<PConstraint, Set<Integer>> variableBindings;
94 private Map<PVariable, Integer> variableMappings;
95 protected final IQueryRuntimeContext runtimeContext;
96
97 public AbstractOperationCompiler(IQueryRuntimeContext runtimeContext) {
98 this.runtimeContext = runtimeContext;
99 }
100
101 /**
102 * Compiles a plan of <code>POperation</code>s to a list of type <code>List&ltISearchOperation></code>
103 *
104 * @param plan
105 * @param boundParameters
106 * @return an ordered list of POperations that make up the compiled search plan
107 * @throws ViatraQueryRuntimeException
108 */
109 @Override
110 public List<ISearchOperation> compile(SubPlan plan, Set<PParameter> boundParameters) {
111
112 variableMappings = CompilerHelper.createVariableMapping(plan);
113 variableBindings = CompilerHelper.cacheVariableBindings(plan, variableMappings, boundParameters);
114
115 operations = new ArrayList<>();
116
117 List<POperation> operationList = CompilerHelper.createOperationsList(plan);
118 for (POperation pOperation : operationList) {
119 compile(pOperation, variableMappings);
120 }
121
122 return operations;
123 }
124
125 private void compile(POperation pOperation, Map<PVariable, Integer> variableMapping) {
126
127 if (pOperation instanceof PApply) {
128 PApply pApply = (PApply) pOperation;
129 PConstraint pConstraint = pApply.getPConstraint();
130
131 if (isCheck(pConstraint, variableMapping)) {
132 // check
133 createCheckDispatcher(pConstraint, variableMapping);
134 } else {
135 // extend
136 createExtendDispatcher(pConstraint, variableMapping);
137 }
138
139 } else if (pOperation instanceof PStart) {
140 // nop
141 } else if (pOperation instanceof PProject) {
142 // nop
143 } else {
144 throw new QueryProcessingException("PStart, PApply or PProject was expected, received: " + pOperation.getClass(), null,"Unexpected POperation type", null);
145 }
146
147 }
148
149 private void createCheckDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) {
150
151
152 // DeferredPConstraint subclasses
153
154 // Equalities are normalized
155
156 if (pConstraint instanceof Inequality) {
157 createCheck((Inequality) pConstraint, variableMapping);
158 } else if (pConstraint instanceof PositivePatternCall){
159 createCheck((PositivePatternCall) pConstraint, variableMapping);
160 } else if (pConstraint instanceof NegativePatternCall) {
161 createCheck((NegativePatternCall) pConstraint,variableMapping);
162 } else if (pConstraint instanceof AggregatorConstraint) {
163 createCheck((AggregatorConstraint) pConstraint, variableMapping);
164 } else if (pConstraint instanceof PatternMatchCounter) {
165 createCheck((PatternMatchCounter) pConstraint, variableMapping);
166 } else if (pConstraint instanceof ExpressionEvaluation) {
167 createCheck((ExpressionEvaluation) pConstraint, variableMapping);
168 } else if (pConstraint instanceof TypeFilterConstraint) {
169 createCheck((TypeFilterConstraint) pConstraint,variableMapping);
170 } else if (pConstraint instanceof ExportedParameter) {
171 // Nothing to do here
172 } else
173
174 // EnumerablePConstraint subclasses
175
176 if (pConstraint instanceof BinaryTransitiveClosure) {
177 createCheck((BinaryTransitiveClosure) pConstraint, variableMapping);
178 } else if (pConstraint instanceof BinaryReflexiveTransitiveClosure) {
179 createCheck((BinaryReflexiveTransitiveClosure)pConstraint, variableMapping);
180 } else if (pConstraint instanceof ConstantValue) {
181 createCheck((ConstantValue) pConstraint, variableMapping);
182 } else if (pConstraint instanceof TypeConstraint) {
183 createCheck((TypeConstraint) pConstraint,variableMapping);
184 } else {
185 String msg = "Unsupported Check constraint: "+pConstraint.toString();
186 throw new QueryProcessingException(msg, null, msg, null);
187 }
188
189 }
190
191 protected void createExtendDispatcher(PConstraint pConstraint, Map<PVariable, Integer> variableMapping) {
192
193 // DeferredPConstraint subclasses
194
195 // Equalities are normalized
196 if (pConstraint instanceof PositivePatternCall) {
197 createExtend((PositivePatternCall)pConstraint, variableMapping);
198 } else if (pConstraint instanceof AggregatorConstraint) {
199 createExtend((AggregatorConstraint) pConstraint, variableMapping);
200 } else if (pConstraint instanceof PatternMatchCounter) {
201 createExtend((PatternMatchCounter) pConstraint, variableMapping);
202 } else if (pConstraint instanceof ExpressionEvaluation) {
203 createExtend((ExpressionEvaluation) pConstraint, variableMapping);
204 } else if (pConstraint instanceof ExportedParameter) {
205 // ExportedParameters are compiled to NOP
206 } else
207
208 // EnumerablePConstraint subclasses
209
210 if (pConstraint instanceof ConstantValue) {
211 createExtend((ConstantValue) pConstraint, variableMapping);
212 } else if (pConstraint instanceof TypeConstraint) {
213 createExtend((TypeConstraint) pConstraint, variableMapping);
214 } else if (pConstraint instanceof BinaryTransitiveClosure) {
215 createExtend((BinaryTransitiveClosure)pConstraint, variableMapping);
216 } else if (pConstraint instanceof BinaryReflexiveTransitiveClosure) {
217 createExtend((BinaryReflexiveTransitiveClosure)pConstraint, variableMapping);
218 } else {
219 String msg = "Unsupported Extend constraint: "+pConstraint.toString();
220 throw new QueryProcessingException(msg, null, msg, null);
221 }
222 }
223
224 private boolean isCheck(PConstraint pConstraint, final Map<PVariable, Integer> variableMapping) {
225 if (pConstraint instanceof NegativePatternCall){
226 return true;
227 }else if (pConstraint instanceof PositivePatternCall){
228 // Positive pattern call is check if all non-single used variables are bound
229 List<Integer> callVariables = pConstraint.getAffectedVariables().stream()
230 .filter(input -> input.getReferringConstraints().size() > 1)
231 .map(variableMapping::get)
232 .collect(Collectors.toList());
233 return variableBindings.get(pConstraint).containsAll(callVariables);
234 }else if (pConstraint instanceof AggregatorConstraint){
235 PVariable outputvar = ((AggregatorConstraint) pConstraint).getResultVariable();
236 return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar));
237 }else if (pConstraint instanceof PatternMatchCounter){
238 PVariable outputvar = ((PatternMatchCounter) pConstraint).getResultVariable();
239 return variableBindings.get(pConstraint).contains(variableMapping.get(outputvar));
240 }else if (pConstraint instanceof ExpressionEvaluation){
241 PVariable outputvar = ((ExpressionEvaluation) pConstraint).getOutputVariable();
242 return outputvar == null || variableBindings.get(pConstraint).contains(variableMapping.get(outputvar));
243 } else {
244 // In other cases, all variables shall be bound to be a check
245 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
246 Set<Integer> varIndices = new HashSet<>();
247 for (PVariable variable : affectedVariables) {
248 varIndices.add(variableMapping.get(variable));
249 }
250 return variableBindings.get(pConstraint).containsAll(varIndices);
251 }
252 }
253
254 @Override
255 public Set<CallWithAdornment> getDependencies() {
256 return dependencies;
257 }
258
259 /**
260 * @return the cached variable bindings for the previously created plan
261 */
262 @Override
263 public Map<PVariable, Integer> getVariableMappings() {
264 return variableMappings;
265 }
266
267 protected void createCheck(PatternMatchCounter counter, Map<PVariable, Integer> variableMapping) {
268 CallInformation information = CallInformation.create(counter, variableMapping, variableBindings.get(counter));
269 operations.add(new CountCheck(information, variableMapping.get(counter.getResultVariable())));
270 dependencies.add(information.getCallWithAdornment());
271 }
272
273 protected void createCheck(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) {
274 CallInformation information = CallInformation.create(pCall, variableMapping, variableBindings.get(pCall));
275 operations.add(new CheckPositivePatternCall(information));
276 dependencies.add(information.getCallWithAdornment());
277 }
278
279 protected void createCheck(ConstantValue constant, Map<PVariable, Integer> variableMapping) {
280 int position = variableMapping.get(constant.getVariablesTuple().get(0));
281 operations.add(new CheckConstant(position, constant.getSupplierKey()));
282 }
283
284 protected void createCheck(BinaryTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) {
285 int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0));
286 int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1));
287
288 //The second parameter is NOT bound during execution!
289 CallInformation information = CallInformation.create(binaryTransitiveClosure, variableMapping, Stream.of(sourcePosition).collect(Collectors.toSet()));
290 operations.add(new BinaryTransitiveClosureCheck(information, sourcePosition, targetPosition, false));
291 dependencies.add(information.getCallWithAdornment());
292 }
293
294 /**
295 * @since 2.0
296 */
297 protected void createCheck(BinaryReflexiveTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) {
298 int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0));
299 int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1));
300
301 //The second parameter is NOT bound during execution!
302 CallInformation information = CallInformation.create(binaryTransitiveClosure, variableMapping, Stream.of(sourcePosition).collect(Collectors.toSet()));
303 createUnaryTypeCheck(binaryTransitiveClosure.getUniverseType(), sourcePosition);
304 operations.add(new BinaryTransitiveClosureCheck(information, sourcePosition, targetPosition, true));
305 dependencies.add(information.getCallWithAdornment());
306 }
307
308 protected void createCheck(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) {
309 // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway
310 Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames();
311 Map<String, Integer> nameMap = new HashMap<>();
312
313 for (String pVariableName : inputParameterNames) {
314 PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName);
315 nameMap.put(pVariableName, variableMapping.get(pVariable));
316 }
317
318 // output variable can be null; if null it is an ExpressionCheck
319 if(expressionEvaluation.getOutputVariable() == null){
320 operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap));
321 } else {
322 operations.add(new ExpressionEvalCheck(expressionEvaluation.getEvaluator(), nameMap, expressionEvaluation.isUnwinding(), variableMapping.get(expressionEvaluation.getOutputVariable())));
323 }
324 }
325
326 protected void createCheck(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) {
327 CallInformation information = CallInformation.create(aggregator, variableMapping, variableBindings.get(aggregator));
328 operations.add(new AggregatorCheck(information, aggregator, variableMapping.get(aggregator.getResultVariable())));
329 dependencies.add(information.getCallWithAdornment());
330 }
331
332 protected void createCheck(NegativePatternCall negativePatternCall, Map<PVariable, Integer> variableMapping) {
333 CallInformation information = CallInformation.create(negativePatternCall, variableMapping, variableBindings.get(negativePatternCall));
334 operations.add(new NACOperation(information));
335 dependencies.add(information.getCallWithAdornment());
336 }
337
338 protected void createCheck(Inequality inequality, Map<PVariable, Integer> variableMapping) {
339 operations.add(new InequalityCheck(variableMapping.get(inequality.getWho()), variableMapping.get(inequality.getWithWhom())));
340 }
341
342 protected void createExtend(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping) {
343 CallInformation information = CallInformation.create(pCall, variableMapping, variableBindings.get(pCall));
344 operations.add(new ExtendPositivePatternCall(information));
345 dependencies.add(information.getCallWithAdornment());
346 }
347
348 protected void createExtend(BinaryTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) {
349 int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0));
350 int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1));
351
352 boolean sourceBound = variableBindings.get(binaryTransitiveClosure).contains(sourcePosition);
353 boolean targetBound = variableBindings.get(binaryTransitiveClosure).contains(targetPosition);
354
355 CallInformation information = CallInformation.create(binaryTransitiveClosure, variableMapping, variableBindings.get(binaryTransitiveClosure));
356
357 if (sourceBound && !targetBound) {
358 operations.add(new ExtendBinaryTransitiveClosure.Forward(information, sourcePosition, targetPosition, false));
359 dependencies.add(information.getCallWithAdornment());
360 } else if (!sourceBound && targetBound) {
361 operations.add(new ExtendBinaryTransitiveClosure.Backward(information, sourcePosition, targetPosition, false));
362 dependencies.add(information.getCallWithAdornment());
363 } else {
364 String msg = "Binary transitive closure not supported with two unbound parameters";
365 throw new QueryProcessingException(msg, null, msg, binaryTransitiveClosure.getPSystem().getPattern());
366 }
367 }
368
369 /**
370 * @since 2.0
371 */
372 protected void createExtend(BinaryReflexiveTransitiveClosure binaryTransitiveClosure, Map<PVariable, Integer> variableMapping) {
373 int sourcePosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(0));
374 int targetPosition = variableMapping.get(binaryTransitiveClosure.getVariablesTuple().get(1));
375
376 boolean sourceBound = variableBindings.get(binaryTransitiveClosure).contains(sourcePosition);
377 boolean targetBound = variableBindings.get(binaryTransitiveClosure).contains(targetPosition);
378
379 CallInformation information = CallInformation.create(binaryTransitiveClosure, variableMapping, variableBindings.get(binaryTransitiveClosure));
380
381 if (sourceBound && !targetBound) {
382 createUnaryTypeCheck(binaryTransitiveClosure.getUniverseType(), sourcePosition);
383 operations.add(new ExtendBinaryTransitiveClosure.Forward(information, sourcePosition, targetPosition, true));
384 dependencies.add(information.getCallWithAdornment());
385 } else if (!sourceBound && targetBound) {
386 createUnaryTypeCheck(binaryTransitiveClosure.getUniverseType(), targetPosition);
387 operations.add(new ExtendBinaryTransitiveClosure.Backward(information, sourcePosition, targetPosition, true));
388 dependencies.add(information.getCallWithAdornment());
389 } else {
390 String msg = "Binary reflective transitive closure not supported with two unbound parameters";
391 throw new QueryProcessingException(msg, null, msg, binaryTransitiveClosure.getPSystem().getPattern());
392 }
393 }
394
395 protected void createExtend(ConstantValue constant, Map<PVariable, Integer> variableMapping) {
396 int position = variableMapping.get(constant.getVariablesTuple().get(0));
397 operations.add(new ExtendConstant(position, constant.getSupplierKey()));
398 }
399
400 protected void createExtend(ExpressionEvaluation expressionEvaluation, Map<PVariable, Integer> variableMapping) {
401 // Fill unbound variables with null; simply copy all variables. Unbound variables will be null anyway
402 Iterable<String> inputParameterNames = expressionEvaluation.getEvaluator().getInputParameterNames();
403 Map<String, Integer> nameMap = new HashMap<>();
404
405 for (String pVariableName : inputParameterNames) {
406 PVariable pVariable = expressionEvaluation.getPSystem().getVariableByNameChecked(pVariableName);
407 nameMap.put(pVariableName, variableMapping.get(pVariable));
408 }
409
410 // output variable can be null; if null it is an ExpressionCheck
411 if(expressionEvaluation.getOutputVariable() == null){
412 operations.add(new ExpressionCheck(expressionEvaluation.getEvaluator(), nameMap));
413 } else {
414 operations.add(new ExpressionEval(expressionEvaluation.getEvaluator(), nameMap, expressionEvaluation.isUnwinding(), variableMapping.get(expressionEvaluation.getOutputVariable())));
415 }
416 }
417
418 protected void createExtend(AggregatorConstraint aggregator, Map<PVariable, Integer> variableMapping) {
419 CallInformation information = CallInformation.create(aggregator, variableMapping, variableBindings.get(aggregator));
420 operations.add(new AggregatorExtend(information, aggregator, variableMapping.get(aggregator.getResultVariable())));
421 dependencies.add(information.getCallWithAdornment());
422 }
423
424 protected void createExtend(PatternMatchCounter patternMatchCounter, Map<PVariable, Integer> variableMapping) {
425 CallInformation information = CallInformation.create(patternMatchCounter, variableMapping, variableBindings.get(patternMatchCounter));
426 operations.add(new CountOperation(information, variableMapping.get(patternMatchCounter.getResultVariable())));
427 dependencies.add(information.getCallWithAdornment());
428 }
429
430} \ No newline at end of file