aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-localsearch/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-localsearch/src/main/java')
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java83
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java114
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/exceptions/LocalSearchException.java33
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/CallWithAdornment.java55
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdaptable.java29
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdapter.java120
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java120
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/LocalSearchMatcher.java301
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/MatcherReference.java97
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java532
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AllValidAdornments.java37
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenDisjunctive.java29
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenIncrementalPredicate.java44
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java49
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/IAdornmentProvider.java72
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LazyPlanningAdornments.java41
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackend.java259
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java65
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactoryProvider.java24
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHintOptions.java70
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java306
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/CheckOperationExecutor.java50
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ExtendOperationExecutor.java77
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IIteratingSearchOperation.java27
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IPatternMatcherOperation.java26
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ISearchOperation.java88
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/MatchingFrameValueProvider.java41
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/AggregatorCheck.java116
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/BinaryTransitiveClosureCheck.java135
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckConstant.java70
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckPositivePatternCall.java96
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CountCheck.java92
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionCheck.java78
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionEvalCheck.java95
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InequalityCheck.java77
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/NACOperation.java89
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/AggregatorExtend.java106
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/CountOperation.java88
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExpressionEval.java104
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendBinaryTransitiveClosure.java185
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendConstant.java75
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendPositivePatternCall.java118
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/SingleValueExtendOperationExecutor.java40
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeCheck.java96
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtend.java145
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtendSingleValue.java114
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/util/CallInformation.java186
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanDescriptor.java49
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanProvider.java33
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/PlanDescriptor.java84
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlan.java99
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanExecutor.java210
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanForBody.java115
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SimplePlanProvider.java49
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ILocalSearchPlanner.java38
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ISearchPlanCodeGenerator.java23
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchPlanner.java140
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchRuntimeBasedStrategy.java257
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintCategory.java41
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfo.java142
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java278
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java283
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/AbstractOperationCompiler.java430
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/GenericOperationCompiler.java101
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/IOperationCompiler.java53
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/IConstraintEvaluationContext.java63
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/ICostFunction.java22
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/HybridMatcherConstraintCostFunction.java91
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/IndexerBasedConstraintCostFunction.java49
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/StatisticsBasedConstraintCostFunction.java413
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/VariableBindingBasedCostFunction.java95
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/CompilerHelper.java209
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/OperationCostComparator.java26
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/profiler/LocalSearchProfilerAdapter.java83
74 files changed, 8370 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java
new file mode 100644
index 00000000..bfb76d9a
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, 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;
10
11import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter;
12import tools.refinery.viatra.runtime.localsearch.matcher.LocalSearchMatcher;
13import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
14import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
15import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
16
17import java.util.Optional;
18import java.util.function.Consumer;
19
20/**
21 * @since 2.0
22 */
23public final class ExecutionLoggerAdapter implements ILocalSearchAdapter {
24
25 volatile String indentation = "";
26 private final Consumer<String> outputConsumer;
27
28 public ExecutionLoggerAdapter(Consumer<String> outputConsumer) {
29 this.outputConsumer = outputConsumer;
30 }
31
32 private void logMessage(String message) {
33 outputConsumer.accept(message);
34 }
35
36 private void logMessage(String message, Object...args) {
37 outputConsumer.accept(String.format(message, args));
38 }
39
40 @Override
41 public void patternMatchingStarted(LocalSearchMatcher lsMatcher) {
42 logMessage(indentation + "[ START] " + lsMatcher.getQuerySpecification().getFullyQualifiedName());
43 }
44
45 @Override
46 public void noMoreMatchesAvailable(LocalSearchMatcher lsMatcher) {
47 logMessage(indentation + "[FINISH] " + lsMatcher.getQuerySpecification().getFullyQualifiedName());
48 }
49
50 @Override
51 public void planChanged(Optional<SearchPlan> oldPlan, Optional<SearchPlan> newPlan) {
52 logMessage(indentation + "[ PLAN] " + newPlan.map(p -> p.getSourceBody().getPattern().getFullyQualifiedName()).orElse(""));
53 logMessage(indentation + newPlan.map(SearchPlan::toString).map(s -> s.replace("\n", "\n" + indentation)).orElse(""));
54 }
55
56 @Override
57 public void operationSelected(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isBacktrack) {
58 String category = isBacktrack ? "[ BACK] " : "[SELECT] ";
59 logMessage(indentation + category + operation.toString());
60 if (operation instanceof IPatternMatcherOperation) {
61 indentation = indentation + "\t";
62 }
63 }
64
65 @Override
66 public void operationExecuted(SearchPlan plan, ISearchOperation operation, MatchingFrame frame,
67 boolean isSuccessful) {
68 if (operation instanceof IPatternMatcherOperation && indentation.length() > 0) {
69 indentation = indentation.substring(1);
70 }
71 logMessage(indentation + "[ %s] %s %s", isSuccessful ? "OK" : "NO", operation.toString(), frame.toString());
72 }
73
74 @Override
75 public void matchFound(SearchPlan plan, MatchingFrame frame) {
76 logMessage(indentation + "[ MATCH] " + plan.getSourceBody().getPattern().getFullyQualifiedName() + " " + frame.toString());
77 }
78
79 @Override
80 public void duplicateMatchFound(MatchingFrame frame) {
81 logMessage(indentation + "[ DUPL.] " + frame.toString());
82 }
83}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java
new file mode 100644
index 00000000..bdbc663c
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java
@@ -0,0 +1,114 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Akos Horvath, Gergely Varro Zoltan Ujhelyi 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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.localsearch;
11
12import tools.refinery.viatra.runtime.matchers.tuple.IModifiableTuple;
13import tools.refinery.viatra.runtime.matchers.tuple.VolatileTuple;
14import tools.refinery.viatra.runtime.matchers.util.Preconditions;
15
16import java.util.Arrays;
17import java.util.stream.Collectors;
18
19/**
20 * A MatchingFrame is a Volatile Tuple implementation used by the local search engine internally.
21 */
22public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
23
24 /**
25 * The array that physically holds the values.
26 */
27 private Object[] frame;
28
29 /**
30 * @since 1.7
31 */
32 public MatchingFrame(int frameSize) {
33 this.frame = new Object[frameSize];
34 }
35
36 /**
37 * Creates a copy of another matching frame; the two frames can be updated separately
38 * @param other
39 * @since 1.7
40 */
41 public MatchingFrame(MatchingFrame other) {
42 this.frame = Arrays.copyOf(other.frame, other.frame.length);
43 }
44
45
46
47 /**
48 * Returns the value stored inside the matching frame.
49 *
50 * @param position
51 * @return the element stored in the selected position in the frame, or null if it is not yet set
52 * @throws IndexOutOfBoundsException
53 * if position is negative
54 * @throws IllegalArgumentException
55 * if the position is larger then the length of the frame
56 */
57 public Object getValue(int position) {
58 Preconditions.checkElementIndex(position, frame.length);
59 return frame[position];
60 }
61
62 /**
63 * Sets the value of the variable at the given position. For internal use in LS matching only.
64 *
65 * @param position the position of the variable within the frame
66 * @param value the value to be set for the variable
67 */
68 public void setValue(int position, Object value) {
69 Preconditions.checkElementIndex(position, frame.length);
70 frame[position] = value;
71 }
72
73 public boolean testAndSetValue(Integer position, Object value) {
74 Preconditions.checkElementIndex(position, frame.length);
75 if (frame[position] == null) {
76 frame[position] = value;
77 return true;
78 } else {
79 return frame[position].equals(value);
80 }
81 }
82
83 @Override
84 public String toString() {
85 return Arrays.stream(frame).map(this::stringRepresentation).collect(Collectors.joining(", ", "[", "]"));
86 }
87
88 private String stringRepresentation(Object obj) {
89 if (obj == null) {
90 return "_";
91 }
92 return obj.toString();
93 }
94
95 @Override
96 public int getSize() {
97 return frame.length;
98 }
99
100 @Override
101 public Object get(int index) {
102 return getValue(index);
103 }
104
105 @Override
106 public Object[] getElements() {
107 return Arrays.copyOf(frame, frame.length);
108 }
109
110 @Override
111 public void set(int index, Object value) {
112 frame[index] = value;
113 }
114}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/exceptions/LocalSearchException.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/exceptions/LocalSearchException.java
new file mode 100644
index 00000000..c239e766
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/exceptions/LocalSearchException.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.exceptions;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12
13/**
14 * @author Zoltan Ujhelyi, Akos Horvath
15 *
16 */
17public class LocalSearchException extends ViatraQueryRuntimeException {
18
19 private static final long serialVersionUID = -2585896573351435974L;
20
21 public static final String PLAN_EXECUTION_ERROR = "Error while executing search plan";
22 public static final String TYPE_ERROR = "Invalid type of variable";
23
24 public LocalSearchException(String description, Throwable rootException) {
25 super(description, rootException);
26 }
27
28 public LocalSearchException(String description) {
29 super(description);
30 }
31
32
33}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/CallWithAdornment.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/CallWithAdornment.java
new file mode 100644
index 00000000..0cabeb97
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/CallWithAdornment.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, 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.matcher;
10
11import java.util.HashSet;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18
19/**
20 * Immutable data that represents the role of a pattern call within an LS query plan.
21 *
22 * <p> The call is expressed as the {@link PConstraint} {@link #call} (implementing {@link IQueryReference}),
23 * while the stored {@link #adornment} records the way it will be used within a search plan (specifically,
24 * pattern parameters within the adornment will have their values known at the point of evaluating the constraint).
25 *
26 *
27 * @author Gabor Bergmann
28 * @since 2.1
29 */
30public class CallWithAdornment {
31 private final IQueryReference call;
32 private final Set<PParameter> adornment;
33
34 public CallWithAdornment(IQueryReference call, Set<PParameter> adornment) {
35 this.call = call;
36 this.adornment = new HashSet<>(adornment);
37 }
38
39 public IQueryReference getCall() {
40 return call;
41 }
42
43 public Set<PParameter> getAdornment() {
44 return adornment;
45 }
46
47
48 public PQuery getReferredQuery() {
49 return call.getReferredQuery();
50 }
51
52 public MatcherReference getMatcherReference() {
53 return new MatcherReference(getReferredQuery(), adornment);
54 }
55}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdaptable.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdaptable.java
new file mode 100644
index 00000000..f4b28ed0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdaptable.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Peter Lunk, 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.matcher;
10
11import java.util.List;
12
13/**
14 * @author Zoltan Ujhelyi
15 *
16 */
17public interface ILocalSearchAdaptable {
18
19 List<ILocalSearchAdapter> getAdapters();
20
21 void addAdapter(ILocalSearchAdapter adapter);
22
23 void removeAdapter(ILocalSearchAdapter adapter);
24
25 void removeAdapters(List<ILocalSearchAdapter> adapter);
26
27 void addAdapters(List<ILocalSearchAdapter> adapter);
28
29} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdapter.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdapter.java
new file mode 100644
index 00000000..df64b5f1
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ILocalSearchAdapter.java
@@ -0,0 +1,120 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.matcher;
10
11import java.util.Optional;
12
13import tools.refinery.viatra.runtime.localsearch.ExecutionLoggerAdapter;
14import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
15import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
16import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
17import tools.refinery.viatra.runtime.localsearch.profiler.LocalSearchProfilerAdapter;
18
19
20/**
21 * A local search adapter allows external code to follow the internal executions of the local search matcher. Possible
22 * implementations of the interface include profilers and debuggers.
23 * <p>
24 * <strong>EXPERIMENTAL</strong>. A few shortcomings have been found for this interface late during the development
25 * lifecycle of version 2.0 whose solution might need breaking possible future implementors. Because of this, right now
26 * it is not recommended to provide implementations outside of VIATRA. If necessary, have a look at the built-in
27 * adapters that should fulfill most cases in the meantime. See bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=535101
28 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=535102 for details.
29 *
30 * @author Marton Bur
31 * @see ExecutionLoggerAdapter
32 * @see LocalSearchProfilerAdapter
33 *
34 */
35public interface ILocalSearchAdapter {
36
37 /**
38 *
39 * @since 1.2
40 */
41 default void adapterRegistered(ILocalSearchAdaptable adaptable) {};
42 /**
43 *
44 * @since 1.2
45 */
46 default void adapterUnregistered(ILocalSearchAdaptable adaptable) {};
47
48 /**
49 * Callback method to indicate the start of a matching process
50 *
51 * @param lsMatcher the local search matcher that starts the matching
52 */
53 default void patternMatchingStarted(LocalSearchMatcher lsMatcher) {};
54
55 /**
56 * Callback method to indicate the end of a matching process
57 * </p>
58 * <strong>WARNING</strong>: It is not guaranteed that this method will be called;
59 * it is possible that a match process will end after a match is found and no other matches are accessed.
60 *
61 * @param lsMatcher the local search matcher that finished
62 * @since 2.0
63 */
64 default void noMoreMatchesAvailable(LocalSearchMatcher lsMatcher) {};
65
66 /**
67 * Callback method to indicate switching to a new plan during the execution of a pattern matching
68 *
69 * @param oldPlan the plan that is finished. Value is null when the first plan is starting.
70 * @param newPlan the plan that will begin execution
71 * @since 2.0
72 */
73 default void planChanged(Optional<SearchPlan> oldPlan, Optional<SearchPlan> newPlan) {};
74
75 /**
76 * Callback method to indicate the selection of an operation to execute
77 *
78 * @param plan the current plan executor
79 * @param frame the current matching frame
80 * @param isBacktrack if true, the selected operation was reached via backtracking
81 * @since 2.0
82 */
83 default void operationSelected(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isBacktrack) {};
84
85 /**
86 * Callback method to indicate that an operation is executed
87 *
88 * @param plan the current plan
89 * @param frame the current matching frame
90 * @param isSuccessful if true, the operation executed successfully, or false if the execution failed and backtracking will happen
91 * @since 2.0
92 */
93 default void operationExecuted(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isSuccessful) {};
94
95 /**
96 * Callback that is used to indicate that a match has been found
97 *
98 * @param plan the search plan executor that found the match
99 * @param frame the frame that holds the substitutions of the variables that match
100 * @since 2.0
101 */
102 default void matchFound(SearchPlan plan, MatchingFrame frame) {};
103 /**
104 * Callback that is used to indicate that the previously reported match has been found as a duplicate, thus will be ignored from the match results.
105 *
106 * @param plan the search plan executor that found the match
107 * @param frame the frame that holds the substitutions of the variables that match
108 * @since 2.0
109 */
110 default void duplicateMatchFound(MatchingFrame frame) {};
111
112 /**
113 * Callback method to indicate that a search plan is initialized in an executor with the given frame and starting operation
114 *
115 * @param searchPlan
116 * @param frame
117 * @since 2.0
118 */
119 default void executorInitializing(SearchPlan searchPlan, MatchingFrame frame) {};
120}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java
new file mode 100644
index 00000000..71aa4aac
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java
@@ -0,0 +1,120 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, 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.localsearch.matcher;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.localsearch.matcher.integration.IAdornmentProvider;
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
15import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
16import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
18import tools.refinery.viatra.runtime.matchers.util.ICache;
19import tools.refinery.viatra.runtime.matchers.util.IProvider;
20
21import java.util.Collections;
22
23/**
24 * The {@link ISearchContext} interface allows search operations to reuse platform services such as the indexer.
25 *
26 * @author Zoltan Ujhelyi
27 * @noreference This interface is not intended to be referenced by clients.
28 * @noimplement This interface is not intended to be implemented by clients.
29 * @noextend This interface is not intended to be extended by clients.
30 *
31 */
32public interface ISearchContext {
33
34 /**
35 * Provides access to the generic query runtime context of the current engine
36 * @since 1.7
37 */
38 IQueryRuntimeContext getRuntimeContext();
39
40 /**
41 * Returns a matcher for a selected query specification.
42 *
43 * @throws ViatraQueryRuntimeException
44 * @since 1.5
45 */
46 IQueryResultProvider getMatcher(CallWithAdornment dependency);
47
48 /**
49 * Allows search operations to cache values through the entire lifecycle of the local search backend. The values are
50 * calculated if not cached before using the given provider, or returned from the cache accordingly.
51 *
52 * @since 1.7
53 */
54 <T> T accessBackendLevelCache(Object key, Class<? extends T> clazz, IProvider<T> valueProvider);
55
56 /**
57 * Returns the engine-specific logger
58 *
59 * @since 2.0
60 */
61 Logger getLogger();
62
63 /**
64 * @noreference This class is not intended to be referenced by clients.
65 * @noimplement This interface is not intended to be implemented by clients.
66 * @noextend This interface is not intended to be extended by clients.
67 */
68 public class SearchContext implements ISearchContext {
69
70 private final IQueryRuntimeContext runtimeContext;
71
72 private final ICache backendLevelCache;
73 private final Logger logger;
74 private final ResultProviderRequestor resultProviderRequestor;
75
76 /**
77 * Initializes a search context using an arbitrary backend context
78 */
79 public SearchContext(IQueryBackendContext backendContext, ICache backendLevelCache,
80 ResultProviderRequestor resultProviderRequestor) {
81 this.resultProviderRequestor = resultProviderRequestor;
82 this.runtimeContext = backendContext.getRuntimeContext();
83 this.logger = backendContext.getLogger();
84
85 this.backendLevelCache = backendLevelCache;
86 }
87
88 /**
89 * @throws ViatraQueryRuntimeException
90 * @since 2.1
91 */
92 @Override
93 public IQueryResultProvider getMatcher(CallWithAdornment dependency) {
94 // Inject adornment for referenced pattern
95 IAdornmentProvider adornmentProvider = query -> {
96 if (query.equals(dependency.getReferredQuery())){
97 return Collections.singleton(dependency.getAdornment());
98 }
99 return Collections.emptySet();
100 };
101 return resultProviderRequestor.requestResultProvider(dependency.getCall(),
102 IAdornmentProvider.toHint(adornmentProvider));
103 }
104
105 @Override
106 public <T> T accessBackendLevelCache(Object key, Class<? extends T> clazz, IProvider<T> valueProvider) {
107 return backendLevelCache.getValue(key, clazz, valueProvider);
108 }
109
110 public IQueryRuntimeContext getRuntimeContext() {
111 return runtimeContext;
112 }
113
114 @Override
115 public Logger getLogger() {
116 return logger;
117 }
118
119 }
120}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/LocalSearchMatcher.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/LocalSearchMatcher.java
new file mode 100644
index 00000000..e31d7b5c
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/LocalSearchMatcher.java
@@ -0,0 +1,301 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Marton Bur, 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.localsearch.matcher;
10
11import java.util.ArrayList;
12import java.util.HashSet;
13import java.util.Iterator;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.NoSuchElementException;
17import java.util.Objects;
18import java.util.Optional;
19import java.util.Set;
20import java.util.Spliterator;
21import java.util.Spliterators;
22import java.util.stream.Collectors;
23import java.util.stream.Stream;
24import java.util.stream.StreamSupport;
25
26import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
27import tools.refinery.viatra.runtime.localsearch.plan.IPlanDescriptor;
28import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
29import tools.refinery.viatra.runtime.localsearch.plan.SearchPlanExecutor;
30import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
31import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
32import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
33import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
34import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
35import tools.refinery.viatra.runtime.matchers.util.Preconditions;
36
37/**
38 * @author Zoltan Ujhelyi
39 * @noinstantiate This class is not intended to be instantiated by clients.
40 */
41public final class LocalSearchMatcher implements ILocalSearchAdaptable {
42
43 private final List<SearchPlanExecutor> plan;
44 private final IPlanDescriptor planDescriptor;
45 private final List<ILocalSearchAdapter> adapters;
46
47 /**
48 * @since 2.0
49 */
50 public List<SearchPlanExecutor> getPlan() {
51 return plan;
52 }
53
54 @Override
55 public List<ILocalSearchAdapter> getAdapters() {
56 return new ArrayList<>(adapters);
57 }
58
59 private abstract class PlanExecutionIterator implements Iterator<Tuple> {
60
61 protected final Iterator<SearchPlanExecutor> planIterator;
62
63 protected SearchPlanExecutor currentPlan;
64 protected MatchingFrame frame;
65 protected final Set<ITuple> matchSet;
66 protected VolatileModifiableMaskedTuple parametersOfFrameView;
67 private boolean isNextMatchCalculated;
68
69 public PlanExecutionIterator(final Iterator<SearchPlanExecutor> planIterator) {
70 this.planIterator = planIterator;
71 isNextMatchCalculated = false;
72 matchSet = new HashSet<>();
73 }
74
75 protected boolean selectNextPlan() {
76 if(currentPlan != null) {
77 currentPlan.removeAdapters(adapters);
78 }
79 boolean validPlanSelected = false;
80
81 SearchPlanExecutor nextPlan = null;
82
83 while (!validPlanSelected && planIterator.hasNext()) {
84 nextPlan = planIterator.next();
85 nextPlan.addAdapters(adapters);
86 nextPlan.resetPlan();
87
88 validPlanSelected = initializeMatchingFrame(nextPlan);
89 }
90
91 if (validPlanSelected) {
92 for (ILocalSearchAdapter adapter : adapters) {
93 adapter.planChanged(Optional.ofNullable(currentPlan).map(SearchPlanExecutor::getSearchPlan),
94 Optional.ofNullable(nextPlan).map(SearchPlanExecutor::getSearchPlan));
95 }
96 currentPlan = nextPlan;
97 return true;
98 } else {
99 currentPlan = null;
100 return false;
101 }
102 }
103
104 protected abstract boolean initializeMatchingFrame(SearchPlanExecutor nextPlan);
105
106 private boolean findNextNewMatchInCurrentPlan() {
107 boolean foundMatch = currentPlan.execute(frame);
108 while (foundMatch && matchSet.contains(parametersOfFrameView)) {
109 for (ILocalSearchAdapter adapter : adapters) {
110 adapter.duplicateMatchFound(frame);
111 }
112 foundMatch = currentPlan.execute(frame);
113 }
114 return foundMatch;
115 }
116
117 @Override
118 public boolean hasNext() {
119 if (isNextMatchCalculated) {
120 return true;
121 }
122 if (currentPlan == null) {
123 return false;
124 }
125 boolean foundMatch = findNextNewMatchInCurrentPlan();
126
127 while (!foundMatch && planIterator.hasNext()) {
128 foundMatch = selectNextPlan() && findNextNewMatchInCurrentPlan();
129 }
130 if (!foundMatch) {
131 for (ILocalSearchAdapter adapter : adapters) {
132 adapter.noMoreMatchesAvailable(LocalSearchMatcher.this);
133 }
134 }
135 isNextMatchCalculated = foundMatch;
136 return foundMatch;
137 }
138
139 @Override
140 public Tuple next() {
141 if (!hasNext()) {
142 throw new NoSuchElementException("No more matches available.");
143 }
144 isNextMatchCalculated = false;
145 final Tuple match = parametersOfFrameView.toImmutable();
146 matchSet.add(match);
147 return match;
148 }
149 }
150
151 private class PlanExecutionIteratorWithArrayParameters extends PlanExecutionIterator {
152
153 private final Object[] parameterValues;
154
155 public PlanExecutionIteratorWithArrayParameters(Iterator<SearchPlanExecutor> planIterator, final Object[] parameterValues) {
156 super(planIterator);
157 this.parameterValues = parameterValues;
158 selectNextPlan();
159 }
160
161 protected boolean initializeMatchingFrame(SearchPlanExecutor nextPlan) {
162 frame = new MatchingFrame(nextPlan.getVariableMapping().size());
163 parametersOfFrameView = new VolatileModifiableMaskedTuple(frame, nextPlan.getParameterMask());
164 for (int i = 0; i < parameterValues.length; i++) {
165 Object valueToSet = parameterValues[i];
166 if (valueToSet != null) {
167 Object oldValue = parametersOfFrameView.get(i);
168 if (oldValue == null) {
169 parametersOfFrameView.set(i, valueToSet);
170 } else if (!Objects.equals(valueToSet, oldValue)) {
171 // Initial value setting resulted in contradictory values. This can happen because two parameter
172 // variables have been unified but the call provides different values for the parameters.
173 return false;
174 }
175 // If oldValue is not null but equal to newValue, the setting can be ignored
176 }
177 }
178
179 return true;
180 }
181 }
182 private class PlanExecutionIteratorWithTupleParameters extends PlanExecutionIterator {
183
184 private final ITuple parameterValues;
185 private final TupleMask parameterSeedMask;
186
187 public PlanExecutionIteratorWithTupleParameters(Iterator<SearchPlanExecutor> planIterator, final TupleMask parameterSeedMask, final ITuple parameterValues) {
188 super(planIterator);
189 this.parameterSeedMask = parameterSeedMask;
190 this.parameterValues = parameterValues;
191 selectNextPlan();
192 }
193
194 protected boolean initializeMatchingFrame(SearchPlanExecutor nextPlan) {
195 frame = new MatchingFrame(nextPlan.getVariableMapping().size());
196 parametersOfFrameView = new VolatileModifiableMaskedTuple(frame, nextPlan.getParameterMask());
197 for (int i = 0; i < parameterSeedMask.getSize(); i++) {
198 int index = parameterSeedMask.indices[i];
199 Object valueToSet = parameterValues.get(i);
200 if (valueToSet != null) {
201 Object oldValue = parametersOfFrameView.get(index);
202 if (oldValue == null) {
203 parametersOfFrameView.set(index, valueToSet);
204 } else if (!Objects.equals(valueToSet, oldValue)) {
205 // Initial value setting resulted in contradictory values. This can happen because two parameter
206 // variables have been unified but the call provides different values for the parameters.
207 return false;
208 }
209 // If oldValue is not null but equal to newValue, the setting can be ignored
210 }
211 }
212
213 return true;
214 }
215 }
216
217 /**
218 * @since 2.0
219 */
220 public LocalSearchMatcher(ISearchContext searchContext, IPlanDescriptor planDescriptor, List<SearchPlan> plan) {
221 Preconditions.checkArgument(planDescriptor != null, "Cannot initialize matcher with null query.");
222 this.planDescriptor = planDescriptor;
223 this.plan = plan.stream().map(p -> new SearchPlanExecutor(p, searchContext)).collect(Collectors.toList());
224 this.adapters = new LinkedList<>();
225 }
226
227 @Override
228 public void addAdapter(ILocalSearchAdapter adapter) {
229 this.adapters.add(adapter);
230 adapter.adapterRegistered(this);
231 }
232
233 @Override
234 public void removeAdapter(ILocalSearchAdapter adapter) {
235 this.adapters.remove(adapter);
236 adapter.adapterUnregistered(this);
237 }
238
239 @Override
240 public void addAdapters(List<ILocalSearchAdapter> adapters) {
241 this.adapters.addAll(adapters);
242 for (ILocalSearchAdapter adapter : adapters) {
243 adapter.adapterRegistered(this);
244 }
245 }
246
247 @Override
248 public void removeAdapters(List<ILocalSearchAdapter> adapters) {
249 this.adapters.removeAll(adapters);
250 for (ILocalSearchAdapter adapter : adapters) {
251 adapter.adapterUnregistered(this);
252 }
253 }
254
255 public int getParameterCount() {
256 return planDescriptor.getQuery().getParameters().size();
257 }
258
259 private void matchingStarted() {
260 for (ILocalSearchAdapter adapter : adapters) {
261 adapter.patternMatchingStarted(this);
262 }
263 }
264
265 /**
266 * @since 2.0
267 */
268 public Stream<Tuple> streamMatches(final Object[] parameterValues) {
269 matchingStarted();
270 PlanExecutionIterator it = new PlanExecutionIteratorWithArrayParameters(plan.iterator(), parameterValues);
271 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it,
272 Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT), false);
273 }
274
275 /**
276 * @since 2.0
277 */
278 public Stream<Tuple> streamMatches(TupleMask parameterSeedMask, final ITuple parameterValues) {
279 matchingStarted();
280 PlanExecutionIterator it = new PlanExecutionIteratorWithTupleParameters(
281 plan.iterator(), parameterSeedMask, parameterValues);
282 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it,
283 Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT), false);
284 }
285
286 /**
287 * Returns the query specification this matcher used as source for the implementation
288 * @return never null
289 */
290 public PQuery getQuerySpecification() {
291 return planDescriptor.getQuery();
292 }
293
294
295 /**
296 * @since 1.5
297 */
298 public IPlanDescriptor getPlanDescriptor() {
299 return planDescriptor;
300 }
301}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/MatcherReference.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/MatcherReference.java
new file mode 100644
index 00000000..6bf25192
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/MatcherReference.java
@@ -0,0 +1,97 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Marton Bur, 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.localsearch.matcher;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
16
17public class MatcherReference {
18 final PQuery query;
19 final Set<PParameter> adornment;
20
21 /**
22 * Hints that can override the callee's own hints. This field is intentionally left out from hashCode and equals
23 */
24 final QueryEvaluationHint hints;
25
26 /**
27 * @since 1.4
28 */
29 public MatcherReference(PQuery query, Set<PParameter> adornment, QueryEvaluationHint hints) {
30 super();
31 this.query = query;
32 this.adornment = adornment;
33 this.hints = hints;
34 }
35
36 public MatcherReference(PQuery query, Set<PParameter> adornment){
37 this(query, adornment, null);
38 }
39
40 public PQuery getQuery() {
41 return query;
42 }
43 public Set<PParameter> getAdornment() {
44 return adornment;
45 }
46 @Override
47 public int hashCode() {
48 final int prime = 31;
49 int result = 1;
50
51 result = prime * result + ((adornment == null) ? 0 : adornment.hashCode());
52 result = prime * result + ((query == null) ? 0 : query.hashCode());
53 return result;
54 }
55 @Override
56 public boolean equals(Object obj) {
57 if (this == obj)
58 return true;
59 if (obj == null)
60 return false;
61 if (getClass() != obj.getClass())
62 return false;
63 MatcherReference other = (MatcherReference) obj;
64 if (adornment == null) {
65 if (other.adornment != null)
66 return false;
67 } else if (!adornment.equals(other.adornment))
68 return false;
69 if (query == null) {
70 if (other.query != null)
71 return false;
72 } else if (!query.equals(other.query))
73 return false;
74 return true;
75 }
76
77 /**
78 * @return the hints to override the called reference's own hints with. Can be null.
79 * @since 1.4
80 */
81 public QueryEvaluationHint getHints() {
82 return hints;
83 }
84
85 @Override
86 public String toString() {
87 StringBuilder sb = new StringBuilder();
88 sb.append(query.getFullyQualifiedName());
89 sb.append("(");
90 for(PParameter p : query.getParameters()){
91 sb.append(adornment.contains(p) ? "b" : "f");
92 }
93 sb.append(")");
94 return sb.toString();
95 }
96
97} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java
new file mode 100644
index 00000000..1ae24d2d
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java
@@ -0,0 +1,532 @@
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.matcher.integration;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.LinkedHashSet;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Map;
21import java.util.Objects;
22import java.util.Optional;
23import java.util.Queue;
24import java.util.Set;
25import java.util.concurrent.Callable;
26import java.util.stream.Collectors;
27import java.util.stream.IntStream;
28import java.util.stream.Stream;
29
30import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
31import tools.refinery.viatra.runtime.localsearch.matcher.CallWithAdornment;
32import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
33import tools.refinery.viatra.runtime.localsearch.matcher.LocalSearchMatcher;
34import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
35import tools.refinery.viatra.runtime.localsearch.plan.IPlanDescriptor;
36import tools.refinery.viatra.runtime.localsearch.plan.IPlanProvider;
37import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
38import tools.refinery.viatra.runtime.localsearch.plan.SearchPlanForBody;
39import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
40import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
41import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
42import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
43import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
44import tools.refinery.viatra.runtime.matchers.backend.IUpdateable;
45import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
46import tools.refinery.viatra.runtime.matchers.backend.QueryHintOption;
47import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
48import tools.refinery.viatra.runtime.matchers.context.IInputKey;
49import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
50import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
51import tools.refinery.viatra.runtime.matchers.context.IndexingService;
52import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
53import tools.refinery.viatra.runtime.matchers.planning.helpers.FunctionalDependencyHelper;
54import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
55import tools.refinery.viatra.runtime.matchers.psystem.PBody;
56import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
57import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
58import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueries;
59import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
60import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
61import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
62import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
63import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
64import tools.refinery.viatra.runtime.matchers.util.Accuracy;
65
66/**
67 * @author Zoltan Ujhelyi
68 * @since 1.7
69 *
70 */
71public abstract class AbstractLocalSearchResultProvider implements IQueryResultProvider {
72
73 protected final LocalSearchBackend backend;
74 protected final IQueryBackendContext backendContext;
75 protected final IQueryRuntimeContext runtimeContext;
76 protected final PQuery query;
77 protected final QueryEvaluationHint userHints;
78 protected final Map<PQuery, LocalSearchHints> hintCache = new HashMap<>();
79 protected final IPlanProvider planProvider;
80 private static final String PLAN_CACHE_KEY = AbstractLocalSearchResultProvider.class.getName() + "#planCache";
81 private final Map<MatcherReference, IPlanDescriptor> planCache;
82 protected final ISearchContext searchContext;
83 /**
84 * @since 2.1
85 */
86 protected ResultProviderRequestor resultProviderRequestor;
87
88 /**
89 * @since 1.5
90 */
91 @SuppressWarnings({ "unchecked"})
92 public AbstractLocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query,
93 IPlanProvider planProvider, QueryEvaluationHint userHints) {
94 this.backend = backend;
95 this.backendContext = context;
96 this.query = query;
97
98 this.planProvider = planProvider;
99 this.userHints = userHints;
100 this.runtimeContext = context.getRuntimeContext();
101 this.resultProviderRequestor = backend.getResultProviderRequestor(query, userHints);
102 this.searchContext = new ISearchContext.SearchContext(backendContext, backend.getCache(), resultProviderRequestor);
103 this.planCache = backend.getCache().getValue(PLAN_CACHE_KEY, Map.class, HashMap::new);
104 }
105
106 protected abstract IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext, LocalSearchHints configuration);
107
108 private IQueryRuntimeContext getRuntimeContext() {
109 return backend.getRuntimeContext();
110 }
111
112 private LocalSearchMatcher createMatcher(IPlanDescriptor plan, final ISearchContext searchContext) {
113 List<SearchPlan> executors = plan.getPlan().stream()
114 .map(input -> new SearchPlan(input.getBody(), input.getCompiledOperations(), input.calculateParameterMask(),
115 input.getVariableKeys()))
116 .collect(Collectors.toList());
117 return new LocalSearchMatcher(searchContext, plan, executors);
118 }
119
120 private IPlanDescriptor getOrCreatePlan(MatcherReference key, IQueryBackendContext backendContext, IOperationCompiler compiler, LocalSearchHints configuration, IPlanProvider planProvider) {
121 if (planCache.containsKey(key)){
122 return planCache.get(key);
123 } else {
124 IPlanDescriptor plan = planProvider.getPlan(backendContext, compiler,
125 resultProviderRequestor, configuration, key);
126 planCache.put(key, plan);
127 return plan;
128 }
129 }
130
131 private IPlanDescriptor getOrCreatePlan(MatcherReference key, IPlanProvider planProvider) {
132 if (planCache.containsKey(key)){
133 return planCache.get(key);
134 } else {
135 LocalSearchHints configuration = overrideDefaultHints(key.getQuery());
136 IOperationCompiler compiler = getOperationCompiler(backendContext, configuration);
137 IPlanDescriptor plan = planProvider.getPlan(backendContext, compiler,
138 resultProviderRequestor, configuration, key);
139 planCache.put(key, plan);
140 return plan;
141 }
142 }
143
144 private LocalSearchHints overrideDefaultHints(PQuery pQuery) {
145 if (hintCache.containsKey(pQuery)) {
146 return hintCache.get(pQuery);
147 } else {
148 LocalSearchHints hint = LocalSearchHints.getDefaultOverriddenBy(
149 computeOverridingHints(pQuery));
150 hintCache.put(pQuery, hint);
151 return hint;
152 }
153 }
154
155 /**
156 * Combine with {@link QueryHintOption#getValueOrDefault(QueryEvaluationHint)} to access
157 * hint settings not covered by {@link LocalSearchHints}
158 */
159 private QueryEvaluationHint computeOverridingHints(PQuery pQuery) {
160 return backendContext.getHintProvider().getQueryEvaluationHint(pQuery).overrideBy(userHints);
161 }
162
163 /**
164 * Prepare this result provider. This phase is separated from the constructor to allow the backend to cache its instance before
165 * requesting preparation for its dependencies.
166 * @since 1.5
167 */
168 public void prepare() {
169 try {
170 runtimeContext.coalesceTraversals(() -> {
171 LocalSearchHints configuration = overrideDefaultHints(query);
172 if (configuration.isUseBase()) {
173 indexInitializationBeforePlanning();
174 }
175 prepareDirectDependencies();
176 runtimeContext.executeAfterTraversal(AbstractLocalSearchResultProvider.this::preparePlansForExpectedAdornments);
177 return null;
178 });
179 } catch (InvocationTargetException e) {
180 throw new QueryProcessingException("Error while building required indexes: {1}", new String[]{e.getTargetException().getMessage()}, "Error while building required indexes.", query, e);
181 }
182 }
183
184 protected void preparePlansForExpectedAdornments() {
185 // Plan for possible adornments
186 for (Set<PParameter> adornment : overrideDefaultHints(query).getAdornmentProvider().getAdornments(query)) {
187 MatcherReference reference = new MatcherReference(query, adornment, userHints);
188 LocalSearchHints configuration = overrideDefaultHints(query);
189 IOperationCompiler compiler = getOperationCompiler(backendContext, configuration);
190 IPlanDescriptor plan = getOrCreatePlan(reference, backendContext, compiler, configuration, planProvider);
191 // Index keys
192 try {
193 if (configuration.isUseBase()) {
194 indexKeys(plan.getIteratedKeys());
195 }
196 } catch (InvocationTargetException e) {
197 throw new QueryProcessingException(e.getMessage(), null, e.getMessage(), query, e);
198 }
199 //Prepare dependencies
200 for(SearchPlanForBody body: plan.getPlan()){
201 for(CallWithAdornment dependency : body.getDependencies()){
202 searchContext.getMatcher(dependency);
203 }
204 }
205 }
206 }
207
208 protected void prepareDirectDependencies() {
209 // Do not prepare for any adornment at this point
210 IAdornmentProvider adornmentProvider = input -> Collections.emptySet();
211 QueryEvaluationHint adornmentHint = IAdornmentProvider.toHint(adornmentProvider);
212
213 for(IQueryReference call : getDirectDependencies()){
214 resultProviderRequestor.requestResultProvider(call, adornmentHint);
215 }
216 }
217
218 /**
219 * This method is called before planning start to allow indexing. It is important to note that this method is called
220 * inside a coalesceTraversals block, meaning (1) it is safe to add multiple registration requests as necessary, but
221 * (2) no value or statistics is available from the index.
222 *
223 * @throws ViatraQueryRuntimeException
224 */
225 protected void indexInitializationBeforePlanning() {
226 // By default, no indexing is necessary
227 }
228
229 /**
230 * Collects and indexes all types _directly_ referred by the PQuery {@link #query}. Types indirect
231 * @param requiredIndexingServices
232 */
233 protected void indexReferredTypesOfQuery(PQuery query, IndexingService requiredIndexingServices) {
234 PQueries.directlyRequiredTypesOfQuery(query, true /*only enumerables are considered for indexing */).forEach(
235 inputKey -> runtimeContext.ensureIndexed(inputKey, requiredIndexingServices)
236 );
237 }
238
239 private Set<IQueryReference> getDirectDependencies() {
240 IFlattenCallPredicate flattenPredicate = overrideDefaultHints(query).getFlattenCallPredicate();
241 Queue<PQuery> queue = new LinkedList<>();
242 Set<PQuery> visited = new HashSet<>();
243 Set<IQueryReference> result = new HashSet<>();
244 queue.add(query);
245
246 while(!queue.isEmpty()){
247 PQuery next = queue.poll();
248 visited.add(next);
249 for(PBody body : next.getDisjunctBodies().getBodies()){
250 for (IQueryReference call : body.getConstraintsOfType(IQueryReference.class)) {
251 if (call instanceof PositivePatternCall &&
252 flattenPredicate.shouldFlatten((PositivePatternCall) call))
253 {
254 PQuery dep = ((PositivePatternCall) call).getReferredQuery();
255 if (!visited.contains(dep)){
256 queue.add(dep);
257 }
258 } else {
259 result.add(call);
260 }
261 }
262 }
263 }
264 return result;
265 }
266
267 private LocalSearchMatcher initializeMatcher(Object[] parameters) {
268 return newLocalSearchMatcher(parameters);
269 }
270
271 private LocalSearchMatcher initializeMatcher(TupleMask parameterSeedMask) {
272 return newLocalSearchMatcher(parameterSeedMask.transformUnique(query.getParameters()));
273
274 }
275
276
277 /**
278 * @throws ViatraQueryRuntimeException
279 */
280 public LocalSearchMatcher newLocalSearchMatcher(ITuple parameters) {
281 final Set<PParameter> adornment = new HashSet<>();
282 for (int i = 0; i < parameters.getSize(); i++) {
283 if (parameters.get(i) != null) {
284 adornment.add(query.getParameters().get(i));
285 }
286 }
287
288 return newLocalSearchMatcher(adornment);
289 }
290
291 /**
292 * @throws ViatraQueryRuntimeException
293 */
294 public LocalSearchMatcher newLocalSearchMatcher(Object[] parameters) {
295 final Set<PParameter> adornment = new HashSet<>();
296 for (int i = 0; i < parameters.length; i++) {
297 if (parameters[i] != null) {
298 adornment.add(query.getParameters().get(i));
299 }
300 }
301
302 return newLocalSearchMatcher(adornment);
303 }
304
305 private LocalSearchMatcher newLocalSearchMatcher(final Set<PParameter> adornment) {
306 final MatcherReference reference = new MatcherReference(query, adornment, userHints);
307
308 IPlanDescriptor plan = getOrCreatePlan(reference, planProvider);
309 if (overrideDefaultHints(reference.getQuery()).isUseBase()){
310 try {
311 indexKeys(plan.getIteratedKeys());
312 } catch (InvocationTargetException e) {
313 throw new LocalSearchException("Could not index keys", e);
314 }
315 }
316
317 LocalSearchMatcher matcher = createMatcher(plan, searchContext);
318 matcher.addAdapters(backend.getAdapters());
319 return matcher;
320 }
321
322 private void indexKeys(final Iterable<IInputKey> keys) throws InvocationTargetException {
323 final IQueryRuntimeContext qrc = getRuntimeContext();
324 qrc.coalesceTraversals(new Callable<Void>() {
325
326 @Override
327 public Void call() throws Exception {
328 for(IInputKey key : keys){
329 if (key.isEnumerable()) {
330 qrc.ensureIndexed(key, IndexingService.INSTANCES);
331 }
332 }
333 return null;
334 }
335 });
336 }
337
338 @Override
339 public boolean hasMatch(Object[] parameters) {
340 final LocalSearchMatcher matcher = initializeMatcher(parameters);
341 return matcher.streamMatches(parameters).findAny().isPresent();
342 }
343
344 @Override
345 public boolean hasMatch(TupleMask parameterSeedMask, ITuple parameters) {
346 final LocalSearchMatcher matcher = initializeMatcher(parameterSeedMask);
347 return matcher.streamMatches(parameterSeedMask, parameters).findAny().isPresent();
348 }
349
350 @Override
351 public Optional<Tuple> getOneArbitraryMatch(Object[] parameters) {
352 final LocalSearchMatcher matcher = initializeMatcher(parameters);
353 return matcher.streamMatches(parameters).findAny();
354 }
355
356 @Override
357 public Optional<Tuple> getOneArbitraryMatch(TupleMask parameterSeedMask, ITuple parameters) {
358 final LocalSearchMatcher matcher = initializeMatcher(parameterSeedMask);
359 return matcher.streamMatches(parameterSeedMask, parameters).findAny();
360 }
361
362 @Override
363 public int countMatches(Object[] parameters) {
364 final LocalSearchMatcher matcher = initializeMatcher(parameters);
365 // Count returns long; casting to int - in case of integer overflow casting will throw the exception
366 return (int) matcher.streamMatches(parameters).count();
367 }
368
369 @Override
370 public int countMatches(TupleMask parameterSeedMask, ITuple parameters) {
371 final LocalSearchMatcher matcher = initializeMatcher(parameterSeedMask);
372 // Count returns long; casting to int - in case of integer overflow casting will throw the exception
373 return (int) matcher.streamMatches(parameterSeedMask, parameters).count();
374 }
375
376 private static final double ESTIMATE_CEILING = Long.MAX_VALUE / 16.0;
377
378 @Override
379 public Optional<Long> estimateCardinality(TupleMask groupMask, Accuracy requiredAccuracy) {
380 if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) { // approximate using parameter types
381 final List<PParameter> parameters = query.getParameters();
382 final Map<Set<Integer>, Set<Integer>> dependencies = backendContext.getQueryAnalyzer()
383 .getProjectedFunctionalDependencies(query, false);
384
385 List<Integer> projectionIndices = groupMask.getIndicesAsList();
386
387 return estimateParameterCombinations(requiredAccuracy, parameters, dependencies,
388 projectionIndices,
389 Collections.emptySet() /* No parameters with fixed value */).map(Double::longValue);
390 }
391 else return Optional.empty();
392 }
393
394 @Override
395 public Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy) {
396 if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) { // approximate using parameter types
397 final List<PParameter> parameters = query.getParameters();
398 final Map<Set<Integer>, Set<Integer>> dependencies = backendContext.getQueryAnalyzer()
399 .getProjectedFunctionalDependencies(query, false);
400
401 // all parameters used for the estimation - determinized order
402 final List<Integer> allParameterIndices =
403 IntStream.range(0, parameters.size()).boxed().collect(Collectors.toList());
404
405 // some free parameters are functionally determined by bound parameters
406 final Set<Integer> boundOrImplied = FunctionalDependencyHelper.closureOf(groupMask.getIndicesAsList(),
407 dependencies);
408
409 return estimateParameterCombinations(requiredAccuracy, parameters, dependencies,
410 allParameterIndices,
411 boundOrImplied);
412 }
413 else return Optional.empty();
414 }
415
416 /**
417 * @since 2.1
418 * @noreference This method is not intended to be referenced by clients.
419 */
420 public double estimateCost(TupleMask inputBindingMask) {
421 // TODO this is currently an abstract cost, not really a branching factor
422
423 HashSet<PParameter> adornment = new HashSet<>(inputBindingMask.transform(query.getParameters()));
424 final MatcherReference reference = new MatcherReference(query, adornment, userHints);
425 IPlanDescriptor plan = getOrCreatePlan(reference, planProvider);
426
427 return plan.getPlan().stream().mapToDouble(SearchPlanForBody::getCost).sum();
428 }
429
430 /**
431 * Approximates using parameter types
432 */
433 private Optional<Double> estimateParameterCombinations(
434 Accuracy requiredAccuracy,
435 final List<PParameter> parameters,
436 final Map<Set<Integer>, Set<Integer>> functionalDependencies,
437 final Collection<Integer> parameterIndicesToEstimate,
438 final Set<Integer> otherDeterminingIndices)
439 {
440 // keep order deterministic
441 LinkedHashSet<Integer> freeParameterIndices = new LinkedHashSet<>(parameterIndicesToEstimate);
442
443 // determining indices are bound
444 freeParameterIndices.removeAll(otherDeterminingIndices);
445
446 // some free parameters are functionally determined by other free parameters
447 for (Integer candidateForRemoval : new ArrayList<>(freeParameterIndices)) {
448 List<Integer> others = Stream.concat(
449 otherDeterminingIndices.stream(),
450 freeParameterIndices.stream().filter(index -> !Objects.equals(index, candidateForRemoval))
451 ).collect(Collectors.toList());
452 Set<Integer> othersClosure = FunctionalDependencyHelper.closureOf(others, functionalDependencies);
453 if (othersClosure.contains(candidateForRemoval)) {
454 // other parameters functionally determine this mone, does not count towards estimate
455 freeParameterIndices.remove(candidateForRemoval);
456 }
457 }
458
459
460 Optional<Double> result = Optional.of(1.0);
461 // TODO this is currently works with declared types only. For better results, information from
462 // the Type inferrer should be included in the PSystem
463 for (int i = 0; (i < parameters.size()); i++) {
464 final IInputKey type = parameters.get(i).getDeclaredUnaryType();
465 if (freeParameterIndices.contains(i) && type != null) {
466 result = result.flatMap(accumulator ->
467 runtimeContext.estimateCardinality(type, TupleMask.identity(1), requiredAccuracy).map(multiplier ->
468 Math.min(accumulator * multiplier, ESTIMATE_CEILING /* avoid overflow */)
469 ));
470 }
471 }
472 // TODO better approximate cardinality based on plan, branching factors, etc.
473 return result;
474 }
475
476
477 @Override
478 public Stream<Tuple> getAllMatches(Object[] parameters) {
479 final LocalSearchMatcher matcher = initializeMatcher(parameters);
480 return matcher.streamMatches(parameters);
481 }
482
483 @Override
484 public Stream<Tuple> getAllMatches(TupleMask parameterSeedMask, ITuple parameters) {
485 final LocalSearchMatcher matcher = initializeMatcher(parameterSeedMask);
486 return matcher.streamMatches(parameterSeedMask, parameters);
487 }
488
489 @Override
490 public IQueryBackend getQueryBackend() {
491 return backend;
492 }
493
494 @Override
495 public void addUpdateListener(IUpdateable listener, Object listenerTag, boolean fireNow) {
496 // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED);
497 }
498
499 @Override
500 public void removeUpdateListener(Object listenerTag) {
501 // throw new UnsupportedOperationException(UPDATE_LISTENER_NOT_SUPPORTED);
502 }
503
504 /**
505 * @since 1.4
506 */
507 public IMatcherCapability getCapabilites() {
508 LocalSearchHints configuration = overrideDefaultHints(query);
509 return configuration;
510 }
511
512 /**
513 * Forgets all stored plans in this result provider. If no plans are stored, nothing happens.
514 *
515 * @since 2.0
516 * @noreference This method is not intended to be referenced by clients; it should only used by {@link LocalSearchBackend}.
517 */
518 public void forgetAllPlans() {
519 planCache.clear();
520 }
521
522 /**
523 * Returns a search plan for a given adornment if exists
524 *
525 * @return a search plan for the pattern with the given adornment, or null if none exists
526 * @since 2.0
527 * @noreference This method is not intended to be referenced by clients; it should only used by {@link LocalSearchBackend}.
528 */
529 public IPlanDescriptor getSearchPlan(Set<PParameter> adornment) {
530 return planCache.get(new MatcherReference(query, adornment));
531 }
532} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AllValidAdornments.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AllValidAdornments.java
new file mode 100644
index 00000000..f801163e
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/AllValidAdornments.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs 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.matcher.integration;
10
11import java.util.Set;
12import java.util.stream.Collectors;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameterDirection;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueries;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18import tools.refinery.viatra.runtime.matchers.util.Sets;
19
20
21/**
22 * This implementation calculates all valid adornments for the given query, respecting the parameter direction constraints.
23 *
24 * @author Grill Balázs
25 * @since 1.5
26 */
27public class AllValidAdornments implements IAdornmentProvider {
28
29 @Override
30 public Iterable<Set<PParameter>> getAdornments(PQuery query) {
31 final Set<PParameter> ins = query.getParameters().stream().filter(PQueries.parameterDirectionPredicate(PParameterDirection.IN)).collect(Collectors.toSet());
32 Set<PParameter> inouts = query.getParameters().stream().filter(PQueries.parameterDirectionPredicate(PParameterDirection.INOUT)).collect(Collectors.toSet());
33 Set<? extends Set<PParameter>> possibleInouts = Sets.powerSet(inouts);
34 return possibleInouts.stream().map(input -> Sets.union(ins, input)).collect(Collectors.toSet());
35 }
36
37}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenDisjunctive.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenDisjunctive.java
new file mode 100644
index 00000000..bf1b61b5
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenDisjunctive.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, 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.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
12import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
13
14/**
15 * Forbids flattening of patterns that have more than one body.
16 *
17 * @since 2.1
18
19 * @author Gabor Bergmann
20 *
21 */
22public class DontFlattenDisjunctive implements IFlattenCallPredicate {
23
24 @Override
25 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
26 return 1 >= positivePatternCall.getReferredQuery().getDisjunctBodies().getBodies().size();
27 }
28
29}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenIncrementalPredicate.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenIncrementalPredicate.java
new file mode 100644
index 00000000..1b918528
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/DontFlattenIncrementalPredicate.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs 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.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
12import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint.BackendRequirement;
13import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
14import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
15
16/**
17 * This implementation forbids flattening of patterns marked to be executed with a caching / incremental backend.
18 * This makes is possible for the user to configure hybrid matching via using
19 * the 'search' and 'incremental keywords in the pattern definition file.
20 *
21 * @since 1.5
22 *
23 */
24public class DontFlattenIncrementalPredicate implements IFlattenCallPredicate {
25
26 @Override
27 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
28 QueryEvaluationHint evaluationHints = positivePatternCall.getReferredQuery().getEvaluationHints();
29 if (evaluationHints == null) return true;
30
31 BackendRequirement backendRequirementType = evaluationHints.getQueryBackendRequirementType();
32 switch(backendRequirementType) {
33 case DEFAULT_CACHING:
34 return false;
35 case SPECIFIC:
36 return !evaluationHints.getQueryBackendFactory().isCaching();
37 case UNSPECIFIED:
38 case DEFAULT_SEARCH:
39 default:
40 return true;
41 }
42 }
43
44}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java
new file mode 100644
index 00000000..ed6c1e5f
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/GenericLocalSearchResultProvider.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, 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.localsearch.matcher.integration;
10
11import tools.refinery.viatra.runtime.localsearch.plan.IPlanProvider;
12import tools.refinery.viatra.runtime.localsearch.planner.compiler.GenericOperationCompiler;
13import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
16import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
17import tools.refinery.viatra.runtime.matchers.context.IndexingService;
18import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
19
20/**
21 * @author Zoltan Ujhelyi
22 * @since 1.7
23 *
24 */
25public class GenericLocalSearchResultProvider extends AbstractLocalSearchResultProvider {
26
27 /**
28 * @throws ViatraQueryRuntimeException
29 */
30 public GenericLocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query,
31 IPlanProvider planProvider, QueryEvaluationHint userHints) {
32 super(backend, context, query, planProvider, userHints);
33 }
34
35 @Override
36 protected void indexInitializationBeforePlanning() {
37 super.indexInitializationBeforePlanning();
38
39 indexReferredTypesOfQuery(query, IndexingService.INSTANCES);
40 indexReferredTypesOfQuery(query, IndexingService.STATISTICS);
41 }
42
43 @Override
44 protected IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext,
45 LocalSearchHints configuration) {
46 return new GenericOperationCompiler(runtimeContext);
47 }
48
49}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/IAdornmentProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/IAdornmentProvider.java
new file mode 100644
index 00000000..86058be0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/IAdornmentProvider.java
@@ -0,0 +1,72 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs 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.matcher.integration;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
15import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint.BackendRequirement;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18
19/**
20 * An adornment provider is used to define the adornments the pattern matcher should prepare for.
21 *
22 * <p>A default implementation is available in {@link AllValidAdornments} that describes all
23 * adornments fulfilling the parameter direction declarations;
24 * another default option (with better performance but restricted applicability) is {@link LazyPlanningAdornments}.
25 *
26 * <br><br>
27 *
28 * Users may implement this interface to limit the number of prepared plans based on some runtime information:
29 *
30 * <pre>
31 * class SomeAdornments{
32 *
33 * public Iterable&lt;Set&lt;{@link PParameter}>> getAdornments({@link PQuery} query){
34 * if (SomeGeneratedQuerySpecification.instance().getInternalQueryRepresentation().equals(query)){
35 * return Collections.singleton(Sets.filter(Sets.newHashSet(query.getParameters()), new Predicate<PParameter>() {
36 *
37 * &#64;Override
38 * public boolean apply(PParameter input) {
39 * // Decide whether this particular parameter will be bound
40 * return false;
41 * }
42 * }));
43 * }
44 * // Returning an empty iterable is safe for unknown queries
45 * return Collections.emptySet();
46 * }
47 *
48 * }
49 * </pre>
50 *
51 * @author Grill Balázs
52 * @since 1.5
53 *
54 */
55public interface IAdornmentProvider {
56
57 /**
58 * The bound parameter sets
59 */
60 public Iterable<Set<PParameter>> getAdornments(PQuery query);
61
62 /**
63 * @return a simple hint that only overrides the adornment provider
64 * @since 2.1
65 */
66 public static QueryEvaluationHint toHint(IAdornmentProvider adornmentProvider) {
67 return new QueryEvaluationHint(
68 Collections.singletonMap(LocalSearchHintOptions.ADORNMENT_PROVIDER, adornmentProvider),
69 BackendRequirement.UNSPECIFIED);
70 }
71
72}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LazyPlanningAdornments.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LazyPlanningAdornments.java
new file mode 100644
index 00000000..30b3689f
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LazyPlanningAdornments.java
@@ -0,0 +1,41 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, 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.matcher.integration;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
16
17/**
18 * This adornment provider does not trigger the preparation of any plans.
19 * Actual query plans will be computed on demand, when the first actual match request is made with a given adornment.
20 *
21 * <p> Caution: this is a safe default adornment provider for {@link GenericLocalSearchResultProvider} only;
22 * do not use for the EMF-specific LS backend.
23 *
24 * <p> The benefits is in execution time: query planning costs for adornments are postponed until first usage
25 * or even entirely avoided (when adornment is never used in practice).
26 * However, query evaluation time may become less predictable, as the first matcher call (with a given adornment)
27 * will include the planning cost.
28 * For benchmarking or other purposes where this is not desirable, use an adornment provider that demands plan precomputation for all necessary adornments.
29 *
30 * @author Gabor Bergmann
31 * @since 2.1
32 *
33 */
34public class LazyPlanningAdornments implements IAdornmentProvider {
35
36 @Override
37 public Iterable<Set<PParameter>> getAdornments(PQuery query) {
38 return Collections.emptySet();
39 }
40
41}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackend.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackend.java
new file mode 100644
index 00000000..ae51e2b0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackend.java
@@ -0,0 +1,259 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, 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.localsearch.matcher.integration;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.HashSet;
17import java.util.List;
18import java.util.Map;
19import java.util.Set;
20import java.util.stream.Stream;
21
22import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
23import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter;
24import tools.refinery.viatra.runtime.localsearch.plan.IPlanDescriptor;
25import tools.refinery.viatra.runtime.localsearch.plan.IPlanProvider;
26import tools.refinery.viatra.runtime.localsearch.plan.SimplePlanProvider;
27import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
28import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
29import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
30import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
31import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
32import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
33import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
34import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
35import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
36import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
37import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
38import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
39import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
40import tools.refinery.viatra.runtime.matchers.util.ICache;
41import tools.refinery.viatra.runtime.matchers.util.PurgableCache;
42
43/**
44 * @author Marton Bur, Zoltan Ujhelyi
45 * @noextend This class is not intended to be subclassed by clients.
46 */
47public abstract class LocalSearchBackend implements IQueryBackend {
48
49 IQueryBackendContext context;
50 IPlanProvider planProvider;
51 private final Set<ILocalSearchAdapter> adapters = new HashSet<>();
52
53 private final PurgableCache generalCache;
54
55 private final Map<PQuery, List<AbstractLocalSearchResultProvider>> resultProviderCache = CollectionsFactory.createMap();
56
57
58 /**
59 * @since 1.5
60 */
61 public LocalSearchBackend(IQueryBackendContext context) {
62 super();
63 this.context = context;
64 this.generalCache = new PurgableCache();
65 this.planProvider = new SimplePlanProvider(context.getLogger());
66 }
67
68 @Override
69 public void flushUpdates() {
70
71 }
72
73 @Override
74 public IQueryResultProvider getResultProvider(PQuery query) {
75 return getResultProvider(query, null);
76 }
77
78 /**
79 * @since 1.4
80 */
81 @Override
82 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint hints) {
83
84 final QueryEvaluationHint callHints = getHintProvider().getQueryEvaluationHint(query).overrideBy(hints);
85 IMatcherCapability requestedCapability = context.getRequiredMatcherCapability(query, callHints);
86 for(AbstractLocalSearchResultProvider existingResultProvider : resultProviderCache.getOrDefault(query, Collections.emptyList())){
87 if (requestedCapability.canBeSubstitute(existingResultProvider.getCapabilites())){
88 return existingResultProvider;
89 }
90 }
91
92 AbstractLocalSearchResultProvider resultProvider = initializeResultProvider(query, hints);
93 resultProviderCache.computeIfAbsent(query, k->new ArrayList<>()).add(resultProvider);
94 resultProvider.prepare();
95 return resultProvider;
96 }
97
98 /**
99 * Returns a requestor that this backend uses while processing pattern calls <i>from</i> this query.
100 * @noreference This method is not intended to be referenced by clients.
101 * @since 2.1
102 */
103 public ResultProviderRequestor getResultProviderRequestor(PQuery query, QueryEvaluationHint userHints) {
104 QueryEvaluationHint hintOnQuery =
105 context.getHintProvider().getQueryEvaluationHint(query).overrideBy(userHints);
106 LocalSearchHints defaultsApplied = LocalSearchHints.getDefaultOverriddenBy(hintOnQuery);
107
108 return new ResultProviderRequestor(this,
109 context.getResultProviderAccess(),
110 context.getHintProvider(),
111 defaultsApplied.getCallDelegationStrategy(),
112 userHints,
113 /* no global overrides */ null);
114 }
115
116 /**
117 * @throws ViatraQueryRuntimeException
118 * @since 1.7
119 */
120 protected abstract AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints);
121
122 @Override
123 public void dispose() {
124 resultProviderCache.clear();
125 generalCache.purge();
126 }
127
128 @Override
129 public boolean isCaching() {
130 return false;
131 }
132
133 /**
134 * @since 2.0
135 */
136 @Override
137 public AbstractLocalSearchResultProvider peekExistingResultProvider(PQuery query) {
138 return resultProviderCache.getOrDefault(query, Collections.emptyList()).stream().findAny().orElse(null);
139 }
140
141 /**
142 * @since 1.4
143 */
144 public IQueryRuntimeContext getRuntimeContext() {
145 return context.getRuntimeContext();
146 }
147
148
149 /**
150 * @since 1.5
151 */
152 public QueryAnalyzer getQueryAnalyzer() {
153 return context.getQueryAnalyzer();
154 }
155
156
157 /**
158 * @since 1.4
159 */
160 public IQueryBackendHintProvider getHintProvider() {
161 return context.getHintProvider();
162 }
163
164 /**
165 * @since 1.5
166 */
167 public void addAdapter(ILocalSearchAdapter adapter){
168 adapters.add(adapter);
169 }
170
171 /**
172 * @since 1.5
173 */
174 public void removeAdapter(ILocalSearchAdapter adapter){
175 adapters.remove(adapter);
176 }
177
178 /**
179 * Return a copy of the current adapters
180 * @since 1.7
181 */
182 public List<ILocalSearchAdapter> getAdapters() {
183 return new ArrayList<>(adapters);
184 }
185
186 /**
187 * @since 1.5
188 */
189 public IQueryBackendContext getBackendContext() {
190 return context;
191 }
192
193 /**
194 * Returns the internal cache of the backend
195 * @since 1.7
196 * @noreference This method is not intended to be referenced by clients.
197 */
198 public ICache getCache() {
199 return generalCache;
200 }
201
202 /**
203 * Updates the previously stored search plans for one or more given queries, computing a new set of plans if
204 * necessary. The new plans created are the same that would be created by executing prepare on the given query
205 * definitions.
206 *
207 * @since 2.0
208 */
209 public void recomputePlans(PQuery... queries) {
210 recomputePlans(Arrays.stream(queries).flatMap(query -> resultProviderCache.getOrDefault(query, Collections.emptyList()).stream()));
211 }
212
213 /**
214 * Updates the previously stored search plans for one or more given queries, computing a new set of plans if
215 * necessary The new plans created are the same that would be created by executing prepare on the given query
216 * definitions.
217 *
218 * @since 2.0
219 */
220 public void recomputePlans(Collection<PQuery> queries) {
221 recomputePlans(queries.stream().flatMap(query -> resultProviderCache.getOrDefault(query, Collections.emptyList()).stream()));
222 }
223
224 /**
225 * Updates the previously stored search plans for one or more given queries, computing a new set of plans if
226 * necessary The new plans created are the same that would be created by executing prepare on the given query
227 * definitions.
228 *
229 * @since 2.0
230 */
231 public void recomputePlans() {
232 recomputePlans(resultProviderCache.values().stream().flatMap(List::stream));
233 }
234
235 private void recomputePlans(Stream<AbstractLocalSearchResultProvider> resultProviders) {
236 try {
237 context.getRuntimeContext().coalesceTraversals(() -> {
238 resultProviders.forEach(resultProvider -> {
239 resultProvider.forgetAllPlans();
240 resultProvider.prepare();
241 });
242 return null;
243 });
244 } catch (InvocationTargetException e) {
245 throw new LocalSearchException("Error while rebuilding plans: " + e.getMessage(), e);
246 }
247 }
248
249 /**
250 * Returns a search plan for a given query and adornment if such plan is already calculated.
251 *
252 * @return a previously calculated search plan for the given query and adornment, or null if no such plan exists
253 * @since 2.0
254 */
255 public IPlanDescriptor getSearchPlan(PQuery query, Set<PParameter> adornment) {
256 final AbstractLocalSearchResultProvider resultProvider = peekExistingResultProvider(query);
257 return (resultProvider == null) ? null : resultProvider.getSearchPlan(adornment);
258 }
259}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java
new file mode 100644
index 00000000..1dd08f98
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactory.java
@@ -0,0 +1,65 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, 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.localsearch.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
14import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
15import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * @author Marton Bur, Zoltan Ujhelyi
20 * @since 1.7
21 *
22 */
23public enum LocalSearchGenericBackendFactory implements IQueryBackendFactory {
24
25 INSTANCE;
26
27 /**
28 * @since 1.5
29 */
30 @Override
31 public IQueryBackend create(IQueryBackendContext context) {
32 return new LocalSearchBackend(context) {
33
34 @Override
35 protected AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints) {
36 return new GenericLocalSearchResultProvider(this, context, query, planProvider, hints);
37 }
38
39 @Override
40 public IQueryBackendFactory getFactory() {
41 return INSTANCE;
42 }
43
44 };
45 }
46
47 @Override
48 public Class<? extends IQueryBackend> getBackendClass() {
49 return LocalSearchBackend.class;
50 }
51
52 /**
53 * @since 1.4
54 */
55 @Override
56 public IMatcherCapability calculateRequiredCapability(PQuery query, QueryEvaluationHint hint) {
57 return LocalSearchHints.parse(hint);
58 }
59
60 @Override
61 public boolean isCaching() {
62 return false;
63 }
64
65}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactoryProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactoryProvider.java
new file mode 100644
index 00000000..ea422d91
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchGenericBackendFactoryProvider.java
@@ -0,0 +1,24 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, 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.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactoryProvider;
13
14/**
15 * @since 2.0
16 */
17public class LocalSearchGenericBackendFactoryProvider implements IQueryBackendFactoryProvider {
18
19 @Override
20 public IQueryBackendFactory getFactory() {
21 return LocalSearchGenericBackendFactory.INSTANCE;
22 }
23
24} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHintOptions.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHintOptions.java
new file mode 100644
index 00000000..43462204
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHintOptions.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs 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.matcher.integration;
10
11import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
12import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.IndexerBasedConstraintCostFunction;
13import tools.refinery.viatra.runtime.matchers.backend.ICallDelegationStrategy;
14import tools.refinery.viatra.runtime.matchers.backend.QueryHintOption;
15import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
16
17/**
18 *
19 * @author Gabor Bergmann
20 * @since 1.5
21 * @noinstantiate This class is not intended to be instantiated by clients.
22 */
23public final class LocalSearchHintOptions {
24
25 private LocalSearchHintOptions() {
26 // Private constructor for utility class
27 }
28
29 public static final QueryHintOption<Boolean> USE_BASE_INDEX =
30 hintOption("USE_BASE_INDEX", true);
31
32 // This key can be used to influence the core planner algorithm
33 public static final QueryHintOption<Integer> PLANNER_TABLE_ROW_COUNT =
34 hintOption("PLANNER_TABLE_ROW_COUNT", 4);
35 /**
36 * Cost function to be used by the planner. Must implement {@link ICostFunction}
37 * @since 1.4
38 */
39 public static final QueryHintOption<ICostFunction> PLANNER_COST_FUNCTION =
40 hintOption("PLANNER_COST_FUNCTION", new IndexerBasedConstraintCostFunction());
41 /**
42 * Predicate to decide whether to flatten specific positive pattern calls {@link IFlattenCallPredicate}
43 * @since 1.4
44 */
45 public static final QueryHintOption<IFlattenCallPredicate> FLATTEN_CALL_PREDICATE =
46 hintOption("FLATTEN_CALL_PREDICATE", new DontFlattenDisjunctive());
47 /**
48 * Strategy to decide how hints (most importantly, backend selection) propagate across pattern calls.
49 * Must implement {@link ICallDelegationStrategy}.
50 * @since 2.1
51 */
52 public static final QueryHintOption<ICallDelegationStrategy> CALL_DELEGATION_STRATEGY =
53 hintOption("CALL_DELEGATION_STRATEGY", ICallDelegationStrategy.FULL_BACKEND_ADHESION);
54
55 /**
56 * A provider of expected adornments {@link IAdornmentProvider}.
57 *
58 * The safe default is {@link AllValidAdornments};
59 * however, the generic backend variant may safely use {@link LazyPlanningAdornments} instead.
60 *
61 * @since 1.5
62 */
63 public static final QueryHintOption<IAdornmentProvider> ADORNMENT_PROVIDER =
64 hintOption("ADORNMENT_PROVIDER", new AllValidAdornments());
65
66 // internal helper for conciseness
67 private static <T, V extends T> QueryHintOption<T> hintOption(String hintKeyLocalName, V defaultValue) {
68 return new QueryHintOption<>(LocalSearchHintOptions.class, hintKeyLocalName, defaultValue);
69 }
70}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java
new file mode 100644
index 00000000..5f3895be
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java
@@ -0,0 +1,306 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.matcher.integration;
10
11import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
12import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.IndexerBasedConstraintCostFunction;
13import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.StatisticsBasedConstraintCostFunction;
14import tools.refinery.viatra.runtime.matchers.backend.*;
15import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
16import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IRewriterTraceCollector;
17import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NopTraceCollector;
18
19import java.util.HashMap;
20import java.util.Map;
21import java.util.Objects;
22
23import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.*;
24import static tools.refinery.viatra.runtime.matchers.backend.CommonQueryHintOptions.normalizationTraceCollector;
25
26/**
27 * Type safe builder and extractor for Local search specific hints
28 *
29 * @author Grill Balázs
30 * @since 1.4
31 *
32 */
33public final class LocalSearchHints implements IMatcherCapability {
34
35 private Boolean useBase = null;
36
37 private Integer rowCount = null;
38
39 private ICostFunction costFunction = null;
40
41 private IFlattenCallPredicate flattenCallPredicate = null;
42
43 private ICallDelegationStrategy callDelegationStrategy = null;
44
45 private IAdornmentProvider adornmentProvider = null;
46
47 private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE;
48
49 private IQueryBackendFactory backendFactory = null;
50
51 private LocalSearchHints() {}
52
53 /**
54 * Return the default settings overridden by the given hints
55 */
56 public static LocalSearchHints getDefaultOverriddenBy(QueryEvaluationHint overridingHint){
57 return parse(getDefault().build(overridingHint));
58 }
59
60 /**
61 * Default settings which are considered the most safe, providing a reasonable performance for most of the cases. Assumes the availability of the base indexer.
62 */
63 public static LocalSearchHints getDefault(){
64 return getDefaultGeneric();
65 }
66
67 /**
68 * Initializes the generic (not EMF specific) search backend with the default settings
69 * @since 1.7
70 */
71 public static LocalSearchHints getDefaultGeneric(){
72 LocalSearchHints result = new LocalSearchHints();
73 result.useBase = true; // Should be unused; but a false value might cause surprises as an engine-default hint
74 result.rowCount = 4;
75 result.costFunction = new IndexerBasedConstraintCostFunction(StatisticsBasedConstraintCostFunction.INVERSE_NAVIGATION_PENALTY_GENERIC);
76 result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getDefaultValue();
77 result.callDelegationStrategy = ICallDelegationStrategy.FULL_BACKEND_ADHESION;
78 result.adornmentProvider = new LazyPlanningAdornments();
79 result.backendFactory = LocalSearchGenericBackendFactory.INSTANCE;
80 return result;
81 }
82
83 /**
84 * Initializes the default search backend with hybrid-enabled settings
85 * @since 2.1
86 */
87 public static LocalSearchHints getDefaultHybrid(){
88 LocalSearchHints result = getDefault();
89 result.callDelegationStrategy = ICallDelegationStrategy.PARTIAL_BACKEND_ADHESION;
90 result.flattenCallPredicate = new IFlattenCallPredicate.And(
91 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive());
92 return result;
93 }
94
95 /**
96 * Initializes the generic (not EMF specific) search backend with hybrid-enabled settings
97 * @since 2.1
98 */
99 public static LocalSearchHints getDefaultGenericHybrid(){
100 LocalSearchHints result = getDefaultGeneric();
101 result.callDelegationStrategy = ICallDelegationStrategy.PARTIAL_BACKEND_ADHESION;
102 result.flattenCallPredicate = new IFlattenCallPredicate.And(
103 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive());
104 return result;
105 }
106
107 public static LocalSearchHints parse(QueryEvaluationHint hint){
108 LocalSearchHints result = new LocalSearchHints();
109
110 result.useBase = USE_BASE_INDEX.getValueOrNull(hint);
111 result.rowCount = PLANNER_TABLE_ROW_COUNT.getValueOrNull(hint);
112 result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getValueOrNull(hint);
113 result.callDelegationStrategy = CALL_DELEGATION_STRATEGY.getValueOrNull(hint);
114 result.costFunction = PLANNER_COST_FUNCTION.getValueOrNull(hint);
115 result.adornmentProvider = ADORNMENT_PROVIDER.getValueOrNull(hint);
116 result.traceCollector = normalizationTraceCollector.getValueOrDefault(hint);
117
118 return result;
119 }
120
121
122 private Map<QueryHintOption<?>, Object> calculateHintMap() {
123 Map<QueryHintOption<?>, Object> map = new HashMap<>();
124 if (useBase != null){
125 USE_BASE_INDEX.insertOverridingValue(map, useBase);
126 }
127 if (rowCount != null){
128 PLANNER_TABLE_ROW_COUNT.insertOverridingValue(map, rowCount);
129 }
130 if (costFunction != null){
131 PLANNER_COST_FUNCTION.insertOverridingValue(map, costFunction);
132 }
133 if (flattenCallPredicate != null){
134 FLATTEN_CALL_PREDICATE.insertOverridingValue(map, flattenCallPredicate);
135 }
136 if (callDelegationStrategy != null){
137 CALL_DELEGATION_STRATEGY.insertOverridingValue(map, callDelegationStrategy);
138 }
139 if (adornmentProvider != null){
140 ADORNMENT_PROVIDER.insertOverridingValue(map, adornmentProvider);
141 }
142 if (traceCollector != null){
143 normalizationTraceCollector.insertOverridingValue(map, traceCollector);
144 }
145 return map;
146 }
147
148 public QueryEvaluationHint build(){
149 Map<QueryHintOption<?>, Object> map = calculateHintMap();
150 return new QueryEvaluationHint(map, backendFactory);
151 }
152
153 /**
154 * @since 1.7
155 */
156 public QueryEvaluationHint build(QueryEvaluationHint overridingHint) {
157 if (overridingHint == null)
158 return build();
159
160 IQueryBackendFactory factory = (overridingHint.getQueryBackendFactory() == null)
161 ? this.backendFactory
162 : overridingHint.getQueryBackendFactory();
163
164 Map<QueryHintOption<?>, Object> hints = calculateHintMap();
165 if (overridingHint.getBackendHintSettings() != null) {
166 hints.putAll(overridingHint.getBackendHintSettings());
167 }
168
169 return new QueryEvaluationHint(hints, factory);
170 }
171
172 public boolean isUseBase() {
173 return useBase;
174 }
175
176 public ICostFunction getCostFunction() {
177 return costFunction;
178 }
179
180 public IFlattenCallPredicate getFlattenCallPredicate() {
181 return flattenCallPredicate;
182 }
183
184 /**
185 * @since 2.1
186 */
187 public ICallDelegationStrategy getCallDelegationStrategy() {
188 return callDelegationStrategy;
189 }
190
191 public Integer getRowCount() {
192 return rowCount;
193 }
194
195 /**
196 * @since 1.5
197 */
198 public IAdornmentProvider getAdornmentProvider() {
199 return adornmentProvider;
200 }
201
202 /**
203 * @since 1.6
204 */
205 public IRewriterTraceCollector getTraceCollector() {
206 return traceCollector == null ? normalizationTraceCollector.getDefaultValue() : traceCollector;
207 }
208
209 public LocalSearchHints setUseBase(boolean useBase) {
210 this.useBase = useBase;
211 return this;
212 }
213
214 public LocalSearchHints setRowCount(int rowCount) {
215 this.rowCount = rowCount;
216 return this;
217 }
218
219 public LocalSearchHints setCostFunction(ICostFunction costFunction) {
220 this.costFunction = costFunction;
221 return this;
222 }
223
224 public LocalSearchHints setFlattenCallPredicate(IFlattenCallPredicate flattenCallPredicate) {
225 this.flattenCallPredicate = flattenCallPredicate;
226 return this;
227 }
228
229
230 /**
231 * @since 2.1
232 */
233 public LocalSearchHints setCallDelegationStrategy(ICallDelegationStrategy callDelegationStrategy) {
234 this.callDelegationStrategy = callDelegationStrategy;
235 return this;
236 }
237
238 /**
239 * @since 1.6
240 */
241 public LocalSearchHints setTraceCollector(IRewriterTraceCollector traceCollector) {
242 this.traceCollector = traceCollector;
243 return this;
244 }
245
246 /**
247 * @since 1.5
248 */
249 public LocalSearchHints setAdornmentProvider(IAdornmentProvider adornmentProvider) {
250 this.adornmentProvider = adornmentProvider;
251 return this;
252 }
253
254 public static LocalSearchHints customizeUseBase(boolean useBase){
255 return new LocalSearchHints().setUseBase(useBase);
256 }
257
258 public static LocalSearchHints customizeRowCount(int rowCount){
259 return new LocalSearchHints().setRowCount(rowCount);
260 }
261
262 public static LocalSearchHints customizeCostFunction(ICostFunction costFunction){
263 return new LocalSearchHints().setCostFunction(costFunction);
264 }
265
266 public static LocalSearchHints customizeFlattenCallPredicate(IFlattenCallPredicate predicate){
267 return new LocalSearchHints().setFlattenCallPredicate(predicate);
268 }
269
270 /**
271 * @since 2.1
272 */
273 public static LocalSearchHints customizeCallDelegationStrategy(ICallDelegationStrategy strategy){
274 return new LocalSearchHints().setCallDelegationStrategy(strategy);
275 }
276
277 /**
278 * @since 1.5
279 */
280 public static LocalSearchHints customizeAdornmentProvider(IAdornmentProvider adornmentProvider){
281 return new LocalSearchHints().setAdornmentProvider(adornmentProvider);
282 }
283
284 /**
285 * @since 1.6
286 */
287 public static LocalSearchHints customizeTraceCollector(IRewriterTraceCollector traceCollector){
288 return new LocalSearchHints().setTraceCollector(traceCollector);
289 }
290
291 @Override
292 public boolean canBeSubstitute(IMatcherCapability capability) {
293 if (capability instanceof LocalSearchHints){
294 LocalSearchHints other = (LocalSearchHints)capability;
295 /*
296 * We allow substitution of matchers if their functionally relevant settings are equal.
297 */
298 return Objects.equals(other.useBase, useBase);
299 }
300 /*
301 * For any other cases (e.g. for Rete), we cannot assume
302 * that matchers created by LS are functionally equivalent.
303 */
304 return false;
305 }
306}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/CheckOperationExecutor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/CheckOperationExecutor.java
new file mode 100644
index 00000000..295ac110
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/CheckOperationExecutor.java
@@ -0,0 +1,50 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations;
10
11import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
12import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
13import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation.ISearchOperationExecutor;
14
15/**
16 * Abstract base class for search operations that check only the already set variables.
17 *
18 * @noextend This class is not intended to be subclassed by clients.
19 * @since 2.0
20 */
21public abstract class CheckOperationExecutor implements ISearchOperationExecutor {
22
23 /**
24 * The executed field ensures that the second call of the check always returns false, resulting in a quick
25 * backtracking.
26 */
27 private boolean executed;
28
29 @Override
30 public void onInitialize(MatchingFrame frame, ISearchContext context) {
31 executed = false;
32 }
33
34 @Override
35 public void onBacktrack(MatchingFrame frame, ISearchContext context) {
36 }
37
38 @Override
39 public boolean execute(MatchingFrame frame, ISearchContext context) {
40 executed = executed ? false : check(frame, context);
41 return executed;
42 }
43
44 /**
45 * Executes the checking operation
46 * @since 1.7
47 */
48 protected abstract boolean check(MatchingFrame frame, ISearchContext context) ;
49
50}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ExtendOperationExecutor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ExtendOperationExecutor.java
new file mode 100644
index 00000000..a72c30dd
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ExtendOperationExecutor.java
@@ -0,0 +1,77 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.viatra.runtime.localsearch.operations;
11
12import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
13import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
14import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation.ISearchOperationExecutor;
15
16import java.util.Iterator;
17
18/**
19 * An operation that can be used to enumerate all possible values for a single position based on a constraint
20 * @author Zoltan Ujhelyi, Akos Horvath
21 * @noextend This class is not intended to be subclassed by clients.
22 * @since 2.0
23 */
24public abstract class ExtendOperationExecutor<T> implements ISearchOperationExecutor {
25
26 private Iterator<? extends T> it;
27
28 /**
29 * Returns an iterator with the possible options from the current state
30 * @since 2.0
31 */
32 protected abstract Iterator<? extends T> getIterator(MatchingFrame frame, ISearchContext context);
33 /**
34 * Updates the frame with the next element of the iterator. Called during {@link #execute(MatchingFrame, ISearchContext)}.
35 *
36 * @return true if the update is successful or false otherwise; in case of false is returned, the next element should be taken from the iterator.
37 * @since 2.0
38 */
39 protected abstract boolean fillInValue(T newValue, MatchingFrame frame, ISearchContext context);
40
41 /**
42 * Restores the frame to the state before {@link #fillInValue(Object, MatchingFrame, ISearchContext)}. Called during
43 * {@link #onBacktrack(MatchingFrame, ISearchContext)}.
44 *
45 * @since 2.0
46 */
47 protected abstract void cleanup(MatchingFrame frame, ISearchContext context);
48
49 @Override
50 public void onInitialize(MatchingFrame frame, ISearchContext context) {
51 it = getIterator(frame, context);
52 }
53
54 @Override
55 public void onBacktrack(MatchingFrame frame, ISearchContext context) {
56 it = null;
57
58 }
59
60 /**
61 * Fixed version that handles failed unification of variables correctly.
62 * @param frame The matching frame to extend.
63 * @param context The search context.
64 * @return {@code true} if an extension was found, {@code false} otherwise.
65 */
66 @Override
67 public boolean execute(MatchingFrame frame, ISearchContext context) {
68 while (it.hasNext()) {
69 var newValue = it.next();
70 if (fillInValue(newValue, frame, context)) {
71 return true;
72 }
73 }
74 return false;
75 }
76
77}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IIteratingSearchOperation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IIteratingSearchOperation.java
new file mode 100644
index 00000000..6fee0097
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IIteratingSearchOperation.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
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.operations;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12
13/**
14 * Denotes a {@link ISearchOperation} which involves iterating over an instances of an {@link IInputKey}
15 *
16 * @author Grill Balázs
17 * @since 1.4
18 *
19 */
20public interface IIteratingSearchOperation extends ISearchOperation{
21
22 /**
23 * Get the {@link IInputKey} which instances this operation iterates upon.
24 */
25 public IInputKey getIteratedInputKey();
26
27}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IPatternMatcherOperation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IPatternMatcherOperation.java
new file mode 100644
index 00000000..d8106329
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/IPatternMatcherOperation.java
@@ -0,0 +1,26 @@
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.operations;
10
11import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
12
13/**
14 * Marker interface for pattern matcher call operations, such as positive and negative pattern calls or match aggregators.
15 *
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 */
19public interface IPatternMatcherOperation {
20
21 /**
22 * Returns the precomputed call information associated with the current operation
23 * @since 2.0
24 */
25 CallInformation getCallInformation();
26}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ISearchOperation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ISearchOperation.java
new file mode 100644
index 00000000..eb6243ed
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/ISearchOperation.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations;
10
11import java.util.List;
12import java.util.function.Function;
13
14import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
15import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
16import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
17
18/**
19 * Represents a search operation executable by the LS engine. It is expected that an operation can be shared among
20 * multiple LS matchers, but the created executors are not.
21 *
22 * @author Zoltan Ujhelyi
23 *
24 */
25public interface ISearchOperation {
26
27 /**
28 * Initializes a new operation executor for the given operation. Repeated calls must return different executor
29 * instances.
30 *
31 * @since 2.0
32 */
33 public ISearchOperationExecutor createExecutor();
34
35 /**
36 *
37 * @since 2.0
38 *
39 */
40 public interface ISearchOperationExecutor {
41
42 /**
43 * Returns the stateless operation this executor was initialized from
44 */
45 ISearchOperation getOperation();
46
47 /**
48 * During the execution of the corresponding plan, the onInitialize callback is evaluated before the execution of
49 * the operation may begin. Operations may use this method to initialize its internal data structures.
50 *
51 * @throws ViatraQueryRuntimeException
52 */
53 void onInitialize(MatchingFrame frame, ISearchContext context);
54
55 /**
56 * After the execution of the operation failed and {@link #execute(MatchingFrame, ISearchContext)} returns false, the onBacktrack
57 * callback is evaluated. Operations may use this method to clean up any temporary structures, and make the
58 * operation ready for a new execution.
59 *
60 * @throws ViatraQueryRuntimeException
61 */
62 void onBacktrack(MatchingFrame frame, ISearchContext context);
63
64 /**
65 *
66 * @param frame
67 * @param context
68 * @return true if successful, or false if backtracking needed
69 * @throws ViatraQueryRuntimeException
70 */
71 boolean execute(MatchingFrame frame, ISearchContext context);
72 }
73 /**
74 *
75 * @return the ordered list of the variable numbers that are affected by the search operation
76 */
77 List<Integer> getVariablePositions();
78
79 /**
80 * Creates a string representation of the search operation by replacing the variable numbers according to the
81 * parameter function. It is expected that the provided function does return a non-null value for each variable
82 * index that is returned by {@link #getVariablePositions()}; otherwise a {@link NullPointerException} will be
83 * thrown during the calculation of the string.
84 *
85 * @since 2.0
86 */
87 String toString(Function<Integer, String> variableMapping);
88}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/MatchingFrameValueProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/MatchingFrameValueProvider.java
new file mode 100644
index 00000000..38f62129
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/MatchingFrameValueProvider.java
@@ -0,0 +1,41 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, 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.localsearch.operations;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
14import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
15import tools.refinery.viatra.runtime.matchers.util.Preconditions;
16
17/**
18 *
19 *
20 * @author Zoltan Ujhelyi
21 *
22 */
23public class MatchingFrameValueProvider implements IValueProvider {
24
25 final Map<String, Integer> nameMap;
26 final MatchingFrame frame;
27
28 public MatchingFrameValueProvider(MatchingFrame frame, Map<String, Integer> nameMap) {
29 super();
30 this.frame = frame;
31 this.nameMap = nameMap;
32 }
33
34 @Override
35 public Object getValue(String variableName) {
36 Integer index = nameMap.get(variableName);
37 Preconditions.checkArgument(index != null, "Unknown parameter variable name");
38 return frame.get(index);
39 }
40
41}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/AggregatorCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/AggregatorCheck.java
new file mode 100644
index 00000000..4d631635
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/AggregatorCheck.java
@@ -0,0 +1,116 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.operations.check;
10
11import java.util.Collections;
12import java.util.List;
13import java.util.Objects;
14import java.util.function.Function;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
20import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
23import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
24import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
25import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint;
26import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
27
28/**
29 * Calculates the aggregated value of a column based on the given {@link AggregatorConstraint}
30 *
31 * @author Balázs Grill
32 * @since 1.4
33 * @noextend This class is not intended to be subclassed by clients.
34 */
35public class AggregatorCheck implements ISearchOperation, IPatternMatcherOperation {
36
37 private class Executor extends CheckOperationExecutor {
38
39 private final VolatileModifiableMaskedTuple maskedTuple;
40 private IQueryResultProvider matcher;
41
42 public Executor() {
43 super();
44 this.maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
45 }
46
47 @Override
48 public void onInitialize(MatchingFrame frame, ISearchContext context) {
49 super.onInitialize(frame, context);
50 maskedTuple.updateTuple(frame);
51 matcher = context.getMatcher(information.getCallWithAdornment());
52 }
53
54 @Override
55 protected boolean check(MatchingFrame frame, ISearchContext context) {
56 IMultisetAggregationOperator<?, ?, ?> operator = aggregator.getAggregator().getOperator();
57 Object result = aggregate(operator, aggregator.getAggregatedColumn(), frame);
58 return result == null ? false : Objects.equals(frame.getValue(position), result);
59 }
60
61 @SuppressWarnings("unchecked")
62 private <Domain, Accumulator, AggregateResult> AggregateResult aggregate(
63 IMultisetAggregationOperator<Domain, Accumulator, AggregateResult> operator, int aggregatedColumn,
64 MatchingFrame initialFrame) {
65 maskedTuple.updateTuple(initialFrame);
66 final Stream<Domain> valueStream = matcher.getAllMatches(information.getParameterMask(), maskedTuple)
67 .map(match -> (Domain) match.get(aggregatedColumn));
68 return operator.aggregateStream(valueStream);
69 }
70
71 @Override
72 public ISearchOperation getOperation() {
73 return AggregatorCheck.this;
74 }
75 }
76
77 private final int position;
78 private final AggregatorConstraint aggregator;
79 private final CallInformation information;
80
81 /**
82 * @since 1.7
83 */
84 public AggregatorCheck(CallInformation information, AggregatorConstraint aggregator, int position) {
85 super();
86 this.information = information;
87 this.position = position;
88 this.aggregator = aggregator;
89 }
90
91 @Override
92 public ISearchOperationExecutor createExecutor() {
93 return new Executor();
94 }
95
96 @Override
97 public List<Integer> getVariablePositions() {
98 return Collections.singletonList(position);
99 }
100
101 @Override
102 public String toString() {
103 return toString(Object::toString);
104 }
105
106 @Override
107 public String toString(Function<Integer, String> variableMapping) {
108 return "check "+variableMapping.apply(position)+" = " + aggregator.getAggregator().getOperator().getName() + " find " + information.toString(variableMapping);
109 }
110
111 @Override
112 public CallInformation getCallInformation() {
113 return information;
114 }
115
116}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/BinaryTransitiveClosureCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/BinaryTransitiveClosureCheck.java
new file mode 100644
index 00000000..8f818542
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/BinaryTransitiveClosureCheck.java
@@ -0,0 +1,135 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.HashSet;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Objects;
16import java.util.Queue;
17import java.util.Set;
18import java.util.function.Function;
19
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
23import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
24import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
25import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
26import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
27import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
28
29/**
30 * Checking for a transitive closure expressed as a local search pattern matcher. The matched pattern must have two
31 * parameters of the same model type.
32 *
33 * @author Zoltan Ujhelyi
34 * @noextend This class is not intended to be subclassed by clients.
35 * @noinstantiate This class is not intended to be instantiated by clients.
36 *
37 */
38public class BinaryTransitiveClosureCheck implements ISearchOperation, IPatternMatcherOperation {
39
40 private class Executor extends CheckOperationExecutor {
41
42 @Override
43 public void onInitialize(MatchingFrame frame, ISearchContext context) {
44 super.onInitialize(frame, context);
45 matcher = context.getMatcher(information.getCallWithAdornment());
46 // Note: second parameter is NOT bound during execution, but the first is
47 }
48
49 @Override
50 protected boolean check(MatchingFrame frame, ISearchContext context) {
51 if (checkReflexive(frame)) {
52 return true;
53 }
54
55 Object targetValue = frame.get(targetPosition);
56 Queue<Object> sourcesToEvaluate = new LinkedList<>();
57 sourcesToEvaluate.add(frame.get(sourcePosition));
58 Set<Object> sourceEvaluated = new HashSet<>();
59 final Object[] mappedFrame = new Object[] {null, null};
60 while (!sourcesToEvaluate.isEmpty()) {
61 Object currentValue = sourcesToEvaluate.poll();
62 sourceEvaluated.add(currentValue);
63 mappedFrame[0] = currentValue;
64 for (Tuple match : (Iterable<Tuple>) () -> matcher.getAllMatches(mappedFrame).iterator()) {
65 Object foundTarget = match.get(1);
66 if (targetValue.equals(foundTarget)) {
67 return true;
68 } else if (!sourceEvaluated.contains(foundTarget)) {
69 sourcesToEvaluate.add(foundTarget);
70 }
71 }
72 }
73 return false;
74 }
75
76 protected boolean checkReflexive(MatchingFrame frame) {
77 return reflexive && Objects.equals(frame.get(sourcePosition), frame.get(targetPosition));
78 }
79
80 @Override
81 public ISearchOperation getOperation() {
82 return BinaryTransitiveClosureCheck.this;
83 }
84 }
85
86 private final CallInformation information;
87 private IQueryResultProvider matcher;
88 private final int sourcePosition;
89 private final int targetPosition;
90 private final boolean reflexive;
91
92 /**
93 * The source position will be matched in the called pattern to the first parameter; while target to the second.
94 * </p>
95 * <strong>NOTE</strong>: the reflexive check call does not include the parameter type checks; appropriate type checks should be
96 * added as necessary by the operation compiler.
97 *
98 * @since 2.0
99 */
100 public BinaryTransitiveClosureCheck(CallInformation information, int sourcePosition, int targetPosition, boolean reflexive) {
101 super();
102 this.sourcePosition = sourcePosition;
103 this.targetPosition = targetPosition;
104 this.information = information;
105 this.reflexive = reflexive;
106 }
107
108 @Override
109 public ISearchOperationExecutor createExecutor() {
110 return new Executor();
111 }
112
113 @Override
114 public String toString() {
115 return toString(Object::toString);
116 }
117
118 @Override
119 public String toString(Function<Integer, String> variableMapping) {
120 String c = information.toString(variableMapping);
121 int p = c.indexOf('(');
122 String modifier = reflexive ? "*" : "+";
123 return "check find "+c.substring(0, p)+ modifier +c.substring(p);
124 }
125
126 @Override
127 public List<Integer> getVariablePositions() {
128 return Arrays.asList(sourcePosition, targetPosition);
129 }
130
131 @Override
132 public CallInformation getCallInformation() {
133 return information;
134 }
135}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckConstant.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckConstant.java
new file mode 100644
index 00000000..4ce48af0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckConstant.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.Collections;
12import java.util.List;
13import java.util.function.Function;
14
15import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
16import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
17import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
18import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
19
20/**
21 * This operation handles constants in search plans by checking if a variable is bound to a certain constant value. Such
22 * operations should be executed as early as possible during plan execution.
23 *
24 * @author Marton Bur
25 * @noextend This class is not intended to be subclassed by clients.
26 */
27public class CheckConstant implements ISearchOperation {
28
29 private class Executor extends CheckOperationExecutor {
30
31 @Override
32 protected boolean check(MatchingFrame frame, ISearchContext context) {
33 return frame.get(position).equals(value);
34 }
35
36 @Override
37 public ISearchOperation getOperation() {
38 return CheckConstant.this;
39 }
40 }
41
42 private int position;
43 private Object value;
44
45 public CheckConstant(int position, Object value) {
46 this.position = position;
47 this.value = value;
48 }
49
50 @Override
51 public ISearchOperationExecutor createExecutor() {
52 return new Executor();
53 }
54
55 @Override
56 public List<Integer> getVariablePositions() {
57 return Collections.singletonList(position);
58 }
59
60 @Override
61 public String toString() {
62 return toString(Object::toString);
63 }
64
65 @Override
66 public String toString(Function<Integer, String> variableMapping) {
67 return "check constant "+variableMapping.apply(position)+"='"+value+"'";
68 }
69
70}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckPositivePatternCall.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckPositivePatternCall.java
new file mode 100644
index 00000000..5f9b688a
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CheckPositivePatternCall.java
@@ -0,0 +1,96 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
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.operations.check;
10
11import java.util.List;
12import java.util.function.Function;
13
14import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
15import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
16import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
17import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
18import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
19import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
20import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
21import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
22
23/**
24 * @author Grill Balázs
25 * @since 1.4
26 * @noextend This class is not intended to be subclassed by clients.
27 */
28public class CheckPositivePatternCall implements ISearchOperation, IPatternMatcherOperation {
29
30 private class Executor extends CheckOperationExecutor {
31
32 private final VolatileModifiableMaskedTuple maskedTuple;
33 private IQueryResultProvider matcher;
34
35 public Executor() {
36 super();
37 this.maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
38 }
39
40 @Override
41 public void onInitialize(MatchingFrame frame, ISearchContext context) {
42 super.onInitialize(frame, context);
43 maskedTuple.updateTuple(frame);
44 matcher = context.getMatcher(information.getCallWithAdornment());
45 }
46
47 /**
48 * @since 1.5
49 */
50 protected boolean check(MatchingFrame frame, ISearchContext context) {
51 return matcher.hasMatch(information.getParameterMask(), maskedTuple);
52 }
53
54 @Override
55 public ISearchOperation getOperation() {
56 return CheckPositivePatternCall.this;
57 }
58 }
59
60 private final CallInformation information;
61
62
63 /**
64 * @since 1.7
65 */
66 public CheckPositivePatternCall(CallInformation information) {
67 super();
68 this.information = information;
69
70 }
71
72 @Override
73 public ISearchOperationExecutor createExecutor() {
74 return new Executor();
75 }
76
77 @Override
78 public List<Integer> getVariablePositions() {
79 return information.getVariablePositions();
80 }
81
82 @Override
83 public String toString() {
84 return toString(Object::toString);
85 }
86
87 @Override
88 public String toString(Function<Integer, String> variableMapping) {
89 return "check find "+information.toString(variableMapping);
90 }
91
92 @Override
93 public CallInformation getCallInformation() {
94 return information;
95 }
96}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CountCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CountCheck.java
new file mode 100644
index 00000000..d74c1c6f
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/CountCheck.java
@@ -0,0 +1,92 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.Collections;
12import java.util.List;
13import java.util.function.Function;
14
15import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
16import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
17import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
18import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
21import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
22import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
23
24/**
25 * Calculates the count of matches for a called matcher
26 *
27 * @author Zoltan Ujhelyi
28 * @noextend This class is not intended to be subclassed by clients.
29 */
30public class CountCheck implements ISearchOperation, IPatternMatcherOperation {
31
32 private class Executor extends CheckOperationExecutor {
33
34 private final VolatileModifiableMaskedTuple maskedTuple;
35 private IQueryResultProvider matcher;
36
37 public Executor() {
38 maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
39 }
40
41 @Override
42 public void onInitialize(MatchingFrame frame, ISearchContext context) {
43 super.onInitialize(frame, context);
44 maskedTuple.updateTuple(frame);
45 matcher = context.getMatcher(information.getCallWithAdornment());
46 }
47
48 @Override
49 protected boolean check(MatchingFrame frame, ISearchContext context) {
50 int count = matcher.countMatches(information.getParameterMask(), maskedTuple);
51 return ((Integer)frame.getValue(position)) == count;
52 }
53
54 @Override
55 public ISearchOperation getOperation() {
56 return CountCheck.this;
57 }
58 }
59
60 private final int position;
61 private final CallInformation information;
62
63 /**
64 * @since 1.7
65 */
66 public CountCheck(CallInformation information, int position) {
67 super();
68 this.information = information;
69 this.position = position;
70 }
71
72
73 @Override
74 public ISearchOperationExecutor createExecutor() {
75 return new Executor();
76 }
77
78 @Override
79 public List<Integer> getVariablePositions() {
80 return Collections.singletonList(position);
81 }
82
83 @Override
84 public String toString(Function<Integer, String> variableMapping) {
85 return "check "+variableMapping.apply(position)+" = count find "+ information.toString(variableMapping);
86 }
87
88 @Override
89 public CallInformation getCallInformation() {
90 return information;
91 }
92}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionCheck.java
new file mode 100644
index 00000000..fc9efdca
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionCheck.java
@@ -0,0 +1,78 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.ArrayList;
12import java.util.List;
13import java.util.Map;
14import java.util.function.Function;
15
16import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
17import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
18import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.localsearch.operations.MatchingFrameValueProvider;
21import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
22
23/**
24 * @author Zoltan Ujhelyi
25 * @noextend This class is not intended to be subclassed by clients.
26 */
27public class ExpressionCheck implements ISearchOperation {
28
29 private class Executor extends CheckOperationExecutor {
30
31 @Override
32 protected boolean check(MatchingFrame frame, ISearchContext context) {
33 try {
34 boolean result = (Boolean) evaluator.evaluateExpression(new MatchingFrameValueProvider(frame, nameMap));
35 return result;
36 } catch (Exception e) {
37 context.getLogger().warn("Error while evaluating expression", e);
38 return false;
39 }
40 }
41
42 @Override
43 public ISearchOperation getOperation() {
44 return ExpressionCheck.this;
45 }
46 }
47
48 IExpressionEvaluator evaluator;
49 Map<String, Integer> nameMap;
50
51 public ExpressionCheck(IExpressionEvaluator evaluator, Map<String, Integer> nameMap) {
52 super();
53 this.evaluator = evaluator;
54 this.nameMap = nameMap;
55 }
56
57 @Override
58 public ISearchOperationExecutor createExecutor() {
59 return new Executor();
60 }
61
62 @Override
63 public List<Integer> getVariablePositions() {
64 // XXX not sure if this is the correct implementation to get the affected variable indicies
65 return new ArrayList<>(nameMap.values());
66 }
67
68 @Override
69 public String toString() {
70 return toString(Object::toString);
71 }
72
73 @Override
74 public String toString(Function<Integer, String> variableMapping) {
75 return "check expression "+evaluator.getShortDescription();
76 }
77
78}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionEvalCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionEvalCheck.java
new file mode 100644
index 00000000..5b1bca10
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ExpressionEvalCheck.java
@@ -0,0 +1,95 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
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.operations.check;
10
11import java.util.ArrayList;
12import java.util.List;
13import java.util.Map;
14import java.util.Set;
15import java.util.function.Function;
16
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
20import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.MatchingFrameValueProvider;
22import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
23
24/**
25 * @author Grill Balázs
26 * @since 1.3
27 * @noextend This class is not intended to be subclassed by clients.
28 */
29public class ExpressionEvalCheck implements ISearchOperation {
30
31 private class Executor extends CheckOperationExecutor {
32
33 @Override
34 protected boolean check(MatchingFrame frame, ISearchContext context) {
35 try {
36 Object result = evaluator.evaluateExpression(new MatchingFrameValueProvider(frame, nameMap));
37 if (!unwind && result != null) {
38 Object currentValue = frame.get(outputPosition);
39 return result.equals(currentValue);
40 } else if (unwind && result instanceof Set<?>) {
41 Object currentValue = frame.get(outputPosition);
42 return ((Set<?>)result).contains(currentValue);
43 }
44 } catch (Exception e) {
45 context.getLogger().warn("Error while evaluating expression", e);
46 }
47 return false;
48 }
49
50 @Override
51 public ISearchOperation getOperation() {
52 return ExpressionEvalCheck.this;
53 }
54 }
55
56 private final int outputPosition;
57 private final IExpressionEvaluator evaluator;
58 private final Map<String, Integer> nameMap;
59 private final boolean unwind;
60
61 public ExpressionEvalCheck(IExpressionEvaluator evaluator, Map<String, Integer> nameMap, int position) {
62 this(evaluator, nameMap, false, position);
63 }
64
65 /**
66 * @since 2.7
67 */
68 public ExpressionEvalCheck(IExpressionEvaluator evaluator, Map<String, Integer> nameMap, boolean unwind, int position) {
69 this.evaluator = evaluator;
70 this.nameMap = nameMap;
71 this.unwind = unwind;
72 this.outputPosition = position;
73 }
74
75 @Override
76 public ISearchOperationExecutor createExecutor() {
77 return new Executor();
78 }
79
80 @Override
81 public List<Integer> getVariablePositions() {
82 // XXX not sure if this is the correct implementation to get the affected variable indicies
83 return new ArrayList<>(nameMap.values());
84 }
85
86 @Override
87 public String toString() {
88 return toString(Object::toString);
89 }
90
91 @Override
92 public String toString(Function<Integer, String> variableMapping) {
93 return "check "+variableMapping.apply(outputPosition)+" = expression "+evaluator.getShortDescription();
94 }
95}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InequalityCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InequalityCheck.java
new file mode 100644
index 00000000..3f30c3c4
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InequalityCheck.java
@@ -0,0 +1,77 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.function.Function;
14
15import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
16import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
17import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
18import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20
21/**
22 * @author Zoltan Ujhelyi
23 * @noextend This class is not intended to be subclassed by clients.
24 */
25public class InequalityCheck implements ISearchOperation {
26
27 private class Executor extends CheckOperationExecutor {
28
29 @Override
30 protected boolean check(MatchingFrame frame, ISearchContext context) {
31 Object source = frame.getValue(sourceLocation);
32 Object target = frame.getValue(targetLocation);
33 if (source == null) {
34 throw new LocalSearchException("Source not bound.");
35 }
36 if (target == null) {
37 throw new LocalSearchException("Target not bound");
38 }
39 return !source.equals(target);
40 }
41
42 @Override
43 public ISearchOperation getOperation() {
44 return InequalityCheck.this;
45 }
46 }
47
48 int sourceLocation;
49 int targetLocation;
50
51 public InequalityCheck(int sourceLocation, int targetLocation) {
52 super();
53 this.sourceLocation = sourceLocation;
54 this.targetLocation = targetLocation;
55 }
56
57 @Override
58 public ISearchOperationExecutor createExecutor() {
59 return new Executor();
60 }
61
62 @Override
63 public String toString() {
64 return toString(Object::toString);
65 }
66
67 @Override
68 public String toString(Function<Integer, String> variableMapping) {
69 return "check "+variableMapping.apply(sourceLocation)+" != "+variableMapping.apply(targetLocation);
70 }
71
72 @Override
73 public List<Integer> getVariablePositions() {
74 return Arrays.asList(sourceLocation, targetLocation);
75 }
76
77}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/NACOperation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/NACOperation.java
new file mode 100644
index 00000000..3759e1d1
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/NACOperation.java
@@ -0,0 +1,89 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.check;
10
11import java.util.List;
12import java.util.function.Function;
13
14import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
15import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
16import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
17import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
18import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
19import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
20import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
21import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
22
23/**
24 * @author Zoltan Ujhelyi
25 * @noextend This class is not intended to be subclassed by clients.
26 */
27public class NACOperation implements ISearchOperation, IPatternMatcherOperation {
28
29 private class Executor extends CheckOperationExecutor {
30 private final VolatileModifiableMaskedTuple maskedTuple;
31 private IQueryResultProvider matcher;
32
33 private Executor() {
34 this.maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
35 }
36
37 @Override
38 public void onInitialize(MatchingFrame frame, ISearchContext context) {
39 super.onInitialize(frame, context);
40 maskedTuple.updateTuple(frame);
41 matcher = context.getMatcher(information.getCallWithAdornment());
42 }
43
44 @Override
45 protected boolean check(MatchingFrame frame, ISearchContext context) {
46 return !matcher.hasMatch(information.getParameterMask(), maskedTuple);
47 }
48
49 @Override
50 public ISearchOperation getOperation() {
51 return NACOperation.this;
52 }
53 }
54
55 private final CallInformation information;
56
57 /**
58 * @since 1.7
59 */
60 public NACOperation(CallInformation information) {
61 super();
62 this.information = information;
63 }
64
65 @Override
66 public ISearchOperationExecutor createExecutor() {
67 return new Executor();
68 }
69
70 @Override
71 public String toString() {
72 return toString(Object::toString);
73 }
74
75 @Override
76 public String toString(Function<Integer, String> variableMapping) {
77 return "check neg find "+information.toString(variableMapping);
78 }
79
80 @Override
81 public List<Integer> getVariablePositions() {
82 return information.getVariablePositions();
83 }
84
85 @Override
86 public CallInformation getCallInformation() {
87 return information;
88 }
89}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/AggregatorExtend.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/AggregatorExtend.java
new file mode 100644
index 00000000..c2e75b7a
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/AggregatorExtend.java
@@ -0,0 +1,106 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.operations.extend;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.function.Function;
16import java.util.stream.Stream;
17
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
20import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
23import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
24import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
25import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint;
26import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
27
28/**
29 * Calculates the aggregated value of a column based on the given {@link AggregatorConstraint}
30 *
31 * @author Balázs Grill
32 * @since 1.4
33 */
34public class AggregatorExtend implements ISearchOperation, IPatternMatcherOperation{
35
36 private class Executor extends SingleValueExtendOperationExecutor<Object> {
37
38 private final VolatileModifiableMaskedTuple maskedTuple;
39 private IQueryResultProvider matcher;
40
41 public Executor(int position) {
42 super(position);
43 this.maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
44 }
45
46 @Override
47 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
48 maskedTuple.updateTuple(frame);
49 matcher = context.getMatcher(information.getCallWithAdornment());
50 Object aggregate = aggregate(aggregator.getAggregator().getOperator(), aggregator.getAggregatedColumn());
51 return aggregate == null ? Collections.emptyIterator() : Collections.singletonList(aggregate).iterator();
52
53 }
54
55 @SuppressWarnings("unchecked")
56 private <Domain, Accumulator, AggregateResult> AggregateResult aggregate(
57 IMultisetAggregationOperator<Domain, Accumulator, AggregateResult> operator, int aggregatedColumn) {
58 final Stream<Domain> valueStream = matcher.getAllMatches(information.getParameterMask(), maskedTuple)
59 .map(match -> (Domain) match.get(aggregatedColumn));
60 return operator.aggregateStream(valueStream);
61 }
62
63 @Override
64 public ISearchOperation getOperation() {
65 return AggregatorExtend.this;
66 }
67 }
68
69 private final AggregatorConstraint aggregator;
70 private final CallInformation information;
71 private final int position;
72
73 /**
74 * @since 1.7
75 */
76 public AggregatorExtend(CallInformation information, AggregatorConstraint aggregator, int position) {
77 this.aggregator = aggregator;
78 this.information = information;
79 this.position = position;
80 }
81
82 @Override
83 public ISearchOperationExecutor createExecutor() {
84 return new Executor(position);
85 }
86
87 @Override
88 public List<Integer> getVariablePositions() {
89 return Arrays.asList(position);
90 }
91
92 @Override
93 public String toString() {
94 return toString(Object::toString);
95 }
96
97 @Override
98 public String toString(Function<Integer, String> variableMapping) {
99 return "extend -"+variableMapping.apply(position)+" = " + aggregator.getAggregator().getOperator().getName()+" find " + information.toString(variableMapping);
100 }
101
102 @Override
103 public CallInformation getCallInformation() {
104 return information;
105 }
106}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/CountOperation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/CountOperation.java
new file mode 100644
index 00000000..08ecc8d6
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/CountOperation.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.extend;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
17import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
18import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
21import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
22import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
23
24/**
25 * Calculates the count of matches for a called matcher
26 *
27 * @author Zoltan Ujhelyi
28 */
29public class CountOperation implements ISearchOperation, IPatternMatcherOperation{
30
31 private class Executor extends SingleValueExtendOperationExecutor<Integer> {
32 private final VolatileModifiableMaskedTuple maskedTuple;
33 private IQueryResultProvider matcher;
34
35 public Executor(int position) {
36 super(position);
37 maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
38 }
39
40 @Override
41 public Iterator<Integer> getIterator(MatchingFrame frame, ISearchContext context) {
42 matcher = context.getMatcher(information.getCallWithAdornment());
43 maskedTuple.updateTuple(frame);
44 return Collections.singletonList(matcher.countMatches(information.getParameterMask(), maskedTuple)).iterator();
45 }
46
47 @Override
48 public ISearchOperation getOperation() {
49 return CountOperation.this;
50 }
51 }
52
53 private final CallInformation information;
54 private final int position;
55
56 /**
57 * @since 1.7
58 */
59 public CountOperation(CallInformation information, int position) {
60 this.information = information;
61 this.position = position;
62 }
63
64 @Override
65 public ISearchOperationExecutor createExecutor() {
66 return new Executor(position);
67 }
68
69 @Override
70 public List<Integer> getVariablePositions() {
71 return information.getVariablePositions();
72 }
73
74 @Override
75 public String toString() {
76 return toString(Object::toString);
77 }
78
79 @Override
80 public String toString(Function<Integer, String> variableMapping) {
81 return "extend -"+variableMapping.apply(position)+" = count find " + information.toString(variableMapping);
82 }
83
84 @Override
85 public CallInformation getCallInformation() {
86 return information;
87 }
88}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExpressionEval.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExpressionEval.java
new file mode 100644
index 00000000..7186f4ac
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExpressionEval.java
@@ -0,0 +1,104 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.extend;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.Map;
16import java.util.Set;
17import java.util.function.Function;
18
19import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
20import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.localsearch.operations.MatchingFrameValueProvider;
23import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
24
25/**
26 * Calculates the result of an expression and stores it inside a variable for future reference.
27 *
28 * @author Zoltan Ujhelyi
29 *
30 */
31public class ExpressionEval implements ISearchOperation {
32
33 private class Executor extends SingleValueExtendOperationExecutor<Object> {
34
35 public Executor(int position) {
36 super(position);
37 }
38
39 @Override
40 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
41 try {
42 Object result = evaluator.evaluateExpression(new MatchingFrameValueProvider(frame, nameMap));
43 if (!unwind && result != null){
44 return Collections.singletonList(result).iterator();
45 } else if (unwind && result instanceof Set<?>) {
46 return ((Set<?>)result).iterator();
47 } else {
48 return Collections.emptyIterator();
49 }
50 } catch (Exception e) {
51 context.getLogger().warn("Error while evaluating expression", e);
52 return Collections.emptyIterator();
53 }
54 }
55
56 @Override
57 public ISearchOperation getOperation() {
58 return ExpressionEval.this;
59 }
60 }
61
62 private final IExpressionEvaluator evaluator;
63 private final boolean unwind;
64 private final Map<String, Integer> nameMap;
65 private final int position;
66
67 public ExpressionEval(IExpressionEvaluator evaluator, Map<String, Integer> nameMap, int position) {
68 this(evaluator, nameMap, false, position);
69 }
70
71 /**
72 * @since 2.7
73 */
74 public ExpressionEval(IExpressionEvaluator evaluator, Map<String, Integer> nameMap, boolean unwind, int position) {
75 this.evaluator = evaluator;
76 this.nameMap = nameMap;
77 this.unwind = unwind;
78 this.position = position;
79 }
80
81 @Override
82 public String toString() {
83 return toString(Object::toString);
84 }
85
86 @Override
87 public String toString(Function<Integer, String> variableMapping) {
88 return "extend -"+variableMapping.apply(position)+" = expression "+evaluator.getShortDescription();
89 }
90
91 @Override
92 public ISearchOperationExecutor createExecutor() {
93 return new Executor(position);
94 }
95
96 @Override
97 public List<Integer> getVariablePositions() {
98 // XXX not sure if this is the correct implementation to get the affected variable indicies
99 List<Integer> variables = new ArrayList<>();
100 variables.addAll(nameMap.values());
101 return variables;
102 }
103
104}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendBinaryTransitiveClosure.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendBinaryTransitiveClosure.java
new file mode 100644
index 00000000..1250e84e
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendBinaryTransitiveClosure.java
@@ -0,0 +1,185 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.HashSet;
13import java.util.Iterator;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.Queue;
17import java.util.Set;
18import java.util.function.Function;
19
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
23import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
24import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
25import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
26import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
27
28/**
29 * Checking for a transitive closure expressed as a local search pattern matcher. The matched pattern must have two
30 * parameters of the same model type.
31 *
32 * @author Zoltan Ujhelyi
33 * @since 1.7
34 *
35 */
36public abstract class ExtendBinaryTransitiveClosure implements ISearchOperation, IPatternMatcherOperation {
37
38 private class Executor extends SingleValueExtendOperationExecutor<Object> {
39
40 public Executor(int position) {
41 super(position);
42 }
43
44 @Override
45 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
46 // Note: second parameter is NOT bound during execution, but the first is
47 IQueryResultProvider matcher = context.getMatcher(information.getCallWithAdornment());
48
49 Queue<Object> seedsToEvaluate = new LinkedList<>();
50 final Object seedValue = frame.get(seedPosition);
51 seedsToEvaluate.add(seedValue);
52 Set<Object> seedsEvaluated = new HashSet<>();
53 Set<Object> targetsFound = new HashSet<>();
54 if (reflexive) {
55 targetsFound.add(seedValue);
56 }
57
58 while(!seedsToEvaluate.isEmpty()) {
59 Object currentValue = seedsToEvaluate.poll();
60 seedsEvaluated.add(currentValue);
61 final Object[] mappedFrame = calculateCallFrame(currentValue);
62 matcher.getAllMatches(mappedFrame).forEach(match -> {
63 Object foundTarget = getTarget(match);
64 targetsFound.add(foundTarget);
65 if (!seedsEvaluated.contains(foundTarget)) {
66 seedsToEvaluate.add(foundTarget);
67 }
68 });
69 }
70
71 return targetsFound.iterator();
72 }
73
74 @Override
75 public ISearchOperation getOperation() {
76 return ExtendBinaryTransitiveClosure.this;
77 }
78 }
79
80 /**
81 * Calculates the transitive closure of a pattern match in a forward direction (first parameter bound, second
82 * unbound).
83 * </p>
84 * <strong>Note</strong>: In case the call is reflexive, it is expected that the bound parameter already matches the universe type of the call.
85 *
86 * @since 1.7
87 */
88 public static class Forward extends ExtendBinaryTransitiveClosure {
89
90 private Object[] seedFrame = new Object[2];
91
92 /**
93 * @since 2.0
94 */
95 public Forward(CallInformation information, int sourcePosition, int targetPosition, boolean reflexive) {
96 super(information, sourcePosition, targetPosition, reflexive);
97 }
98
99 protected Object[] calculateCallFrame(Object seed) {
100 seedFrame[0] = seed;
101 seedFrame[1] = null;
102 return seedFrame;
103 }
104
105 protected Object getTarget(Tuple frame) {
106 return frame.get(1);
107 }
108 }
109
110 /**
111 * Calculates the transitive closure of a pattern match in a backward direction (first parameter unbound, second
112 * bound)
113 * </p>
114 * <strong>Note</strong>: In case the call is reflexive, it is expected that the bound parameter already matches the universe type of the call.
115 *
116 * @since 2.0
117 */
118 public static class Backward extends ExtendBinaryTransitiveClosure {
119 private Object[] seedFrame = new Object[2];
120
121 /**
122 * @since 2.0
123 */
124 public Backward(CallInformation information, int sourcePosition, int targetPosition, boolean reflexive) {
125 super(information, targetPosition, sourcePosition, reflexive);
126 }
127
128 protected Object[] calculateCallFrame(Object seed) {
129 seedFrame[0] = null;
130 seedFrame[1] = seed;
131 return seedFrame;
132 }
133
134 protected Object getTarget(Tuple frame) {
135 return frame.get(0);
136 }
137 }
138
139 private final int seedPosition;
140 private final int targetPosition;
141 private final CallInformation information;
142 private final boolean reflexive;
143
144 /**
145 * The source position will be matched in the called pattern to the first parameter; while target to the second.
146 * @since 2.0
147 */
148 protected ExtendBinaryTransitiveClosure(CallInformation information, int seedPosition, int targetPosition, boolean reflexive) {
149 this.information = information;
150 this.seedPosition = seedPosition;
151 this.targetPosition = targetPosition;
152 this.reflexive = reflexive;
153 }
154
155 protected abstract Object[] calculateCallFrame(Object seed);
156
157 protected abstract Object getTarget(Tuple frame);
158
159 @Override
160 public ISearchOperationExecutor createExecutor() {
161 return new Executor(targetPosition);
162 }
163
164 @Override
165 public String toString() {
166 return toString(Object::toString);
167 }
168
169 @Override
170 public String toString(Function<Integer, String> variableMapping) {
171 String c = information.toString(variableMapping);
172 int p = c.indexOf('(');
173 return "extend find " + c.substring(0, p) + "+" + c.substring(p);
174 }
175
176 @Override
177 public List<Integer> getVariablePositions() {
178 return Arrays.asList(seedPosition, targetPosition);
179 }
180
181 @Override
182 public CallInformation getCallInformation() {
183 return information;
184 }
185}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendConstant.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendConstant.java
new file mode 100644
index 00000000..455236f3
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendConstant.java
@@ -0,0 +1,75 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.function.Function;
16
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20
21/**
22 * This operation handles constants in search plans by binding a variable to a constant value. Such operations should be
23 * executed as early as possible during plan execution.
24 *
25 * @author Marton Bur
26 *
27 */
28public class ExtendConstant implements ISearchOperation {
29
30 private class Executor extends SingleValueExtendOperationExecutor<Object> {
31
32 public Executor(int position) {
33 super(position);
34 }
35
36 @Override
37 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
38 return Collections.singletonList(value).iterator();
39 }
40
41 @Override
42 public ISearchOperation getOperation() {
43 return ExtendConstant.this;
44 }
45 }
46
47 private final Object value;
48 private final int position;
49
50 public ExtendConstant(int position, Object value) {
51 this.position = position;
52 this.value = value;
53 }
54
55 @Override
56 public ISearchOperationExecutor createExecutor() {
57 return new Executor(position);
58 }
59
60 @Override
61 public List<Integer> getVariablePositions() {
62 return Arrays.asList(position);
63 }
64
65 @Override
66 public String toString() {
67 return toString(Object::toString);
68 }
69
70 @Override
71 public String toString(Function<Integer, String> variableMapping) {
72 return "extend constant -"+variableMapping.apply(position)+"='"+value+"'";
73 }
74
75}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendPositivePatternCall.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendPositivePatternCall.java
new file mode 100644
index 00000000..690a3241
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendPositivePatternCall.java
@@ -0,0 +1,118 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
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.operations.extend;
10
11import java.util.Iterator;
12import java.util.List;
13import java.util.function.Function;
14
15import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
16import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
17import tools.refinery.viatra.runtime.localsearch.operations.ExtendOperationExecutor;
18import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.localsearch.operations.util.CallInformation;
21import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
22import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
23import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
24import tools.refinery.viatra.runtime.matchers.tuple.VolatileModifiableMaskedTuple;
25
26/**
27 * @author Grill Balázs
28 * @since 1.4
29 *
30 */
31public class ExtendPositivePatternCall implements ISearchOperation, IPatternMatcherOperation {
32
33 private class Executor extends ExtendOperationExecutor<Tuple> {
34 private final VolatileModifiableMaskedTuple maskedTuple;
35
36 public Executor() {
37 maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask());
38 }
39
40 @Override
41 protected Iterator<? extends Tuple> getIterator(MatchingFrame frame, ISearchContext context) {
42 maskedTuple.updateTuple(frame);
43 IQueryResultProvider matcher = context.getMatcher(information.getCallWithAdornment());
44 return matcher.getAllMatches(information.getParameterMask(), maskedTuple).iterator();
45 }
46
47 /**
48 * @since 2.0
49 */
50 @Override
51 protected boolean fillInValue(Tuple result, MatchingFrame frame, ISearchContext context) {
52 TupleMask mask = information.getFullFrameMask();
53 // The first loop clears out the elements from a possible previous iteration
54 for(int i : information.getFreeParameterIndices()) {
55 mask.set(frame, i, null);
56 }
57 for(int i : information.getFreeParameterIndices()) {
58 Object oldValue = mask.getValue(frame, i);
59 Object valueToFill = result.get(i);
60 if (oldValue != null && !oldValue.equals(valueToFill)){
61 // If the inverse map contains more than one values for the same key, it means that these arguments are unified by the caller.
62 // In this case if the callee assigns different values the frame shall be dropped
63 return false;
64 }
65 mask.set(frame, i, valueToFill);
66 }
67 return true;
68 }
69
70 @Override
71 protected void cleanup(MatchingFrame frame, ISearchContext context) {
72 TupleMask mask = information.getFullFrameMask();
73 for(int i : information.getFreeParameterIndices()){
74 mask.set(frame, i, null);
75 }
76
77 }
78
79 @Override
80 public ISearchOperation getOperation() {
81 return ExtendPositivePatternCall.this;
82 }
83 }
84
85 private final CallInformation information;
86
87 /**
88 * @since 1.7
89 */
90 public ExtendPositivePatternCall(CallInformation information) {
91 this.information = information;
92 }
93
94 @Override
95 public ISearchOperationExecutor createExecutor() {
96 return new Executor();
97 }
98
99 @Override
100 public List<Integer> getVariablePositions() {
101 return information.getVariablePositions();
102 }
103
104 @Override
105 public String toString() {
106 return toString(Object::toString);
107 }
108
109 @Override
110 public String toString(Function<Integer, String> variableMapping) {
111 return "extend find " + information.toString(variableMapping);
112 }
113
114 @Override
115 public CallInformation getCallInformation() {
116 return information;
117 }
118}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/SingleValueExtendOperationExecutor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/SingleValueExtendOperationExecutor.java
new file mode 100644
index 00000000..a04ffcca
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/SingleValueExtendOperationExecutor.java
@@ -0,0 +1,40 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, 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.operations.extend;
10
11import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
12import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
13import tools.refinery.viatra.runtime.localsearch.operations.ExtendOperationExecutor;
14
15/**
16 * @since 2.0
17 * @noextend This class is not intended to be subclassed by clients.
18 */
19public abstract class SingleValueExtendOperationExecutor<T> extends ExtendOperationExecutor<T> {
20 protected int position;
21
22 /**
23 * @param position the frame position all values are to be added
24 */
25 public SingleValueExtendOperationExecutor(int position) {
26 super();
27 this.position = position;
28 }
29
30 @Override
31 protected final boolean fillInValue(T newValue, MatchingFrame frame, ISearchContext context) {
32 frame.setValue(position, newValue);
33 return true;
34 }
35
36 @Override
37 protected final void cleanup(MatchingFrame frame, ISearchContext context) {
38 frame.setValue(position, null);
39 }
40} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeCheck.java
new file mode 100644
index 00000000..2b189c57
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeCheck.java
@@ -0,0 +1,96 @@
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.operations.generic;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.List;
14import java.util.function.Function;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
20import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
24import tools.refinery.viatra.runtime.matchers.tuple.VolatileMaskedTuple;
25import tools.refinery.viatra.runtime.matchers.util.Preconditions;
26
27/**
28 * @author Zoltan Ujhelyi
29 * @since 1.7
30 * @noextend This class is not intended to be subclassed by clients.
31 */
32public class GenericTypeCheck implements ISearchOperation, IIteratingSearchOperation {
33
34 private class Executor extends CheckOperationExecutor {
35 private VolatileMaskedTuple maskedTuple;
36
37 private Executor() {
38 this.maskedTuple = new VolatileMaskedTuple(callMask);
39 }
40
41 @Override
42 protected boolean check(MatchingFrame frame, ISearchContext context) {
43 maskedTuple.updateTuple(frame);
44 return context.getRuntimeContext().containsTuple(type, maskedTuple);
45 }
46
47 @Override
48 public ISearchOperation getOperation() {
49 return GenericTypeCheck.this;
50 }
51 }
52
53 private final IInputKey type;
54 private final List<Integer> positionList;
55 private final TupleMask callMask;
56
57 public GenericTypeCheck(IInputKey type, int[] positions, TupleMask callMask) {
58 this.callMask = callMask;
59 Preconditions.checkArgument(positions.length == type.getArity(),
60 "The type %s requires %d parameters, but %d positions are provided", type.getPrettyPrintableName(),
61 type.getArity(), positions.length);
62 List<Integer> modifiablePositionList = new ArrayList<>();
63 for (int position : positions) {
64 modifiablePositionList.add(position);
65 }
66 this.positionList = Collections.unmodifiableList(modifiablePositionList);
67 this.type = type;
68 }
69
70 @Override
71 public List<Integer> getVariablePositions() {
72 return positionList;
73 }
74
75 @Override
76 public ISearchOperationExecutor createExecutor() {
77 return new Executor();
78 }
79
80 @Override
81 public String toString() {
82 return toString(Object::toString);
83 }
84
85 @Override
86 public String toString(Function<Integer, String> variableMapping) {
87 return "check " + type.getPrettyPrintableName() + "("
88 + positionList.stream().map(input -> String.format("+%s", variableMapping.apply(input))).collect(Collectors.joining(", "))
89 + ")";
90 }
91
92 @Override
93 public IInputKey getIteratedInputKey() {
94 return type;
95 }
96}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtend.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtend.java
new file mode 100644
index 00000000..dfc3e9ad
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtend.java
@@ -0,0 +1,145 @@
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.operations.generic;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.Objects;
16import java.util.Set;
17import java.util.function.Function;
18import java.util.stream.Collectors;
19
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.ExtendOperationExecutor;
23import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
24import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
25import tools.refinery.viatra.runtime.matchers.context.IInputKey;
26import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
27import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
28import tools.refinery.viatra.runtime.matchers.tuple.VolatileMaskedTuple;
29import tools.refinery.viatra.runtime.matchers.util.Preconditions;
30
31/**
32 * @author Zoltan Ujhelyi
33 * @since 1.7
34 * @noextend This class is not intended to be subclassed by clients.
35 */
36public class GenericTypeExtend implements IIteratingSearchOperation {
37
38 private class Executor extends ExtendOperationExecutor<Tuple> {
39 private final VolatileMaskedTuple maskedTuple;
40
41 public Executor() {
42 this.maskedTuple = new VolatileMaskedTuple(callMask);
43 }
44
45 @Override
46 protected Iterator<? extends Tuple> getIterator(MatchingFrame frame, ISearchContext context) {
47 maskedTuple.updateTuple(frame);
48 return context.getRuntimeContext().enumerateTuples(type, indexerMask, maskedTuple).iterator();
49 }
50
51 @Override
52 protected boolean fillInValue(Tuple newTuple, MatchingFrame frame, ISearchContext context) {
53 for (Integer position : unboundVariableIndices) {
54 frame.setValue(position, null);
55 }
56 for (int i = 0; i < positions.length; i++) {
57 Object newValue = newTuple.get(i);
58 Object oldValue = frame.getValue(positions[i]);
59 if (oldValue != null && !Objects.equals(oldValue, newValue)) {
60 // If positions tuple maps more than one values for the same element (e.g. loop), it means that
61 // these arguments are to unified by the caller. In this case if the callee assigns different values
62 // the frame shall be considered a failed match
63 return false;
64 }
65 frame.setValue(positions[i], newValue);
66 }
67 return true;
68 }
69
70 @Override
71 protected void cleanup(MatchingFrame frame, ISearchContext context) {
72 for (Integer position : unboundVariableIndices) {
73 frame.setValue(position, null);
74 }
75 }
76
77 @Override
78 public ISearchOperation getOperation() {
79 return GenericTypeExtend.this;
80 }
81 }
82
83 private final IInputKey type;
84 private final int[] positions;
85 private final List<Integer> positionList;
86 private final Set<Integer> unboundVariableIndices;
87 private final TupleMask indexerMask;
88 private final TupleMask callMask;
89
90 /**
91 *
92 * @param type
93 * the type to execute the extend operation on
94 * @param positions
95 * the parameter positions that represent the variables of the input key
96 * @param unboundVariableIndices
97 * the set of positions that are bound at the start of the operation
98 */
99 public GenericTypeExtend(IInputKey type, int[] positions, TupleMask callMask, TupleMask indexerMask, Set<Integer> unboundVariableIndices) {
100 Preconditions.checkArgument(positions.length == type.getArity(),
101 "The type %s requires %d parameters, but %d positions are provided", type.getPrettyPrintableName(),
102 type.getArity(), positions.length);
103 List<Integer> modifiablePositionList = new ArrayList<>();
104 for (int position : positions) {
105 modifiablePositionList.add(position);
106 }
107 this.positionList = Collections.unmodifiableList(modifiablePositionList);
108 this.positions = positions;
109 this.type = type;
110
111 this.unboundVariableIndices = unboundVariableIndices;
112 this.indexerMask = indexerMask;
113 this.callMask = callMask;
114 }
115
116 @Override
117 public IInputKey getIteratedInputKey() {
118 return type;
119 }
120
121 @Override
122 public ISearchOperationExecutor createExecutor() {
123 return new Executor();
124 }
125
126 @Override
127 public List<Integer> getVariablePositions() {
128 return positionList;
129 }
130
131 @Override
132 public String toString() {
133 return toString(Object::toString);
134 }
135
136 @Override
137 public String toString(Function<Integer, String> variableMapping) {
138 return "extend " + type.getPrettyPrintableName() + "("
139 + positionList.stream()
140 .map(input -> String.format("%s%s", unboundVariableIndices.contains(input) ? "-" : "+", variableMapping.apply(input)))
141 .collect(Collectors.joining(", "))
142 + ")";
143 }
144
145}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtendSingleValue.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtendSingleValue.java
new file mode 100644
index 00000000..45e4fd0e
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/generic/GenericTypeExtendSingleValue.java
@@ -0,0 +1,114 @@
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.operations.generic;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.Objects;
16import java.util.function.Function;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
20import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
21import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
22import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
23import tools.refinery.viatra.runtime.localsearch.operations.extend.SingleValueExtendOperationExecutor;
24import tools.refinery.viatra.runtime.matchers.context.IInputKey;
25import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
26import tools.refinery.viatra.runtime.matchers.tuple.VolatileMaskedTuple;
27import tools.refinery.viatra.runtime.matchers.util.Preconditions;
28
29/**
30 * @author Zoltan Ujhelyi
31 * @since 1.7
32 * @noextend This class is not intended to be subclassed by clients.
33 */
34public class GenericTypeExtendSingleValue implements IIteratingSearchOperation {
35
36 private class Executor extends SingleValueExtendOperationExecutor<Object> {
37
38 private final VolatileMaskedTuple maskedTuple;
39
40 public Executor(int position) {
41 super(position);
42 this.maskedTuple = new VolatileMaskedTuple(callMask);
43 }
44
45 @Override
46 protected Iterator<? extends Object> getIterator(MatchingFrame frame, ISearchContext context) {
47 maskedTuple.updateTuple(frame);
48 return context.getRuntimeContext().enumerateValues(type, indexerMask, maskedTuple).iterator();
49 }
50
51 @Override
52 public ISearchOperation getOperation() {
53 return GenericTypeExtendSingleValue.this;
54 }
55 }
56
57 private final IInputKey type;
58 private final List<Integer> positionList;
59 private final TupleMask indexerMask;
60 private final TupleMask callMask;
61 private final int unboundVariableIndex;
62
63 /**
64 *
65 * @param type
66 * the type to execute the extend operation on
67 * @param positions
68 * the parameter positions that represent the variables of the input key
69 */
70 public GenericTypeExtendSingleValue(IInputKey type, int[] positions, TupleMask callMask, TupleMask indexerMask, int unboundVariableIndex) {
71 Preconditions.checkArgument(positions.length == type.getArity(),
72 "The type %s requires %d parameters, but %d positions are provided", type.getPrettyPrintableName(),
73 type.getArity(), positions.length);
74 List<Integer> modifiablePositionList = new ArrayList<>();
75 for (int position : positions) {
76 modifiablePositionList.add(position);
77 }
78 this.unboundVariableIndex = unboundVariableIndex;
79 this.positionList = Collections.unmodifiableList(modifiablePositionList);
80 this.type = type;
81
82 this.callMask = callMask;
83 this.indexerMask = indexerMask;
84 }
85
86 @Override
87 public IInputKey getIteratedInputKey() {
88 return type;
89 }
90
91 @Override
92 public ISearchOperationExecutor createExecutor() {
93 return new Executor(unboundVariableIndex);
94 }
95
96 @Override
97 public List<Integer> getVariablePositions() {
98 return positionList;
99 }
100
101 @Override
102 public String toString() {
103 return toString(Object::toString);
104 }
105
106 @Override
107 public String toString(Function<Integer, String> variableMapping) {
108 return "extend " + type.getPrettyPrintableName() + "("
109 + positionList.stream().map(
110 input -> String.format("%s%s", Objects.equals(input, unboundVariableIndex) ? "-" : "+", variableMapping.apply(input)))
111 .collect(Collectors.joining(", "))
112 + ")";
113 }
114}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/util/CallInformation.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/util/CallInformation.java
new file mode 100644
index 00000000..b141a7b0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/util/CallInformation.java
@@ -0,0 +1,186 @@
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.operations.util;
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.function.Function;
18import java.util.stream.Collectors;
19
20import tools.refinery.viatra.runtime.localsearch.matcher.CallWithAdornment;
21import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
22import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
23import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.PatternCallBasedDeferred;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryReflexiveTransitiveClosure;
26import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
27import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
29import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
30import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
31import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
32
33/**
34 * This class stores a precompiled version of call-related metadata and masks for local search operations
35 *
36 * @author Zoltan Ujhelyi
37 * @since 1.7
38 */
39public final class CallInformation {
40
41 private final TupleMask fullFrameMask;
42 private final TupleMask thinFrameMask;
43 private final TupleMask parameterMask;
44 private final int[] freeParameterIndices;
45
46 private final Map<PParameter, Integer> mapping = new HashMap<>();
47 private final Set<PParameter> adornment = new HashSet<>();
48 private final PQuery referredQuery;
49 private final MatcherReference matcherReference;
50 private final IQueryReference call;
51 private CallWithAdornment callWithAdornment;
52
53 public static CallInformation create(PatternCallBasedDeferred constraint, Map<PVariable, Integer> variableMapping, Set<Integer> bindings) {
54 return new CallInformation(constraint.getActualParametersTuple(), constraint, bindings, variableMapping);
55 }
56
57 public static CallInformation create(PositivePatternCall pCall, Map<PVariable, Integer> variableMapping, Set<Integer> bindings) {
58 return new CallInformation(pCall.getVariablesTuple(), pCall, bindings, variableMapping);
59 }
60
61 public static CallInformation create(BinaryTransitiveClosure constraint, Map<PVariable, Integer> variableMapping, Set<Integer> bindings) {
62 return new CallInformation(constraint.getVariablesTuple(), constraint, bindings, variableMapping);
63 }
64
65 /**
66 * @since 2.0
67 */
68 public static CallInformation create(BinaryReflexiveTransitiveClosure constraint, Map<PVariable, Integer> variableMapping, Set<Integer> bindings) {
69 return new CallInformation(constraint.getVariablesTuple(), constraint, bindings, variableMapping);
70 }
71
72 private CallInformation(Tuple actualParameters, IQueryReference call, final Set<Integer> bindings,
73 Map<PVariable, Integer> variableMapping) {
74 this.call = call;
75 this.referredQuery = call.getReferredQuery();
76 int keySize = actualParameters.getSize();
77 List<Integer> parameterMaskIndices = new ArrayList<>();
78 int[] fullParameterMaskIndices = new int[keySize];
79 for (int i = 0; i < keySize; i++) {
80 PParameter symbolicParameter = referredQuery.getParameters().get(i);
81 PVariable parameter = (PVariable) actualParameters.get(i);
82 Integer originalFrameIndex = variableMapping.get(parameter);
83 mapping.put(symbolicParameter, originalFrameIndex);
84 fullParameterMaskIndices[i] = originalFrameIndex;
85 if (bindings.contains(originalFrameIndex)) {
86 parameterMaskIndices.add(originalFrameIndex);
87 adornment.add(symbolicParameter);
88 }
89 }
90
91 thinFrameMask = TupleMask.fromSelectedIndices(variableMapping.size(), parameterMaskIndices);
92 fullFrameMask = TupleMask.fromSelectedIndices(variableMapping.size(), fullParameterMaskIndices);
93
94 // This second iteration is necessary as we don't know beforehand the number of bound parameters
95 int[] boundParameterIndices = new int[adornment.size()];
96 int boundIndex = 0;
97 freeParameterIndices = new int[keySize - adornment.size()];
98 int freeIndex = 0;
99 for (int i = 0; i < keySize; i++) {
100 if (bindings.contains(variableMapping.get(actualParameters.get(i)))) {
101 boundParameterIndices[boundIndex] = i;
102 boundIndex++;
103 } else {
104 freeParameterIndices[freeIndex] = i;
105 freeIndex++;
106 }
107 }
108 parameterMask = TupleMask.fromSelectedIndices(keySize, boundParameterIndices);
109 callWithAdornment = new CallWithAdornment(call, adornment);
110 matcherReference = callWithAdornment.getMatcherReference();
111 }
112
113 /**
114 * Returns a mask describing how the bound variables of a Matching Frame are mapped to parameter indexes
115 */
116 public TupleMask getThinFrameMask() {
117 return thinFrameMask;
118 }
119
120 /**
121 * Returns a mask describing how all variables of a Matching Frame are mapped to parameter indexes
122 */
123 public TupleMask getFullFrameMask() {
124 return fullFrameMask;
125 }
126
127 /**
128 * Returns a mask describing the adornment the called pattern uses
129 */
130 public TupleMask getParameterMask() {
131 return parameterMask;
132 }
133
134 public MatcherReference getReference() {
135 return matcherReference;
136 }
137
138 /**
139 * @since 2.1
140 */
141 public IQueryReference getCall() {
142 return call;
143 }
144
145 /**
146 * @since 2.1
147 */
148 public CallWithAdornment getCallWithAdornment() {
149 return callWithAdornment;
150 }
151
152 /**
153 * Returns the parameter indices that are unbound before the call
154 */
155 public int[] getFreeParameterIndices() {
156 return freeParameterIndices;
157 }
158
159 public List<Integer> getVariablePositions() {
160 List<Integer> variables = new ArrayList<>(mapping.size());
161 for(PParameter p : referredQuery.getParameters()){
162 variables.add(mapping.get(p));
163 }
164 return variables;
165 }
166
167
168
169 @Override
170 public String toString() {
171 return toString(Object::toString);
172 }
173
174 /**
175 * @since 2.0
176 */
177 public String toString(Function<Integer, String> variableMapping) {
178 return referredQuery.getFullyQualifiedName() + "("
179 + referredQuery.getParameters().stream().map(
180 input -> (adornment.contains(input) ? "+" : "-") + variableMapping.apply(mapping.get(input)))
181 .collect(Collectors.joining(","))
182 + ")";
183 }
184
185
186}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanDescriptor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanDescriptor.java
new file mode 100644
index 00000000..987996c9
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanDescriptor.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.plan;
10
11import java.util.Collection;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IInputKey;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * Denotes an executable plan
20 *
21 * @author Grill Balázs
22 * @since 1.4
23 *
24 */
25public interface IPlanDescriptor {
26
27 /**
28 * The query which this plan implements
29 */
30 public PQuery getQuery();
31
32 /**
33 * The executable search plans for each body in the query
34 * @since 2.0
35 */
36 public Collection<SearchPlanForBody> getPlan();
37
38 /**
39 * The set of parameters this plan assumes to be bound
40 */
41 public Set<PParameter> getAdornment();
42
43 /**
44 * The collection of {@link IInputKey}s which needs to be iterated during the execution of this plan. For optimal
45 * performance, instances of these keys might be indexed.
46 */
47 public Set<IInputKey> getIteratedKeys();
48
49}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanProvider.java
new file mode 100644
index 00000000..b74282ca
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/IPlanProvider.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.plan;
10
11import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
12import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHints;
13import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
16import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
17
18/**
19 * @author Grill Balázs
20 * @since 1.4
21 * @noreference This interface is not intended to be referenced by clients.
22 */
23public interface IPlanProvider {
24
25 /**
26 * @throws ViatraQueryRuntimeException
27 * @since 2.1
28 */
29 public IPlanDescriptor getPlan(IQueryBackendContext backend, IOperationCompiler compiler,
30 ResultProviderRequestor resultProviderRequestor,
31 LocalSearchHints configuration, MatcherReference key);
32
33}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/PlanDescriptor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/PlanDescriptor.java
new file mode 100644
index 00000000..a5565546
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/PlanDescriptor.java
@@ -0,0 +1,84 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.plan;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Set;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
20import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
21import tools.refinery.viatra.runtime.matchers.context.IInputKey;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
23import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
24
25/**
26 * @author Grill Balázs
27 * @since 1.4
28 *
29 */
30public class PlanDescriptor implements IPlanDescriptor {
31
32 private final PQuery pquery;
33 private final List<SearchPlanForBody> plan;
34 private final Set<PParameter> adornment;
35 private Set<IInputKey> iteratedKeys = null;
36
37 public PlanDescriptor(PQuery pquery, Collection<SearchPlanForBody> plan, Set<PParameter> adornment) {
38 this.pquery = pquery;
39 this.plan = new ArrayList<>(plan);
40 this.adornment = adornment;
41 }
42
43 @Override
44 public PQuery getQuery() {
45 return pquery;
46 }
47
48 @Override
49 public Collection<SearchPlanForBody> getPlan() {
50 return plan;
51 }
52
53 @Override
54 public Set<PParameter> getAdornment() {
55 return adornment;
56 }
57
58 @Override
59 public Set<IInputKey> getIteratedKeys() {
60 if (iteratedKeys == null){
61 Set<IInputKey> keys = new HashSet<>();
62 for(SearchPlanForBody bodyPlan : plan){
63 for(ISearchOperation operation : bodyPlan.getCompiledOperations()){
64 if (operation instanceof IIteratingSearchOperation){
65 keys.add(((IIteratingSearchOperation) operation).getIteratedInputKey());
66 }
67 }
68 }
69 iteratedKeys = Collections.unmodifiableSet(keys);
70 }
71 return iteratedKeys;
72 }
73
74 @Override
75 public String toString() {
76 return new StringBuilder().append("Plan for ").append(pquery.getFullyQualifiedName()).append("(")
77 .append(adornment.stream().map(PParameter::getName).collect(Collectors.joining(",")))
78 .append("{")
79 .append(plan.stream().map(Object::toString).collect(Collectors.joining("}\n{")))
80 .append("}")
81 .toString();
82 }
83
84}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlan.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlan.java
new file mode 100644
index 00000000..3159f707
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlan.java
@@ -0,0 +1,99 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, 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.localsearch.plan;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.List;
14import java.util.Map;
15import java.util.Map.Entry;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22
23/**
24 * A SearchPlan stores a collection of SearchPlanOperations for a fixed order of variables.
25 *
26 * @author Zoltan Ujhelyi
27 *
28 */
29public class SearchPlan {
30
31 private final List<ISearchOperation> operations;
32 private final Map<Integer, PVariable> variableMapping;
33 private final TupleMask parameterMask;
34 private final PBody body;
35
36 /**
37 * @since 2.0
38 */
39 public SearchPlan(PBody body, List<ISearchOperation> operations, TupleMask parameterMask, Map<PVariable, Integer> variableMapping) {
40 this.body = body;
41 this.operations = Collections.unmodifiableList(new ArrayList<>(operations));
42 this.parameterMask = parameterMask;
43 this.variableMapping = Collections.unmodifiableMap(variableMapping.entrySet().stream()
44 .collect(Collectors.toMap(Entry::getValue, Entry::getKey)));
45 }
46
47
48 /**
49 * Returns an immutable list of operations stored in the plan.
50 * @return the operations
51 */
52 public List<ISearchOperation> getOperations() {
53 return operations;
54 }
55
56 /**
57 * Returns an immutable map of variable mappings for the plan
58 * @since 2.0
59 */
60 public Map<Integer, PVariable> getVariableMapping() {
61 return variableMapping;
62 }
63
64 /**
65 * Returns the index of a given operation in the plan
66 * @since 2.0
67 */
68 public int getOperationIndex(ISearchOperation operation) {
69 return operations.indexOf(operation);
70 }
71
72 /**
73 * @since 2.0
74 */
75 public TupleMask getParameterMask() {
76 return parameterMask;
77 }
78
79 /**
80 * @since 2.0
81 */
82 public PBody getSourceBody() {
83 return body;
84 }
85
86 @Override
87 public String toString() {
88 StringBuilder sb = new StringBuilder();
89
90 sb.append("{\n");
91 for(ISearchOperation operation : this.getOperations()){
92 sb.append("\t");
93 sb.append(operation);
94 sb.append("\n");
95 }
96 sb.append("}");
97 return sb.toString();
98 }
99}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanExecutor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanExecutor.java
new file mode 100644
index 00000000..4a4e2450
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanExecutor.java
@@ -0,0 +1,210 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Akos Horvath, Gergely Varro Zoltan Ujhelyi 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 *******************************************************************************/
9
10 package tools.refinery.viatra.runtime.localsearch.plan;
11
12
13import java.util.Collections;
14import java.util.List;
15import java.util.Map;
16import java.util.concurrent.CopyOnWriteArrayList;
17import java.util.stream.Collectors;
18
19import org.apache.log4j.Logger;
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
22import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdaptable;
23import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter;
24import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
25import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
26import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation.ISearchOperationExecutor;
27import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
28import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
29import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
30import tools.refinery.viatra.runtime.matchers.util.Preconditions;
31
32/**
33 * A search plan executor is used to execute {@link SearchPlan} instances.
34 * @noinstantiate This class is not intended to be instantiated by clients.
35 */
36public class SearchPlanExecutor implements ILocalSearchAdaptable {
37
38 private int currentOperation;
39 private final List<ISearchOperationExecutor> operations;
40 private final SearchPlan plan;
41 private final ISearchContext context;
42 private final List<ILocalSearchAdapter> adapters = new CopyOnWriteArrayList<>();
43
44 /**
45 * @since 2.0
46 */
47 public Map<Integer, PVariable> getVariableMapping() {
48 return plan.getVariableMapping();
49 }
50
51 public int getCurrentOperation() {
52 return currentOperation;
53 }
54
55 public SearchPlan getSearchPlan() {
56 return plan;
57 }
58
59 /**
60 * @since 1.7
61 */
62 public TupleMask getParameterMask() {
63 return plan.getParameterMask();
64 }
65
66 @Override
67 public void addAdapters(List<ILocalSearchAdapter> adapters) {
68 for(ILocalSearchAdapter adapter : adapters){
69 if (!this.adapters.contains(adapter)){
70 this.adapters.add(adapter);
71 adapter.adapterRegistered(this);
72 }
73 }
74 }
75
76 @Override
77 public void removeAdapters(List<ILocalSearchAdapter> adapters) {
78 for (ILocalSearchAdapter adapter : adapters) {
79 if (this.adapters.remove(adapter)){
80 adapter.adapterUnregistered(this);
81 }
82 }
83 }
84
85 /**
86 * @since 2.0
87 */
88 public SearchPlanExecutor(SearchPlan plan, ISearchContext context) {
89 Preconditions.checkArgument(context != null, "Context cannot be null");
90 this.plan = plan;
91 this.context = context;
92 operations = plan.getOperations().stream().map(ISearchOperation::createExecutor).collect(Collectors.toList());
93 this.currentOperation = -1;
94 }
95
96
97 private void init(MatchingFrame frame) {
98 if (currentOperation == -1) {
99 currentOperation++;
100 ISearchOperationExecutor operation = operations.get(currentOperation);
101 if (!adapters.isEmpty()){
102 for (ILocalSearchAdapter adapter : adapters) {
103 adapter.executorInitializing(plan, frame);
104 }
105 }
106 operation.onInitialize(frame, context);
107 } else if (currentOperation == operations.size()) {
108 currentOperation--;
109 } else {
110 throw new LocalSearchException(LocalSearchException.PLAN_EXECUTION_ERROR);
111 }
112 }
113
114
115 /**
116 * Calculates the cost of the search plan.
117 */
118 public double cost() {
119 /* default generated stub */
120 return 0.0;
121 }
122
123 /**
124 * @throws ViatraQueryRuntimeException
125 */
126 public boolean execute(MatchingFrame frame) {
127 int upperBound = operations.size() - 1;
128 init(frame);
129 operationSelected(frame, currentOperation, false);
130 while (currentOperation >= 0 && currentOperation <= upperBound) {
131 if (operations.get(currentOperation).execute(frame, context)) {
132 operationExecuted(frame, currentOperation, true);
133 currentOperation++;
134 operationSelected(frame, currentOperation, false);
135 if (currentOperation <= upperBound) {
136 ISearchOperationExecutor operation = operations.get(currentOperation);
137 operation.onInitialize(frame, context);
138 }
139 } else {
140 operationExecuted(frame, currentOperation, false);
141 ISearchOperationExecutor operation = operations.get(currentOperation);
142 operation.onBacktrack(frame, context);
143 currentOperation--;
144 operationSelected(frame, currentOperation, true);
145 }
146 }
147 boolean matchFound = currentOperation > upperBound;
148 if (matchFound && !adapters.isEmpty()) {
149 for (ILocalSearchAdapter adapter : adapters) {
150 adapter.matchFound(plan, frame);
151 }
152 }
153 return matchFound;
154 }
155
156 public void resetPlan() {
157 currentOperation = -1;
158 }
159
160 public void printDebugInformation() {
161 for (int i = 0; i < operations.size(); i++) {
162 Logger.getRootLogger().debug("[" + i + "]\t" + operations.get(i).toString());
163 }
164 }
165
166 private void operationExecuted(MatchingFrame frame, int operationIndex, boolean isSuccessful) {
167 if (!adapters.isEmpty()){
168 for (ILocalSearchAdapter adapter : adapters) {
169 adapter.operationExecuted(plan, operations.get(operationIndex).getOperation(), frame, isSuccessful);
170 }
171 }
172 }
173
174 private void operationSelected(MatchingFrame frame, int operationIndex, boolean isBacktrack) {
175 if (!adapters.isEmpty() && operationIndex >= 0 && operationIndex < operations.size()){
176 for (ILocalSearchAdapter adapter : adapters) {
177 adapter.operationSelected(plan, operations.get(operationIndex).getOperation(), frame, isBacktrack);
178 }
179 }
180 }
181
182 public ISearchContext getContext() {
183 return context;
184 }
185
186 @Override
187 public List<ILocalSearchAdapter> getAdapters() {
188 return Collections.<ILocalSearchAdapter>unmodifiableList(this.adapters);
189 }
190
191 @Override
192 public void addAdapter(ILocalSearchAdapter adapter) {
193 addAdapters(Collections.singletonList(adapter));
194 }
195
196 @Override
197 public void removeAdapter(ILocalSearchAdapter adapter) {
198 removeAdapters(Collections.singletonList(adapter));
199 }
200
201 @Override
202 public String toString() {
203 if (operations == null) {
204 return "Unspecified plan";
205 } else {
206 return operations.stream().map(Object::toString).collect(Collectors.joining("\n"));
207 }
208 }
209
210}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanForBody.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanForBody.java
new file mode 100644
index 00000000..e0300da4
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SearchPlanForBody.java
@@ -0,0 +1,115 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, 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.plan;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.List;
15import java.util.Map;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.localsearch.matcher.CallWithAdornment;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
23import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
24
25/**
26 * This class is responsible for storing the results of the planner and operation compiler for a selected body.
27 * @since 2.0
28 * @noinstantiate This class is not intended to be instantiated by clients.
29 */
30public class SearchPlanForBody {
31
32 private final PBody body;
33 private final Map<PVariable, Integer> variableKeys;
34 private final int[] parameterKeys;
35 private final SubPlan plan;
36 private final List<ISearchOperation> compiledOperations;
37 private final Collection<CallWithAdornment> dependencies;
38 private final double cost;
39 private final Object internalRepresentation;
40
41 /**
42 * @since 2.1
43 */
44 public SearchPlanForBody(PBody body, Map<PVariable, Integer> variableKeys,
45 SubPlan plan, List<ISearchOperation> compiledOperations, Collection<CallWithAdornment> dependencies,
46 Object internalRepresentation, double cost) {
47 super();
48 this.body = body;
49 this.variableKeys = variableKeys;
50 this.plan = plan;
51 this.internalRepresentation = internalRepresentation;
52 this.cost = cost;
53 List<PVariable> parameters = body.getSymbolicParameterVariables();
54 parameterKeys = new int[parameters.size()];
55 for (int i=0; i<parameters.size(); i++) {
56 parameterKeys[i] = variableKeys.get(parameters.get(i));
57 }
58 this.compiledOperations = new ArrayList<>(compiledOperations.size()+1);
59 this.compiledOperations.addAll(compiledOperations);
60
61 this.dependencies = new ArrayList<>(dependencies);
62 }
63
64 public PBody getBody() {
65 return body;
66 }
67
68 public Map<PVariable, Integer> getVariableKeys() {
69 return variableKeys;
70 }
71
72 public int[] getParameterKeys() {
73 return Arrays.copyOf(parameterKeys, parameterKeys.length);
74 }
75
76 public List<ISearchOperation> getCompiledOperations() {
77 return compiledOperations;
78 }
79
80 public SubPlan getPlan() {
81 return plan;
82 }
83
84 public Collection<CallWithAdornment> getDependencies() {
85 return dependencies;
86 }
87
88 public TupleMask calculateParameterMask() {
89 return TupleMask.fromSelectedIndices(variableKeys.size(), parameterKeys);
90 }
91
92 @Override
93 public String toString() {
94 return compiledOperations.stream().map(Object::toString).collect(Collectors.joining("\n"));
95 }
96
97 /**
98 * @since 2.1
99 */
100 public double getCost() {
101 return cost;
102 }
103
104 /**
105 * @return The internal representation of the search plan, if any, for traceability
106 * @since 2.1
107 */
108 public Object getInternalRepresentation() {
109 return internalRepresentation;
110 }
111
112
113
114
115}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SimplePlanProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SimplePlanProvider.java
new file mode 100644
index 00000000..ed31bcb0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/plan/SimplePlanProvider.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.plan;
10
11import java.util.Collection;
12
13import org.apache.log4j.Logger;
14import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
15import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHints;
16import tools.refinery.viatra.runtime.localsearch.planner.LocalSearchPlanner;
17import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
18import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
19import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
20
21/**
22 * A plan provider implementation which caches previously calculated plans to avoid re-planning for the same adornment
23 *
24 * @author Grill Balázs
25 * @since 1.7
26 *
27 */
28public class SimplePlanProvider implements IPlanProvider {
29
30 private final Logger logger;
31
32 public SimplePlanProvider(Logger logger) {
33 this.logger = logger;
34 }
35
36 @Override
37 public IPlanDescriptor getPlan(IQueryBackendContext backend, IOperationCompiler compiler,
38 final ResultProviderRequestor resultRequestor,
39 final LocalSearchHints configuration, MatcherReference key) {
40
41 LocalSearchPlanner planner = new LocalSearchPlanner(backend, compiler, logger, configuration, resultRequestor);
42
43 Collection<SearchPlanForBody> plansForBodies = planner.plan(key.getQuery(), key.getAdornment());
44
45 IPlanDescriptor plan = new PlanDescriptor(key.getQuery(), plansForBodies, key.getAdornment());
46 return plan;
47 }
48
49}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ILocalSearchPlanner.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ILocalSearchPlanner.java
new file mode 100644
index 00000000..dfd9a3c8
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ILocalSearchPlanner.java
@@ -0,0 +1,38 @@
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;
10
11import java.util.Collection;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.localsearch.plan.SearchPlanForBody;
15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18
19/**
20 * @author Zoltan Ujhelyi
21 * @since 1.7
22 */
23public interface ILocalSearchPlanner {
24
25 /**
26 * Creates executable plans for the provided query. It is required to call one of the
27 * <code>initializePlanner()</code> methods before calling this method.
28 *
29 * @param querySpec
30 * @param boundParameters
31 * a set of bound parameters
32 * @return a mapping between ISearchOperation list and a mapping, that holds a PVariable-Integer mapping for the
33 * list of ISearchOperations
34 * @throws ViatraQueryRuntimeException
35 */
36 Collection<SearchPlanForBody> plan(PQuery querySpec, Set<PParameter> boundParameters);
37
38} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ISearchPlanCodeGenerator.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ISearchPlanCodeGenerator.java
new file mode 100644
index 00000000..72218337
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/ISearchPlanCodeGenerator.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.planner;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
14
15/**
16 * @author Marton Bur
17 *
18 */
19public interface ISearchPlanCodeGenerator {
20
21 void compile(List<List<ISearchOperation>> plans);
22
23}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchPlanner.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchPlanner.java
new file mode 100644
index 00000000..f44be655
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchPlanner.java
@@ -0,0 +1,140 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.planner;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18
19import org.apache.log4j.Logger;
20import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHints;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.localsearch.plan.SearchPlanForBody;
23import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
24import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
25import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
26import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
27import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
28import tools.refinery.viatra.runtime.matchers.psystem.PBody;
29import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
30import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
31import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
32import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
33import tools.refinery.viatra.runtime.matchers.psystem.rewriters.PBodyNormalizer;
34import tools.refinery.viatra.runtime.matchers.psystem.rewriters.PDisjunctionRewriter;
35import tools.refinery.viatra.runtime.matchers.psystem.rewriters.PDisjunctionRewriterCacher;
36import tools.refinery.viatra.runtime.matchers.psystem.rewriters.PQueryFlattener;
37
38/**
39 *
40 * @author Marton Bur
41 * @noreference This class is not intended to be referenced by clients.
42 */
43public class LocalSearchPlanner implements ILocalSearchPlanner {
44
45 // Externally set tools for planning
46 private final PDisjunctionRewriter preprocessor;
47 private final LocalSearchRuntimeBasedStrategy plannerStrategy;
48 private final IQueryRuntimeContext runtimeContext;
49 private final LocalSearchHints configuration;
50 private final IOperationCompiler operationCompiler;
51 private final IQueryBackendContext context;
52 private final ResultProviderRequestor resultRequestor;
53
54 /**
55 * @param resultRequestor
56 * @since 1.7
57 */
58 public LocalSearchPlanner(IQueryBackendContext backendContext, IOperationCompiler compiler, Logger logger,
59 final LocalSearchHints configuration, ResultProviderRequestor resultRequestor)
60 {
61
62 this.runtimeContext = backendContext.getRuntimeContext();
63 this.configuration = configuration;
64 this.operationCompiler = compiler;
65 this.resultRequestor = resultRequestor;
66 PQueryFlattener flattener = new PQueryFlattener(configuration.getFlattenCallPredicate());
67 /*
68 * TODO https://bugs.eclipse.org/bugs/show_bug.cgi?id=439358: The normalizer is initialized with the false
69 * parameter to turn off unary constraint elimination to work around an issue related to plan ordering: the
70 * current implementation of the feature target checking operations expect that the source types were checked
71 * before. However, this causes duplicate constraint checks in the search plan that might affect performance
72 * negatively.
73 */
74 PBodyNormalizer normalizer = new PBodyNormalizer(runtimeContext.getMetaContext()) {
75
76 @Override
77 protected boolean shouldCalculateImpliedTypes(PQuery query) {
78 return false;
79 }
80 };
81 preprocessor = new PDisjunctionRewriterCacher(flattener, normalizer);
82
83 plannerStrategy = new LocalSearchRuntimeBasedStrategy();
84
85 context = backendContext;
86 }
87
88 /**
89 * Creates executable plans for the provided query. It is required to call one of the
90 * <code>initializePlanner()</code> methods before calling this method.
91 *
92 * @param querySpec
93 * @param boundParameters
94 * a set of bound parameters
95 * @return a mapping between ISearchOperation list and a mapping, that holds a PVariable-Integer mapping for the
96 * list of ISearchOperations
97 */
98 @Override
99 public Collection<SearchPlanForBody> plan(PQuery querySpec, Set<PParameter> boundParameters) {
100 // 1. Preparation
101 preprocessor.setTraceCollector(configuration.getTraceCollector());
102 Set<PBody> normalizedBodies = preprocessor.rewrite(querySpec.getDisjunctBodies()).getBodies();
103
104 List<SearchPlanForBody> plansForBodies = new ArrayList<>(normalizedBodies.size());
105
106 for (PBody normalizedBody : normalizedBodies) {
107 // 2. Plan creation
108 // Context has matchers for the referred Queries (IQuerySpecifications)
109 Set<PVariable> boundVariables = calculatePatternAdornmentForPlanner(boundParameters, normalizedBody);
110 PlanState searchPlanInternal = plannerStrategy.plan(normalizedBody, boundVariables, context, resultRequestor, configuration);
111 SubPlan plan = plannerStrategy.convertPlan(boundVariables, searchPlanInternal);
112 // 3. PConstraint -> POperation compilation step
113 // * Pay extra caution to extend operations, when more than one variables are unbound
114 List<ISearchOperation> compiledOperations = operationCompiler.compile(plan, boundParameters);
115 // Store the variable mappings for the plans for debug purposes (traceability information)
116 SearchPlanForBody compiledPlan = new SearchPlanForBody(normalizedBody,
117 operationCompiler.getVariableMappings(), plan, compiledOperations,
118 operationCompiler.getDependencies(),
119 searchPlanInternal, searchPlanInternal.getCost());
120
121 plansForBodies.add(compiledPlan);
122 }
123
124 return plansForBodies;
125 }
126
127 private Set<PVariable> calculatePatternAdornmentForPlanner(Set<PParameter> boundParameters, PBody normalizedBody) {
128 Map<PParameter, PVariable> parameterMapping = new HashMap<>();
129 for (ExportedParameter constraint : normalizedBody.getSymbolicParameters()) {
130 parameterMapping.put(constraint.getPatternParameter(), constraint.getParameterVariable());
131 }
132 Set<PVariable> boundVariables = new HashSet<>();
133 for (PParameter parameter : boundParameters) {
134 PVariable mappedParameter = parameterMapping.get(parameter);
135 boundVariables.add(mappedParameter);
136 }
137 return boundVariables;
138 }
139
140}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchRuntimeBasedStrategy.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchRuntimeBasedStrategy.java
new file mode 100644
index 00000000..1bebe37e
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/LocalSearchRuntimeBasedStrategy.java
@@ -0,0 +1,257 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.planner;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHints;
20import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
21import tools.refinery.viatra.runtime.localsearch.planner.util.OperationCostComparator;
22import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
23import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
24import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
25import tools.refinery.viatra.runtime.matchers.planning.SubPlanFactory;
26import tools.refinery.viatra.runtime.matchers.planning.operations.PApply;
27import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
28import tools.refinery.viatra.runtime.matchers.planning.operations.PStart;
29import tools.refinery.viatra.runtime.matchers.psystem.PBody;
30import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
31import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
32import tools.refinery.viatra.runtime.matchers.util.Sets;
33
34/**
35 * This class contains the logic for local search plan calculation based on costs of the operations.
36 * Its name refers to the fact that the strategy tries to use as much information as available about
37 * the model on which the matching is initiated. When no runtime info is available, it falls back to
38 * the information available from the metamodel durint operation cost calculation.
39 *
40 * The implementation is based on the paper "Gergely Varró, Frederik Deckwerth, Martin Wieber, and Andy Schürr:
41 * An algorithm for generating model-sensitive search plans for pattern matching on EMF models"
42 * (DOI: 10.1007/s10270-013-0372-2)
43 *
44 * @author Marton Bur
45 * @noreference This class is not intended to be referenced by clients.
46 */
47public class LocalSearchRuntimeBasedStrategy {
48
49 private final OperationCostComparator infoComparator = new OperationCostComparator();
50
51
52 /**
53 * Converts a plan to the standard format
54 */
55 protected SubPlan convertPlan(Set<PVariable> initialBoundVariables, PlanState searchPlan) {
56 PBody pBody;
57 pBody = searchPlan.getAssociatedPBody();
58
59 // Create a starting plan
60 SubPlanFactory subPlanFactory = new SubPlanFactory(pBody);
61
62 // We assume that the adornment (now the bound variables) is previously set
63 SubPlan plan = subPlanFactory.createSubPlan(new PStart(initialBoundVariables));
64
65 List<PConstraintInfo> operations = searchPlan.getOperations();
66 for (PConstraintInfo pConstraintPlanInfo : operations) {
67 PConstraint pConstraint = pConstraintPlanInfo.getConstraint();
68 plan = subPlanFactory.createSubPlan(new PApply(pConstraint), plan);
69 }
70
71 return subPlanFactory.createSubPlan(new PProject(pBody.getSymbolicParameterVariables()), plan);
72 }
73
74 /**
75 * The implementation of a local search-based algorithm to create a search plan for a flattened (and normalized)
76 * PBody
77 * @param pBody for which the plan is to be created
78 * @param initialBoundVariables variables that are known to have already assigned values
79 * @param context the backend context
80 * @param resultProviderRequestor requestor for accessing result providers of called patterns
81 * @param configuration the planner configuration
82 * @return the complete search plan for the given {@link PBody}
83 * @since 2.1
84 */
85 protected PlanState plan(PBody pBody, Set<PVariable> initialBoundVariables,
86 IQueryBackendContext context, final ResultProviderRequestor resultProviderRequestor,
87 LocalSearchHints configuration) {
88 final ICostFunction costFunction = configuration.getCostFunction();
89 PConstraintInfoInferrer pConstraintInfoInferrer = new PConstraintInfoInferrer(
90 configuration.isUseBase(), context, resultProviderRequestor, costFunction::apply);
91
92 // Create mask infos
93 Set<PConstraint> constraintSet = pBody.getConstraints();
94 List<PConstraintInfo> constraintInfos =
95 pConstraintInfoInferrer.createPConstraintInfos(constraintSet);
96
97 // Calculate the characteristic function
98 // The characteristic function tells whether a given adornment is backward reachable from the (B)* state, where
99 // each variable is bound.
100 // The characteristic function is represented as a set of set of variables
101 // TODO this calculation is not not implemented yet, thus the contents of the returned set is not considered later
102 List<Set<PVariable>> reachableBoundVariableSets = reachabilityAnalysis(pBody, constraintInfos);
103 int k = configuration.getRowCount();
104 PlanState searchPlan = calculateSearchPlan(pBody, initialBoundVariables, k, reachableBoundVariableSets, constraintInfos);
105 return searchPlan;
106 }
107
108 private PlanState calculateSearchPlan(PBody pBody, Set<PVariable> initialBoundVariables, int k,
109 List<Set<PVariable>> reachableBoundVariableSets, List<PConstraintInfo> allMaskInfos) {
110
111 List<PConstraintInfo> allPotentialExtendInfos = new ArrayList<>();
112 List<PConstraintInfo> allPotentialCheckInfos = new ArrayList<>();
113 Map<PVariable, List<PConstraintInfo>> checkOpsByVariables = new HashMap<>();
114 Map<PVariable, Collection<PConstraintInfo>> extendOpsByBoundVariables = new HashMap<>();
115
116 for (PConstraintInfo op : allMaskInfos) {
117 if (op.getFreeVariables().isEmpty()) { // CHECK
118 allPotentialCheckInfos.add(op);
119 } else { // EXTEND
120 allPotentialExtendInfos.add(op);
121 for (PVariable variable : op.getBoundVariables()) {
122 extendOpsByBoundVariables.computeIfAbsent(variable, v -> new ArrayList<>()).add(op);
123 }
124 }
125 }
126 // For CHECKs only, we must start from lists that are ordered by the cost of the constraint application
127 Collections.sort(allPotentialCheckInfos, infoComparator); // costs are eagerly needed for check ops
128 for (PConstraintInfo op : allPotentialCheckInfos) {
129 for (PVariable variable : op.getBoundVariables()) {
130 checkOpsByVariables.computeIfAbsent(variable, v -> new ArrayList<>()).add(op);
131 }
132 }
133 // costs are not needed for extend ops until they are first applied (TODO make cost computaiton on demand)
134
135
136 // rename for better understanding
137 Set<PVariable> boundVariables = initialBoundVariables;
138 Set<PVariable> freeVariables = Sets.difference(pBody.getUniqueVariables(), initialBoundVariables);
139
140 int variableCount = pBody.getUniqueVariables().size();
141 int n = freeVariables.size();
142
143 List<List<PlanState>> stateTable = initializeStateTable(k, n);
144
145 // Set initial state: begin with an empty operation list
146 PlanState initialState = new PlanState(pBody, boundVariables);
147
148 // Initial state creation, categorizes all operations; add present checks to operationsList
149 initialState.updateExtends(allPotentialExtendInfos);
150 initialState.applyChecks(allPotentialCheckInfos);
151 stateTable.get(n).add(0, initialState);
152
153 // stateTable.get(0) will contain the states with adornment B*
154 for (int i = n; i > 0; i--) {
155 for (int j = 0; j < k && j < stateTable.get(i).size(); j++) {
156 PlanState currentState = stateTable.get(i).get(j);
157
158 for (PConstraintInfo constraintInfo : currentState.getPresentExtends()) {
159 // for each present EXTEND operation
160 PlanState newState = calculateNextState(currentState, constraintInfo);
161 // also eagerly perform any CHECK operations that become applicable (extends still deferred)
162 newState.applyChecksBasedOnDelta(checkOpsByVariables);
163
164 if(currentState.getBoundVariables().size() == newState.getBoundVariables().size()){
165 // This means no variable binding was done, go on with the next constraint info
166 continue;
167 }
168 int i2 = variableCount - newState.getBoundVariables().size();
169
170 List<Integer> newIndices = determineIndices(stateTable, i2, newState, k);
171 int a = newIndices.get(0);
172 int c = newIndices.get(1);
173
174 if (checkInsertCondition(stateTable.get(i2), newState, reachableBoundVariableSets, a, c, k)) {
175 updateExtends(newState, currentState, extendOpsByBoundVariables); // preprocess next steps
176 insert(stateTable,i2, newState, a, c, k);
177 }
178 }
179 }
180 }
181
182 return stateTable.get(0).get(0);
183 }
184
185 private List<List<PlanState>> initializeStateTable(int k, int n) {
186 List<List<PlanState>> stateTable = new ArrayList<>();
187 // Initialize state table and fill it with null
188 for (int i = 0; i <= n ; i++) {
189 stateTable.add(new ArrayList<>());
190 }
191 return stateTable;
192 }
193
194 private void insert(List<List<PlanState>> stateTable, int idx, PlanState newState, int a, int c, int k) {
195 stateTable.get(idx).add(c, newState);
196 while(stateTable.get(idx).size() > k){
197 // Truncate back to size k when grows too big
198 stateTable.set(idx, stateTable.get(idx).subList(0, k));
199 }
200 }
201
202 private void updateExtends(PlanState newState, PlanState currentState,
203 Map<PVariable, ? extends Collection<PConstraintInfo>> extendOpsByBoundVariables)
204 {
205 List<PConstraintInfo> presentExtends = currentState.getPresentExtends();
206
207 // Recategorize operations
208 newState.updateExtendsBasedOnDelta(presentExtends, extendOpsByBoundVariables);
209
210 return;
211 }
212
213 private boolean checkInsertCondition(List<PlanState> list, PlanState newState,
214 List<Set<PVariable>> reachableBoundVariableSets, int a, int c, int k) {
215// boolean isAmongBestK = (a == (k + 1)) && c < a && reachableBoundVariableSets.contains(newState.getBoundVariables());
216 boolean isAmongBestK = a == k && c < a ;
217 boolean isBetterThanCurrent = a < k && c <= a;
218
219 return isAmongBestK || isBetterThanCurrent;
220 }
221
222 private List<Integer> determineIndices(List<List<PlanState>> stateTable, int i2, PlanState newState, int k) {
223 int a = k;
224 int c = 0;
225 List<Integer> acIndices = new ArrayList<>();
226 for (int j = 0; j < k; j++) {
227 if (j < stateTable.get(i2).size()) {
228 PlanState stateInTable = stateTable.get(i2).get(j);
229 if (newState.getBoundVariables().equals(stateInTable.getBoundVariables())) {
230 // The new state has the same adornment as the stored one - they are not adornment disjoint
231 a = j;
232 }
233 if (newState.getCost() >= stateInTable.getCost()) {
234 c = j + 1;
235 }
236 } else {
237 break;
238 }
239 }
240
241 acIndices.add(a);
242 acIndices.add(c);
243 return acIndices;
244 }
245
246 private PlanState calculateNextState(PlanState currentState, PConstraintInfo constraintInfo) {
247 return currentState.cloneWithApplied(constraintInfo);
248 }
249
250 private List<Set<PVariable>> reachabilityAnalysis(PBody pBody, List<PConstraintInfo> constraintInfos) {
251 // TODO implement reachability analisys, also save/persist the results somewhere
252 List<Set<PVariable>> reachableBoundVariableSets = new ArrayList<>();
253 return reachableBoundVariableSets;
254 }
255
256
257}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintCategory.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintCategory.java
new file mode 100644
index 00000000..b98dd12e
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintCategory.java
@@ -0,0 +1,41 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.planner;
10
11
12/**
13 * Expresses the state of a PConstraint application
14 * condition with respect to a given adornment.
15 *
16 * @author Marton Bur
17 * @noreference This enum is not intended to be referenced by clients.
18 */
19public enum PConstraintCategory {
20 /*
21 * During plan creation an operation is considered a past
22 * operation, if an already bound variable is free in the
23 * mask of the operation.
24 * (Mask of the operation: the required binding state of
25 * the affected variables)
26 */
27 PAST,
28 /*
29 * The binding states of the variables in the operation
30 * mask correspond to the current binding states of the
31 * variables in the search plan
32 */
33 PRESENT,
34 /*
35 * There is at least one bound variable in the mask of
36 * a future operation that is still free at the current
37 * state of the plan. Also, a future operation can't be
38 * PAST.
39 */
40 FUTURE;
41}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfo.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfo.java
new file mode 100644
index 00000000..c2c76ef2
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfo.java
@@ -0,0 +1,142 @@
1/**
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Danil 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.localsearch.planner;
10
11import java.util.Collections;
12import java.util.LinkedHashSet;
13import java.util.Set;
14import java.util.function.Function;
15
16import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
17import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
18import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
19import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
20import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
24import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
25
26/**
27 * Wraps a PConstraint together with information required for the planner. Currently contains information about the expected binding state of
28 * the affected variables also called application condition, and the cost of the enforcement, based on the meta and/or the runtime context.
29 *
30 * @author Marton Bur
31 * @noreference This class is not intended to be referenced by clients.
32 */
33public class PConstraintInfo implements IConstraintEvaluationContext {
34
35 private PConstraint constraint;
36 private Set<PVariable> boundMaskVariables;
37 private Set<PVariable> freeMaskVariables;
38 private Set<PConstraintInfo> sameWithDifferentBindings;
39 private IQueryRuntimeContext runtimeContext;
40 private QueryAnalyzer queryAnalyzer;
41 private IQueryResultProviderAccess resultProviderAccess;
42 private ResultProviderRequestor resultRequestor;
43
44 private Double cost;
45 private Function<IConstraintEvaluationContext, Double> costFunction;
46
47
48 /**
49 * Instantiates the wrapper
50 * @param constraintfor which the information is added and stored
51 * @param boundMaskVariables the bound variables in the operation mask
52 * @param freeMaskVariables the free variables in the operation mask
53 * @param sameWithDifferentBindings during the planning process, multiple operation adornments are considered for a constraint, so that it
54 * is represented by multiple plan infos. This parameter contains all plan infos that are for the same
55 * constraint, but with different adornment
56 * @param context the query backend context
57 */
58 public PConstraintInfo(PConstraint constraint, Set<PVariable> boundMaskVariables, Set<PVariable> freeMaskVariables,
59 Set<PConstraintInfo> sameWithDifferentBindings,
60 IQueryBackendContext context,
61 ResultProviderRequestor resultRequestor,
62 Function<IConstraintEvaluationContext, Double> costFunction) {
63 this.constraint = constraint;
64 this.costFunction = costFunction;
65 this.boundMaskVariables = new LinkedHashSet<>(boundMaskVariables);
66 this.freeMaskVariables = new LinkedHashSet<>(freeMaskVariables);
67 this.sameWithDifferentBindings = sameWithDifferentBindings;
68 this.resultRequestor = resultRequestor;
69 this.runtimeContext = context.getRuntimeContext();
70 this.queryAnalyzer = context.getQueryAnalyzer();
71 this.resultProviderAccess = context.getResultProviderAccess();
72
73 this.cost = null; // cost will be computed lazily (esp. important for pattern calls)
74 }
75
76 @Override
77 public IQueryRuntimeContext getRuntimeContext() {
78 return runtimeContext;
79 }
80
81 @Override
82 public QueryAnalyzer getQueryAnalyzer() {
83 return queryAnalyzer;
84 }
85
86 @Override
87 public PConstraint getConstraint() {
88 return constraint;
89 }
90
91 @Override
92 public Set<PVariable> getFreeVariables() {
93 return freeMaskVariables;
94 }
95
96 @Override
97 public Set<PVariable> getBoundVariables() {
98 return boundMaskVariables;
99 }
100
101 public Set<PConstraintInfo> getSameWithDifferentBindings() {
102 return sameWithDifferentBindings;
103 }
104
105 public double getCost() {
106 if (cost == null) {
107 // Calculate cost of the constraint based on its type
108 cost = costFunction.apply(this);
109 }
110 return cost;
111 }
112
113 public PConstraintCategory getCategory(PBody pBody, Set<PVariable> boundVariables) {
114 if (!Collections.disjoint(boundVariables, this.freeMaskVariables)) {
115 return PConstraintCategory.PAST;
116 } else if (!boundVariables.containsAll(this.boundMaskVariables)) {
117 return PConstraintCategory.FUTURE;
118 } else {
119 return PConstraintCategory.PRESENT;
120 }
121 }
122
123 @Override
124 public String toString() {
125 return String.format("%s, bound variables: %s, cost: \"%.2f\"", constraint.toString(), boundMaskVariables.toString(), cost);
126 }
127
128 /**
129 * @deprecated use {@link #resultProviderRequestor()}
130 */
131 @Override
132 @Deprecated
133 public IQueryResultProviderAccess resultProviderAccess() {
134 return resultProviderAccess;
135 }
136
137 @Override
138 public ResultProviderRequestor resultProviderRequestor() {
139 return resultRequestor;
140 }
141
142}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java
new file mode 100644
index 00000000..eeac07ce
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java
@@ -0,0 +1,278 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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;
10
11import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
12import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.*;
18import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.AbstractTransitiveClosure;
19import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
20import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
21import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
23import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameterDirection;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
25import tools.refinery.viatra.runtime.matchers.util.Sets;
26
27import java.util.*;
28import java.util.function.Function;
29import java.util.function.Predicate;
30import java.util.stream.Collectors;
31import java.util.stream.Stream;
32
33
34/**
35 * @author Grill Balázs
36 * @noreference This class is not intended to be referenced by clients.
37 */
38class PConstraintInfoInferrer {
39
40 private static final Predicate<PVariable> SINGLE_USE_VARIABLE = input -> input != null && input.getReferringConstraints().size() == 1;
41
42 private final boolean useIndex;
43 private final Function<IConstraintEvaluationContext, Double> costFunction;
44 private final IQueryBackendContext context;
45 private final ResultProviderRequestor resultRequestor;
46
47
48 public PConstraintInfoInferrer(boolean useIndex,
49 IQueryBackendContext backendContext,
50 ResultProviderRequestor resultRequestor,
51 Function<IConstraintEvaluationContext, Double> costFunction) {
52 this.useIndex = useIndex;
53 this.context = backendContext;
54 this.resultRequestor = resultRequestor;
55 this.costFunction = costFunction;
56 }
57
58
59 /**
60 * Create all possible application condition for all constraint
61 *
62 * @param constraintSet the set of constraints
63 * @return a collection of the wrapper PConstraintInfo objects with all the allowed application conditions
64 */
65 public List<PConstraintInfo> createPConstraintInfos(Set<PConstraint> constraintSet) {
66 List<PConstraintInfo> constraintInfos = new ArrayList<>();
67
68 for (PConstraint pConstraint : constraintSet) {
69 createPConstraintInfoDispatch(constraintInfos, pConstraint);
70 }
71 return constraintInfos;
72 }
73
74 private void createPConstraintInfoDispatch(List<PConstraintInfo> resultList, PConstraint pConstraint){
75 if(pConstraint instanceof ExportedParameter){
76 createConstraintInfoExportedParameter(resultList, (ExportedParameter) pConstraint);
77 } else if(pConstraint instanceof TypeConstraint){
78 createConstraintInfoTypeConstraint(resultList, (TypeConstraint)pConstraint);
79 } else if(pConstraint instanceof TypeFilterConstraint){
80 createConstraintInfoTypeFilterConstraint(resultList, (TypeFilterConstraint)pConstraint);
81 } else if(pConstraint instanceof ConstantValue){
82 createConstraintInfoConstantValue(resultList, (ConstantValue)pConstraint);
83 } else if (pConstraint instanceof Inequality){
84 createConstraintInfoInequality(resultList, (Inequality) pConstraint);
85 } else if (pConstraint instanceof ExpressionEvaluation){
86 createConstraintInfoExpressionEvaluation(resultList, (ExpressionEvaluation)pConstraint);
87 } else if (pConstraint instanceof AggregatorConstraint){
88 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((AggregatorConstraint) pConstraint).getResultVariable());
89 } else if (pConstraint instanceof PatternMatchCounter){
90 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((PatternMatchCounter) pConstraint).getResultVariable());
91 } else if (pConstraint instanceof PositivePatternCall){
92 createConstraintInfoPositivePatternCall(resultList, (PositivePatternCall) pConstraint);
93 } else if (pConstraint instanceof AbstractTransitiveClosure) {
94 createConstraintInfoBinaryTransitiveClosure(resultList, (AbstractTransitiveClosure) pConstraint);
95 } else{
96 createConstraintInfoGeneric(resultList, pConstraint);
97 }
98 }
99
100 private void createConstraintInfoConstantValue(List<PConstraintInfo> resultList,
101 ConstantValue pConstraint) {
102 // A ConstantValue constraint has a single variable, which is allowed to be unbound
103 // (extending through ConstantValue is considered a cheap operation)
104 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
105 Set<? extends Set<PVariable>> bindings = Sets.powerSet(affectedVariables);
106 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings);
107 }
108
109
110 private void createConstraintInfoPositivePatternCall(List<PConstraintInfo> resultList,
111 PositivePatternCall pCall) {
112 // A pattern call can have any of its variables unbound
113 Set<PVariable> affectedVariables = pCall.getAffectedVariables();
114 // IN parameters cannot be unbound and
115 // OUT parameters cannot be bound
116 Tuple variables = pCall.getVariablesTuple();
117 final Set<PVariable> inVariables = new HashSet<>();
118 Set<PVariable> inoutVariables = new HashSet<>();
119 List<PParameter> parameters = pCall.getReferredQuery().getParameters();
120 for(int i=0;i<parameters.size();i++){
121 switch(parameters.get(i).getDirection()){
122 case IN:
123 inVariables.add((PVariable) variables.get(i));
124 break;
125 case INOUT:
126 inoutVariables.add((PVariable) variables.get(i));
127 break;
128 case OUT:
129 default:
130 break;
131
132 }
133 }
134 Iterable<Set<PVariable>> bindings = Sets.powerSet(inoutVariables).stream()
135 .map(input -> Stream.concat(input.stream(), inVariables.stream()).collect(Collectors.toSet()))
136 .collect(Collectors.toSet());
137
138 doCreateConstraintInfos(resultList, pCall, affectedVariables, bindings);
139 }
140
141 private void createConstraintInfoBinaryTransitiveClosure(List<PConstraintInfo> resultList,
142 AbstractTransitiveClosure closure) {
143 // A pattern call can have any of its variables unbound
144
145 List<PParameter> parameters = closure.getReferredQuery().getParameters();
146 Tuple variables = closure.getVariablesTuple();
147
148 Set<Set<PVariable>> bindings = new HashSet<>();
149 PVariable firstVariable = (PVariable) variables.get(0);
150 PVariable secondVariable = (PVariable) variables.get(1);
151 // Check is always supported
152 bindings.add(new HashSet<>(Arrays.asList(firstVariable, secondVariable)));
153 // If first parameter is not bound mandatorily, it can be left out
154 if (parameters.get(0).getDirection() != PParameterDirection.IN) {
155 bindings.add(Collections.singleton(secondVariable));
156 }
157 // If second parameter is not bound mandatorily, it can be left out
158 if (parameters.get(1).getDirection() != PParameterDirection.IN) {
159 bindings.add(Collections.singleton(firstVariable));
160 }
161
162 doCreateConstraintInfos(resultList, closure, closure.getAffectedVariables(), bindings);
163 }
164
165
166
167 private void createConstraintInfoExportedParameter(List<PConstraintInfo> resultList,
168 ExportedParameter parameter) {
169 // In case of an exported parameter constraint, the parameter must be bound in order to execute
170 Set<PVariable> affectedVariables = parameter.getAffectedVariables();
171 doCreateConstraintInfos(resultList, parameter, affectedVariables, Collections.singleton(affectedVariables));
172 }
173
174 private void createConstraintInfoExpressionEvaluation(List<PConstraintInfo> resultList,
175 ExpressionEvaluation expressionEvaluation) {
176 // An expression evaluation can only have its output variable unbound. All other variables shall be bound
177 PVariable output = expressionEvaluation.getOutputVariable();
178 Set<Set<PVariable>> bindings = new HashSet<>();
179 Set<PVariable> affectedVariables = expressionEvaluation.getAffectedVariables();
180 // All variables bound -> check
181 bindings.add(affectedVariables);
182 // Output variable is not bound -> extend
183 bindings.add(affectedVariables.stream().filter(var -> !Objects.equals(var, output)).collect(Collectors.toSet()));
184 doCreateConstraintInfos(resultList, expressionEvaluation, affectedVariables, bindings);
185 }
186
187 private void createConstraintInfoTypeFilterConstraint(List<PConstraintInfo> resultList,
188 TypeFilterConstraint filter){
189 // In case of type filter, all affected variables must be bound in order to execute
190 Set<PVariable> affectedVariables = filter.getAffectedVariables();
191 doCreateConstraintInfos(resultList, filter, affectedVariables, Collections.singleton(affectedVariables));
192 }
193
194 private void createConstraintInfoInequality(List<PConstraintInfo> resultList,
195 Inequality inequality){
196 // In case of inequality, all affected variables must be bound in order to execute
197 Set<PVariable> affectedVariables = inequality.getAffectedVariables();
198 doCreateConstraintInfos(resultList, inequality, affectedVariables, Collections.singleton(affectedVariables));
199 }
200
201 private void createConstraintInfoAggregatorConstraint(List<PConstraintInfo> resultList,
202 PConstraint pConstraint, PVariable resultVariable){
203 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
204
205 // The only variables which can be unbound are single-use
206 Set<PVariable> canBeUnboundVariables =
207 Stream.concat(Stream.of(resultVariable), affectedVariables.stream().filter(SINGLE_USE_VARIABLE)).collect(Collectors.toSet());
208
209 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables);
210
211 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings);
212 }
213
214 /**
215 *
216 * @param canBeUnboundVariables Variables which are allowed to be unbound
217 * @param affectedVariables All affected variables
218 * @return The set of possible bound variable sets
219 */
220 private Set<Set<PVariable>> calculatePossibleBindings(Set<PVariable> canBeUnboundVariables, Set<PVariable> affectedVariables){
221 final Set<PVariable> mustBindVariables = affectedVariables.stream().filter(input -> !canBeUnboundVariables.contains(input)).collect(Collectors.toSet());
222 return Sets.powerSet(canBeUnboundVariables).stream()
223 .map(input -> {
224 //some variables have to be bound before executing this constraint
225 Set<PVariable> result= new HashSet<>(input);
226 result.addAll(mustBindVariables);
227 return result;
228 })
229 .collect(Collectors.toSet());
230 }
231
232 private void createConstraintInfoGeneric(List<PConstraintInfo> resultList, PConstraint pConstraint){
233 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
234
235 // The only variables which can be unbound are single use variables
236 Set<PVariable> canBeUnboundVariables = affectedVariables.stream().filter(SINGLE_USE_VARIABLE).collect(Collectors.toSet());
237
238 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables);
239
240 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings);
241 }
242
243 private void createConstraintInfoTypeConstraint(List<PConstraintInfo> resultList,
244 TypeConstraint typeConstraint) {
245 Set<PVariable> affectedVariables = typeConstraint.getAffectedVariables();
246 Set<? extends Set<PVariable>> bindings = null;
247
248 IInputKey inputKey = typeConstraint.getSupplierKey();
249 if(inputKey.isEnumerable()){
250 bindings = Sets.powerSet(affectedVariables);
251 }else{
252 // For not enumerable types, this constraint can only be a check
253 bindings = Collections.singleton(affectedVariables);
254 }
255
256 doCreateConstraintInfos(resultList, typeConstraint, affectedVariables, bindings);
257 }
258
259 private void doCreateConstraintInfos(List<PConstraintInfo> constraintInfos,
260 PConstraint pConstraint, Set<PVariable> affectedVariables, Iterable<? extends Set<PVariable>> bindings) {
261 Set<PConstraintInfo> sameWithDifferentBindings = new HashSet<>();
262 for (Set<PVariable> boundVariables : bindings) {
263
264 PConstraintInfo info = new PConstraintInfo(pConstraint, boundVariables,
265 affectedVariables.stream().filter(input -> !boundVariables.contains(input)).collect(Collectors.toSet()),
266 sameWithDifferentBindings, context, resultRequestor, costFunction);
267 constraintInfos.add(info);
268 sameWithDifferentBindings.add(info);
269 }
270 }
271
272 private Set<Set<PVariable>> excludeUnnavigableOperationMasks(TypeConstraint typeConstraint, Set<? extends Set<PVariable>> bindings) {
273 PVariable firstVariable = typeConstraint.getVariableInTuple(0);
274 return bindings.stream().filter(
275 boundVariablesSet -> (boundVariablesSet.isEmpty() || boundVariablesSet.contains(firstVariable)))
276 .collect(Collectors.toSet());
277 }
278}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java
new file mode 100644
index 00000000..e93b07bc
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java
@@ -0,0 +1,283 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.planner;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Comparator;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
19
20import tools.refinery.viatra.runtime.localsearch.planner.util.OperationCostComparator;
21import tools.refinery.viatra.runtime.matchers.algorithms.OrderedIterableMerge;
22import tools.refinery.viatra.runtime.matchers.psystem.PBody;
23import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
24import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
25
26/**
27 * This class represents the state of the plan during planning.
28 *
29 * <p> A PlanState represents a sequence of operations (operationsList) and caches the computed cost
30 * for this operation sequence. The list and the cost are initialized in the constructor.
31 * However, #categorizeChecks() also updates the operations list (by suffixing checks)
32 *
33 * @author Marton Bur
34 * @noreference This class is not intended to be referenced by clients.
35 */
36public class PlanState {
37
38 private final PBody pBody;
39 private final List<PConstraintInfo> operationsList;
40 private final Set<PVariable> boundVariables;
41 private final Collection<PVariable> deltaVariables; /* bound since ancestor plan */
42 private final Set<PConstraint> enforcedConstraints;
43
44 private double cummulativeProduct;
45 private double cost;
46
47 private static Comparator<PConstraintInfo> infoComparator = new OperationCostComparator();
48
49 /*
50 * For a short explanation of past, present and future operations,
51 * see class
52 */
53 private List<PConstraintInfo> presentExtends;
54
55 /**
56 * Creates an initial state
57 */
58 public PlanState(PBody pBody, Set<PVariable> boundVariables) {
59
60 this(pBody, new ArrayList<>(), boundVariables, boundVariables /* also the delta */,
61 0.0 /* initial cost */, 1.0 /*initial branch count */);
62 }
63
64 public PlanState cloneWithApplied(PConstraintInfo op) {
65 // Create operation list based on the current state
66 ArrayList<PConstraintInfo> newOperationsList =
67 // pre-reserve excess capacity for later addition of CHECK ops
68 new ArrayList<>(pBody.getConstraints().size());
69 newOperationsList.addAll(this.getOperations());
70 newOperationsList.add(op);
71
72 // Bind the variables of the op
73 Collection<PVariable> deltaVariables = op.getFreeVariables();
74 Set<PVariable> allBoundVariables =
75 // pre-reserve exact capacity as variables are known
76 // (will not be affected by adding CHECK ops later)
77 new HashSet<>(this.getBoundVariables().size() + deltaVariables.size());
78 allBoundVariables.addAll(this.getBoundVariables());
79 allBoundVariables.addAll(deltaVariables);
80
81 PlanState newState = new PlanState(getAssociatedPBody(), newOperationsList, allBoundVariables, deltaVariables,
82 cost, cummulativeProduct);
83 newState.accountNewOperation(op);
84 return newState;
85 }
86
87 private PlanState(PBody pBody, List<PConstraintInfo> operationsList,
88 Set<PVariable> boundVariables, Collection<PVariable> deltaVariables,
89 double cost, double cummulativeProduct)
90 {
91 this.pBody = pBody;
92 this.operationsList = operationsList;
93 this.boundVariables = boundVariables;
94 this.enforcedConstraints = new HashSet<>();
95 this.deltaVariables = deltaVariables;
96 this.cost = cost;
97 this.cummulativeProduct = cummulativeProduct;
98 }
99
100 // NOT included for EXTEND: bind all variables of op
101 private void accountNewOperation(PConstraintInfo constraintInfo) {
102 this.enforcedConstraints.add(constraintInfo.getConstraint());
103 accountCost(constraintInfo);
104 }
105
106 private void accountCost(PConstraintInfo constraintInfo) {
107 double constraintCost = constraintInfo.getCost();
108 double branchFactor = constraintCost;
109 if (constraintCost > 0){
110 cost += cummulativeProduct * constraintCost;
111 cummulativeProduct *= branchFactor;
112 }
113 }
114
115
116 public Set<PConstraint> getEnforcedConstraints() {
117 return enforcedConstraints;
118 }
119
120 /**
121 * Re-categorizes given extend operations into already applied or no longer applicable ones (discarded),
122 * immediately applicable ones (saved as presently viable extends),
123 * and not yet applicable ones (discarded).
124 *
125 * @param allPotentialExtendInfos all other extends that may be applicable
126 * to this plan state now or in the future;
127 * MUST consist of "extend" constraint applications only (at least one free variable)
128 */
129 public void updateExtends(Iterable<PConstraintInfo> allPotentialExtendInfos) {
130 presentExtends = new ArrayList<>();
131
132
133 // categorize future/present extend constraint infos
134 for (PConstraintInfo op : allPotentialExtendInfos) {
135 updateExtendInternal(op);
136 }
137 }
138
139 /**
140 * Re-categorizes given extend operations into already applied or no longer applicable ones (discarded),
141 * immediately applicable ones (saved as presently viable extends),
142 * and not yet applicable ones (discarded).
143 *
144 * @param extendOpsByBoundVariables all EXTEND operations indexed by affected <i>bound</i> variables
145 * MUST consist of "extend" constraint applications only (at least one free variable)
146 */
147 public void updateExtendsBasedOnDelta(
148 Iterable<PConstraintInfo> previousPresentExtends,
149 Map<PVariable, ? extends Collection<PConstraintInfo>> extendOpsByBoundVariables)
150 {
151 presentExtends = new ArrayList<>();
152 if (operationsList.isEmpty())
153 throw new IllegalStateException("Not applicable as starting step");
154
155 for (PConstraintInfo extend: previousPresentExtends) {
156 updateExtendInternal(extend);
157 }
158
159 Set<PConstraintInfo> affectedExtends = new HashSet<>();
160 for (PVariable variable : deltaVariables) {
161 // only those check ops may become applicable that have an affected variable in the delta
162 Collection<PConstraintInfo> extendsForVariable = extendOpsByBoundVariables.get(variable);
163 if (null != extendsForVariable) {
164 affectedExtends.addAll(extendsForVariable);
165 }
166 }
167 for (PConstraintInfo extend: affectedExtends) {
168 updateExtendInternal(extend);
169 }
170 }
171
172 private void updateExtendInternal(PConstraintInfo op) {
173 if(!enforcedConstraints.contains(op.getConstraint())) {
174 categorizeExtend(op);
175 }
176 }
177
178 /**
179 * Check operations that newly became applicable (see {@link #getDeltaVariables()})
180 * are appended to operations lists.
181 *
182 * <p> Will never discover degenerate checks (of PConstraints with zero variables),
183 * so must not use on initial state.
184 *
185 * @param allPotentialCheckInfos all CHECK operations
186 * MUST consist of "check" constraint applications only (no free variables)
187 * and must be iterable in decreasing order of cost
188 *
189 *
190 */
191 public void applyChecks(List<PConstraintInfo> allPotentialCheckInfos) {
192 applyChecksInternal(allPotentialCheckInfos);
193 }
194
195 /**
196 * Immediately applicable checks are appended to operations lists.
197 *
198 * @param checkOpsByVariables all CHECK operations indexed by affected variables
199 * MUST consist of "check" constraint applications only (no free variables)
200 * and each bucket must be iterable in decreasing order of cost
201 */
202 public void applyChecksBasedOnDelta(Map<PVariable, List<PConstraintInfo>> checkOpsByVariables) {
203 if (operationsList.isEmpty())
204 throw new IllegalStateException("Not applicable as starting step");
205
206 Iterable<PConstraintInfo> affectedChecks = Collections.emptyList();
207
208 for (PVariable variable : deltaVariables) {
209 // only those check ops may become applicable that have an affected variable in the delta
210 List<PConstraintInfo> checksForVariable = checkOpsByVariables.get(variable);
211 if (null != checksForVariable) {
212 affectedChecks = OrderedIterableMerge.mergeUniques(affectedChecks, checksForVariable, infoComparator);
213 }
214 }
215
216 // checks retain their order, no re-sorting needed
217 applyChecksInternal(affectedChecks);
218 }
219
220 private void applyChecksInternal(Iterable<PConstraintInfo> checks) {
221 for (PConstraintInfo checkInfo : checks) {
222 if (this.boundVariables.containsAll(checkInfo.getBoundVariables()) &&
223 !enforcedConstraints.contains(checkInfo.getConstraint()))
224 {
225 operationsList.add(checkInfo);
226 accountNewOperation(checkInfo);
227 }
228 }
229 }
230
231
232 private void categorizeExtend(PConstraintInfo constraintInfo) {
233 PConstraintCategory category = constraintInfo.getCategory(pBody, boundVariables);
234 if (category == PConstraintCategory.PRESENT) {
235 presentExtends.add(constraintInfo);
236 } else {
237 // do not categorize past/future operations
238 }
239 }
240
241
242 public PBody getAssociatedPBody() {
243 return pBody;
244 }
245
246 public List<PConstraintInfo> getOperations() {
247 return operationsList;
248 }
249
250 public Set<PVariable> getBoundVariables() {
251 return boundVariables;
252 }
253
254 /**
255 * @return the derived cost of the plan contained in the state
256 */
257 public double getCost() {
258 return cost;
259 }
260
261
262 /**
263 * @return cumulative branching factor
264 * @since 2.1
265 */
266 public double getCummulativeProduct() {
267 return cummulativeProduct;
268 }
269
270 public List<PConstraintInfo> getPresentExtends() {
271 return presentExtends;
272 }
273
274 /**
275 * Contains only those variables that are added by the newest extend
276 * (or the initially bound ones if no extend yet)
277 */
278 public Collection<PVariable> getDeltaVariables() {
279 return deltaVariables;
280 }
281
282
283}
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
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/GenericOperationCompiler.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/GenericOperationCompiler.java
new file mode 100644
index 00000000..d86982e9
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/GenericOperationCompiler.java
@@ -0,0 +1,101 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.viatra.runtime.localsearch.planner.compiler;
11
12import tools.refinery.viatra.runtime.localsearch.operations.generic.GenericTypeCheck;
13import tools.refinery.viatra.runtime.localsearch.operations.generic.GenericTypeExtend;
14import tools.refinery.viatra.runtime.localsearch.operations.generic.GenericTypeExtendSingleValue;
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22
23import java.util.*;
24
25/**
26 * @author Zoltan Ujhelyi
27 * @since 1.7
28 *
29 */
30public class GenericOperationCompiler extends AbstractOperationCompiler {
31
32 public GenericOperationCompiler(IQueryRuntimeContext runtimeContext) {
33 super(runtimeContext);
34 }
35
36 @Override
37 protected void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
38 IInputKey inputKey = typeConstraint.getInputKey();
39 Tuple tuple = typeConstraint.getVariablesTuple();
40 int[] positions = new int[tuple.getSize()];
41 for (int i = 0; i < tuple.getSize(); i++) {
42 PVariable variable = (PVariable) tuple.get(i);
43 positions[i] = variableMapping.get(variable);
44 }
45 operations.add(new GenericTypeCheck(inputKey, positions, TupleMask.fromSelectedIndices(variableMapping.size(), positions)));
46
47 }
48
49 @Override
50 protected void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
51 IInputKey inputKey = typeConstraint.getSupplierKey();
52 Tuple tuple = typeConstraint.getVariablesTuple();
53 int[] positions = new int[tuple.getSize()];
54 for (int i = 0; i < tuple.getSize(); i++) {
55 PVariable variable = (PVariable) tuple.get(i);
56 positions[i] = variableMapping.get(variable);
57 }
58 operations.add(new GenericTypeCheck(inputKey, positions, TupleMask.fromSelectedIndices(variableMapping.size(), positions)));
59 }
60
61 @Override
62 protected void createUnaryTypeCheck(IInputKey inputKey, int position) {
63 int[] positions = new int[] {position};
64 operations.add(new GenericTypeCheck(inputKey, positions, TupleMask.fromSelectedIndices(1, positions)));
65 }
66
67 @Override
68 protected void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
69 IInputKey inputKey = typeConstraint.getSupplierKey();
70 Tuple tuple = typeConstraint.getVariablesTuple();
71
72 int[] positions = new int[tuple.getSize()];
73 List<Integer> boundVariableIndices = new ArrayList<>();
74 List<Integer> boundVariables = new ArrayList<>();
75 Set<Integer> unboundVariables = new HashSet<>();
76 for (int i = 0; i < tuple.getSize(); i++) {
77 PVariable variable = (PVariable) tuple.get(i);
78 Integer position = variableMapping.get(variable);
79 positions[i] = position;
80 if (variableBindings.get(typeConstraint).contains(position)) {
81 boundVariableIndices.add(i);
82 boundVariables.add(position);
83 } else {
84 unboundVariables.add(position);
85 }
86 }
87 TupleMask indexerMask = TupleMask.fromSelectedIndices(inputKey.getArity(), boundVariableIndices);
88 TupleMask callMask = TupleMask.fromSelectedIndices(variableMapping.size(), boundVariables);
89 // If multiple tuple elements from the indexer should be bound to the same variable, we must use a
90 // {@link GenericTypeExtend} check whether the tuple elements have the same value.
91 if (unboundVariables.size() == 1 && indexerMask.getSize() + 1 == indexerMask.getSourceWidth()) {
92 operations.add(new GenericTypeExtendSingleValue(inputKey, positions, callMask, indexerMask, unboundVariables.iterator().next()));
93 } else {
94 operations.add(new GenericTypeExtend(inputKey, positions, callMask, indexerMask, unboundVariables));
95 }
96
97 }
98
99
100
101}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/IOperationCompiler.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/IOperationCompiler.java
new file mode 100644
index 00000000..625a7eb2
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/IOperationCompiler.java
@@ -0,0 +1,53 @@
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.List;
12import java.util.Map;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.localsearch.matcher.CallWithAdornment;
16import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
17import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
18import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
19import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
22
23/**
24 * An operation compiler is responsible for creating executable search plans from the subplan structure.
25 *
26 * @author Zoltan Ujhelyi
27 * @since 1.7
28 *
29 */
30public interface IOperationCompiler {
31
32 /**
33 * Compiles a plan of <code>POperation</code>s to a list of type <code>List&ltISearchOperation></code>
34 *
35 * @param plan
36 * @param boundParameters
37 * @return an ordered list of POperations that make up the compiled search plan
38 * @throws ViatraQueryRuntimeException
39 */
40 List<ISearchOperation> compile(SubPlan plan, Set<PParameter> boundParameters);
41
42 /**
43 * Replaces previous method returning {@link MatcherReference}
44 * @since 2.1
45 */
46 Set<CallWithAdornment> getDependencies();
47
48 /**
49 * @return the cached variable bindings for the previously created plan
50 */
51 Map<PVariable, Integer> getVariableMappings();
52
53} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/IConstraintEvaluationContext.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/IConstraintEvaluationContext.java
new file mode 100644
index 00000000..9b44612b
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/IConstraintEvaluationContext.java
@@ -0,0 +1,63 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.cost;
10
11import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
12import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
13import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15import java.util.Collection;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
18
19/**
20 * This interface denotes the evaluation context of a constraint, intended for cost estimation. Provides access to information
21 * on which the cost function can base its calculation.
22 *
23 * @author Grill Balázs
24 * @since 1.4
25 * @noimplement
26 */
27public interface IConstraintEvaluationContext {
28
29 /**
30 * Get the constraint to be evaluated
31 */
32 public PConstraint getConstraint();
33
34 /**
35 * Unbound variables at the time of evaluating the constraint
36 */
37 public Collection<PVariable> getFreeVariables();
38
39 /**
40 * Bound variables at the time of evaluating the constraint
41 */
42 public Collection<PVariable> getBoundVariables();
43
44 public IQueryRuntimeContext getRuntimeContext();
45
46 /**
47 * @since 1.5
48 */
49 public QueryAnalyzer getQueryAnalyzer();
50
51 /**
52 * @deprecated use {@link #resultProviderRequestor()}
53 * @since 1.5
54 */
55 @Deprecated
56 public IQueryResultProviderAccess resultProviderAccess();
57
58 /**
59 * @since 2.1
60 */
61 public ResultProviderRequestor resultProviderRequestor();
62
63}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/ICostFunction.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/ICostFunction.java
new file mode 100644
index 00000000..4d9d0708
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/ICostFunction.java
@@ -0,0 +1,22 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.cost;
10
11/**
12 * Common interface for cost function implementation
13 *
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public interface ICostFunction{
19
20 public double apply(IConstraintEvaluationContext input);
21
22}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/HybridMatcherConstraintCostFunction.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/HybridMatcherConstraintCostFunction.java
new file mode 100644
index 00000000..df9292f0
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/HybridMatcherConstraintCostFunction.java
@@ -0,0 +1,91 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.cost.impl;
10
11import java.util.HashMap;
12import java.util.List;
13import java.util.Map;
14import java.util.Set;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
18import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
19import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * This cost function is intended to be used on hybrid configuration, with the strict restriction than any
28 * non-flattened positive pattern call is executed with Rete engine. This implementation provides the exact number
29 * of matches by invoking the result provider for the called pattern.
30 *
31 * @deprecated {@link StatisticsBasedConstraintCostFunction} should use {@link IQueryResultProvider#estimateCardinality(tools.refinery.viatra.runtime.matchers.tuple.TupleMask, org.eclipse.viatra.query.runtime.matchers.util.Accuracy)}
32 */
33@Deprecated
34public class HybridMatcherConstraintCostFunction extends IndexerBasedConstraintCostFunction {
35
36 @Override
37 protected double _calculateCost(PositivePatternCall patternCall, IConstraintEvaluationContext context) {
38 // Determine local constant constraints which is used to filter results
39 Tuple variables = patternCall.getVariablesTuple();
40 Set<Object> variablesSet = variables.getDistinctElements();
41 final Map<PVariable, Object> constantMap = new HashMap<>();
42 for (PConstraint _constraint : patternCall.getPSystem().getConstraints()) {
43 if (_constraint instanceof ConstantValue){
44 ConstantValue constraint = (ConstantValue) _constraint;
45 PVariable variable = (PVariable) constraint.getVariablesTuple().get(0);
46 if (variablesSet.contains(variable) && context.getBoundVariables().contains(variable)) {
47 constantMap.put(variable, constraint.getSupplierKey());
48 }
49 }
50 }
51
52 // Determine filter
53 Object[] filter = new Object[variables.getSize()];
54 for(int i=0; i < variables.getSize(); i++){
55 filter[i] = constantMap.get(variables.get(i));
56 }
57
58 // aggregate keys are the bound and not filtered variables
59 // These will be fixed in runtime, but unknown at planning time
60 // This is represented by indices to ease working with result tuples
61 final Map<Object, Integer> variableIndices = variables.invertIndex();
62 List<Integer> aggregateKeys = context.getBoundVariables().stream()
63 .filter(input -> !constantMap.containsKey(input))
64 .map(variableIndices::get)
65 .collect(Collectors.toList());
66
67 IQueryResultProvider resultProvider = context.resultProviderRequestor().requestResultProvider(patternCall, null);
68 Map<Tuple, Integer> aggregatedCounts = new HashMap<>();
69
70 // Iterate over all matches and count together matches that has equal values on
71 // aggregateKeys positions. The cost of the pattern call is considered to be the
72 // Maximum of these counted values
73
74 int result = 0;
75 // NOTE: a stream is not an iterable (cannot be iterated more than once), so to use it in a for-loop
76 // it has to be wrapped; in the following line a lambda is used to implement Iterable#iterator()
77 for (Tuple match : (Iterable<Tuple>) () -> resultProvider.getAllMatches(filter).iterator()) {
78 Tuple extracted = Tuples.flatTupleOf(aggregateKeys.stream().map(match::get).toArray());
79 int count = (aggregatedCounts.containsKey(extracted))
80 ? aggregatedCounts.get(extracted) + 1
81 : 1;
82 aggregatedCounts.put(extracted, count);
83 if (result < count) {
84 result = count;
85 }
86 }
87
88 return result;
89 }
90
91} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/IndexerBasedConstraintCostFunction.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/IndexerBasedConstraintCostFunction.java
new file mode 100644
index 00000000..9e2c8680
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/IndexerBasedConstraintCostFunction.java
@@ -0,0 +1,49 @@
1/**
2 * Copyright (c) 2010-2016, Grill Balázs, 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.cost.impl;
10
11import java.util.Optional;
12
13import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
14import tools.refinery.viatra.runtime.matchers.context.IInputKey;
15import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
16import tools.refinery.viatra.runtime.matchers.util.Accuracy;
17
18/**
19 * Cost function which calculates cost based on the cardinality of items in the runtime model, provided by the base indexer
20 *
21 * @author Grill Balázs
22 * @since 1.4
23 */
24public class IndexerBasedConstraintCostFunction extends StatisticsBasedConstraintCostFunction {
25
26
27
28
29 /**
30 *
31 */
32 public IndexerBasedConstraintCostFunction() {
33 super();
34 }
35
36 /**
37 * @param inverseNavigationPenalty
38 * @since 2.1
39 */
40 public IndexerBasedConstraintCostFunction(double inverseNavigationPenalty) {
41 super(inverseNavigationPenalty);
42 }
43
44 @Override
45 public Optional<Long> projectionSize(IConstraintEvaluationContext input, IInputKey supplierKey, TupleMask groupMask, Accuracy requiredAccuracy) {
46 return input.getRuntimeContext().estimateCardinality(supplierKey, groupMask, requiredAccuracy);
47 }
48
49}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/StatisticsBasedConstraintCostFunction.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/StatisticsBasedConstraintCostFunction.java
new file mode 100644
index 00000000..873be31d
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/StatisticsBasedConstraintCostFunction.java
@@ -0,0 +1,413 @@
1/**
2 * Copyright (c) 2010-2016, Grill Balázs, 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.cost.impl;
10
11import static tools.refinery.viatra.runtime.matchers.planning.helpers.StatisticsHelper.min;
12
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.List;
18import java.util.Map;
19import java.util.Optional;
20import java.util.Set;
21
22import tools.refinery.viatra.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider;
23import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
24import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
25import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
26import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
27import tools.refinery.viatra.runtime.matchers.context.IInputKey;
28import tools.refinery.viatra.runtime.matchers.planning.helpers.FunctionalDependencyHelper;
29import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
30import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
31import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
32import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
33import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint;
34import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
35import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
36import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Inequality;
37import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.NegativePatternCall;
38import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.PatternMatchCounter;
39import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
40import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryReflexiveTransitiveClosure;
41import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
42import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
43import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
44import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
45import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
46import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
47import tools.refinery.viatra.runtime.matchers.util.Accuracy;
48import tools.refinery.viatra.runtime.matchers.util.Preconditions;
49
50/**
51 * Cost function which calculates cost based on the cardinality of items in the runtime model
52 *
53 * <p> To provide custom statistics, override
54 * {@link #projectionSize(IConstraintEvaluationContext, IInputKey, TupleMask, Accuracy)}
55 * and {@link #bucketSize(IQueryReference, IConstraintEvaluationContext, TupleMask)}.
56 *
57 * @author Grill Balázs
58 * @since 1.4
59 */
60public abstract class StatisticsBasedConstraintCostFunction implements ICostFunction {
61 protected static final double MAX_COST = 250.0;
62
63 protected static final double DEFAULT_COST = StatisticsBasedConstraintCostFunction.MAX_COST - 100.0;
64
65 /**
66 * @since 2.1
67 */
68 public static final double INVERSE_NAVIGATION_PENALTY_DEFAULT = 0.10;
69 /**
70 * @since 2.1
71 */
72 public static final double INVERSE_NAVIGATION_PENALTY_GENERIC = 0.01;
73 /**
74 * @since 2.7
75 */
76 public static final double EVAL_UNWIND_EXTENSION_FACTOR = 3.0;
77
78 private final double inverseNavigationPenalty;
79
80
81 /**
82 * @since 2.1
83 */
84 public StatisticsBasedConstraintCostFunction(double inverseNavigationPenalty) {
85 super();
86 this.inverseNavigationPenalty = inverseNavigationPenalty;
87 }
88 public StatisticsBasedConstraintCostFunction() {
89 this(INVERSE_NAVIGATION_PENALTY_DEFAULT);
90 }
91
92 /**
93 * @deprecated call and implement {@link #projectionSize(IConstraintEvaluationContext, IInputKey, TupleMask, Accuracy)} instead
94 */
95 @Deprecated
96 public long countTuples(final IConstraintEvaluationContext input, final IInputKey supplierKey) {
97 return projectionSize(input, supplierKey, TupleMask.identity(supplierKey.getArity()), Accuracy.EXACT_COUNT).orElse(-1L);
98 }
99
100 /**
101 * Override this to provide custom statistics on edge/node counts.
102 * New implementors shall implement this instead of {@link #countTuples(IConstraintEvaluationContext, IInputKey)}
103 * @since 2.1
104 */
105 public Optional<Long> projectionSize(final IConstraintEvaluationContext input, final IInputKey supplierKey,
106 final TupleMask groupMask, Accuracy requiredAccuracy) {
107 long legacyCount = countTuples(input, supplierKey);
108 return legacyCount < 0 ? Optional.empty() : Optional.of(legacyCount);
109 }
110
111 /**
112 * Override this to provide custom estimates for match set sizes of called patterns.
113 * @since 2.1
114 */
115 public Optional<Double> bucketSize(final IQueryReference patternCall,
116 final IConstraintEvaluationContext input, TupleMask projMask) {
117 IQueryResultProvider resultProvider = input.resultProviderRequestor().requestResultProvider(patternCall, null);
118 // TODO hack: use LS cost instead of true bucket size estimate
119 if (resultProvider instanceof AbstractLocalSearchResultProvider) {
120 double estimatedCost = ((AbstractLocalSearchResultProvider) resultProvider).estimateCost(projMask);
121 return Optional.of(estimatedCost);
122 } else {
123 return resultProvider.estimateAverageBucketSize(projMask, Accuracy.APPROXIMATION);
124 }
125 }
126
127
128
129 @Override
130 public double apply(final IConstraintEvaluationContext input) {
131 return this.calculateCost(input.getConstraint(), input);
132 }
133
134 protected double _calculateCost(final ConstantValue constant, final IConstraintEvaluationContext input) {
135 return 0.0f;
136 }
137
138 protected double _calculateCost(final TypeConstraint constraint, final IConstraintEvaluationContext input) {
139 final Collection<PVariable> freeMaskVariables = input.getFreeVariables();
140 final Collection<PVariable> boundMaskVariables = input.getBoundVariables();
141 IInputKey supplierKey = constraint.getSupplierKey();
142 long arity = supplierKey.getArity();
143
144 if ((arity == 1)) {
145 // unary constraint
146 return calculateUnaryConstraintCost(constraint, input);
147 } else if ((arity == 2)) {
148 // binary constraint
149 PVariable srcVariable = ((PVariable) constraint.getVariablesTuple().get(0));
150 PVariable dstVariable = ((PVariable) constraint.getVariablesTuple().get(1));
151 boolean isInverse = false;
152 // Check if inverse navigation is needed along the edge
153 if ((freeMaskVariables.contains(srcVariable) && boundMaskVariables.contains(dstVariable))) {
154 isInverse = true;
155 }
156 double binaryExtendCost = calculateBinaryCost(supplierKey, srcVariable, dstVariable, isInverse, input);
157 // Make inverse navigation slightly more expensive than forward navigation
158 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=501078
159 return (isInverse) ? binaryExtendCost + inverseNavigationPenalty : binaryExtendCost;
160 } else {
161 // n-ary constraint
162 throw new UnsupportedOperationException("Cost calculation for arity " + arity + " is not implemented yet");
163 }
164 }
165
166
167 /**
168 * @deprecated use/implement {@link #calculateBinaryCost(IInputKey, PVariable, PVariable, boolean, IConstraintEvaluationContext)} instead
169 */
170 @Deprecated
171 protected double calculateBinaryExtendCost(final IInputKey supplierKey, final PVariable srcVariable,
172 final PVariable dstVariable, final boolean isInverse, long edgeCount /* TODO remove */,
173 final IConstraintEvaluationContext input) {
174 throw new UnsupportedOperationException();
175 }
176
177 /**
178 * @since 2.1
179 */
180 protected double calculateBinaryCost(final IInputKey supplierKey, final PVariable srcVariable,
181 final PVariable dstVariable, final boolean isInverse,
182 final IConstraintEvaluationContext input) {
183 final Collection<PVariable> freeMaskVariables = input.getFreeVariables();
184 final PConstraint constraint = input.getConstraint();
185
186// IQueryMetaContext metaContext = input.getRuntimeContext().getMetaContext();
187// Collection<InputKeyImplication> implications = metaContext.getImplications(supplierKey);
188
189 Optional<Long> edgeUpper = projectionSize(input, supplierKey, TupleMask.identity(2), Accuracy.BEST_UPPER_BOUND);
190 Optional<Long> srcUpper = projectionSize(input, supplierKey, TupleMask.selectSingle(0, 2), Accuracy.BEST_UPPER_BOUND);
191 Optional<Long> dstUpper = projectionSize(input, supplierKey, TupleMask.selectSingle(1, 2), Accuracy.BEST_UPPER_BOUND);
192
193 if (freeMaskVariables.contains(srcVariable) && freeMaskVariables.contains(dstVariable)) {
194 Double branchCount = edgeUpper.map(Long::doubleValue).orElse(
195 srcUpper.map(Long::doubleValue).orElse(DEFAULT_COST)
196 *
197 dstUpper.map(Long::doubleValue).orElse(DEFAULT_COST)
198 );
199 return branchCount;
200
201 } else {
202
203 Optional<Long> srcLower = projectionSize(input, supplierKey, TupleMask.selectSingle(0, 2), Accuracy.APPROXIMATION);
204 Optional<Long> dstLower = projectionSize(input, supplierKey, TupleMask.selectSingle(1, 2), Accuracy.APPROXIMATION);
205
206 List<Optional<Long>> nodeLower = Arrays.asList(srcLower, dstLower);
207 List<Optional<Long>> nodeUpper = Arrays.asList(srcUpper, dstUpper);
208
209 int from = isInverse ? 1 : 0;
210 int to = isInverse ? 0 : 1;
211
212 Optional<Double> costEstimate = Optional.empty();
213
214 if (!freeMaskVariables.contains(srcVariable) && !freeMaskVariables.contains(dstVariable)) {
215 // both variables bound, this is a simple check
216 costEstimate = min(costEstimate, 0.9);
217 } // TODO use bucket size estimation in the runtime context
218 costEstimate = min(costEstimate,
219 edgeUpper.flatMap(edges ->
220 nodeLower.get(from).map(fromNodes ->
221 // amortize edges over start nodes
222 (fromNodes == 0) ? 0.0 : (((double) edges) / fromNodes)
223 )));
224 if (navigatesThroughFunctionalDependencyInverse(input, constraint)) {
225 costEstimate = min(costEstimate, nodeUpper.get(to).flatMap(toNodes ->
226 nodeLower.get(from).map(fromNodes ->
227 // due to a reverse functional dependency, the destination count is an upper bound for the edge count
228 (fromNodes == 0) ? 0.0 : ((double) toNodes) / fromNodes
229 )));
230 }
231 if (! edgeUpper.isPresent()) {
232 costEstimate = min(costEstimate, nodeUpper.get(to).flatMap(toNodes ->
233 nodeLower.get(from).map(fromNodes ->
234 // If count is 0, no such element exists in the model, so there will be no branching
235 // TODO rethink, why dstNodeCount / srcNodeCount instead of dstNodeCount?
236 // The universally valid bound would be something like sparseEdgeEstimate = dstNodeCount + 1.0
237 // If we assume sparseness, we can reduce it by a SPARSENESS_FACTOR (e.g. 0.1).
238 // Alternatively, discount dstNodeCount * srcNodeCount on a SPARSENESS_EXPONENT (e.g 0.75) and then amortize over srcNodeCount.
239 fromNodes != 0 ? Math.max(1.0, ((double) toNodes) / fromNodes) : 1.0
240 )));
241 }
242 if (navigatesThroughFunctionalDependency(input, constraint)) {
243 // At most one destination value
244 costEstimate = min(costEstimate, 1.0);
245 }
246
247 return costEstimate.orElse(DEFAULT_COST);
248
249 }
250 }
251
252 /**
253 * @since 1.7
254 */
255 protected boolean navigatesThroughFunctionalDependency(final IConstraintEvaluationContext input,
256 final PConstraint constraint) {
257 return navigatesThroughFunctionalDependency(input, constraint, input.getBoundVariables(), input.getFreeVariables());
258 }
259 /**
260 * @since 2.1
261 */
262 protected boolean navigatesThroughFunctionalDependencyInverse(final IConstraintEvaluationContext input,
263 final PConstraint constraint) {
264 return navigatesThroughFunctionalDependency(input, constraint, input.getFreeVariables(), input.getBoundVariables());
265 }
266 /**
267 * @since 2.1
268 */
269 protected boolean navigatesThroughFunctionalDependency(final IConstraintEvaluationContext input,
270 final PConstraint constraint, Collection<PVariable> determining, Collection<PVariable> determined) {
271 final QueryAnalyzer queryAnalyzer = input.getQueryAnalyzer();
272 final Map<Set<PVariable>, Set<PVariable>> functionalDependencies = queryAnalyzer
273 .getFunctionalDependencies(Collections.singleton(constraint), false);
274 final Set<PVariable> impliedVariables = FunctionalDependencyHelper.closureOf(determining,
275 functionalDependencies);
276 return ((impliedVariables != null) && impliedVariables.containsAll(determined));
277 }
278
279 protected double calculateUnaryConstraintCost(final TypeConstraint constraint,
280 final IConstraintEvaluationContext input) {
281 PVariable variable = (PVariable) constraint.getVariablesTuple().get(0);
282 if (input.getBoundVariables().contains(variable)) {
283 return 0.9;
284 } else {
285 return projectionSize(input, constraint.getSupplierKey(), TupleMask.identity(1), Accuracy.APPROXIMATION)
286 .map(count -> 1.0 + count).orElse(DEFAULT_COST);
287 }
288 }
289
290 protected double _calculateCost(final ExportedParameter exportedParam, final IConstraintEvaluationContext input) {
291 return 0.0;
292 }
293
294 protected double _calculateCost(final TypeFilterConstraint exportedParam,
295 final IConstraintEvaluationContext input) {
296 return 0.0;
297 }
298
299 protected double _calculateCost(final PositivePatternCall patternCall, final IConstraintEvaluationContext input) {
300 final List<Integer> boundPositions = new ArrayList<>();
301 final List<PParameter> parameters = patternCall.getReferredQuery().getParameters();
302 for (int i = 0; (i < parameters.size()); i++) {
303 final PVariable variable = patternCall.getVariableInTuple(i);
304 if (input.getBoundVariables().contains(variable)) boundPositions.add(i);
305 }
306 TupleMask projMask = TupleMask.fromSelectedIndices(parameters.size(), boundPositions);
307
308 return bucketSize(patternCall, input, projMask).orElse(DEFAULT_COST);
309 }
310
311
312 /**
313 * @since 1.7
314 */
315 protected double _calculateCost(final ExpressionEvaluation evaluation, final IConstraintEvaluationContext input) {
316 // Even if there are multiple results here, if all output variable is bound eval unwind will not result in
317 // multiple branches in search graph
318 final double multiplier = evaluation.isUnwinding() && !input.getFreeVariables().isEmpty()
319 ? EVAL_UNWIND_EXTENSION_FACTOR
320 : 1.0;
321 return _calculateCost((PConstraint) evaluation, input) * multiplier;
322 }
323
324 /**
325 * @since 1.7
326 */
327 protected double _calculateCost(final Inequality inequality, final IConstraintEvaluationContext input) {
328 return _calculateCost((PConstraint)inequality, input);
329 }
330
331 /**
332 * @since 1.7
333 */
334 protected double _calculateCost(final AggregatorConstraint aggregator, final IConstraintEvaluationContext input) {
335 return _calculateCost((PConstraint)aggregator, input);
336 }
337
338 /**
339 * @since 1.7
340 */
341 protected double _calculateCost(final NegativePatternCall call, final IConstraintEvaluationContext input) {
342 return _calculateCost((PConstraint)call, input);
343 }
344
345 /**
346 * @since 1.7
347 */
348 protected double _calculateCost(final PatternMatchCounter counter, final IConstraintEvaluationContext input) {
349 return _calculateCost((PConstraint)counter, input);
350 }
351
352 /**
353 * @since 1.7
354 */
355 protected double _calculateCost(final BinaryTransitiveClosure closure, final IConstraintEvaluationContext input) {
356 // if (input.getFreeVariables().size() == 1) return 3.0;
357 return StatisticsBasedConstraintCostFunction.DEFAULT_COST;
358 }
359
360 /**
361 * @since 2.0
362 */
363 protected double _calculateCost(final BinaryReflexiveTransitiveClosure closure, final IConstraintEvaluationContext input) {
364 // if (input.getFreeVariables().size() == 1) return 3.0;
365 return StatisticsBasedConstraintCostFunction.DEFAULT_COST;
366 }
367
368 /**
369 * Default cost calculation strategy
370 */
371 protected double _calculateCost(final PConstraint constraint, final IConstraintEvaluationContext input) {
372 if (input.getFreeVariables().isEmpty()) {
373 return 1.0;
374 } else {
375 return StatisticsBasedConstraintCostFunction.DEFAULT_COST;
376 }
377 }
378
379 /**
380 * @throws ViatraQueryRuntimeException
381 */
382 public double calculateCost(final PConstraint constraint, final IConstraintEvaluationContext input) {
383 Preconditions.checkArgument(constraint != null, "Set constraint value correctly");
384 if (constraint instanceof ExportedParameter) {
385 return _calculateCost((ExportedParameter) constraint, input);
386 } else if (constraint instanceof TypeFilterConstraint) {
387 return _calculateCost((TypeFilterConstraint) constraint, input);
388 } else if (constraint instanceof ConstantValue) {
389 return _calculateCost((ConstantValue) constraint, input);
390 } else if (constraint instanceof PositivePatternCall) {
391 return _calculateCost((PositivePatternCall) constraint, input);
392 } else if (constraint instanceof TypeConstraint) {
393 return _calculateCost((TypeConstraint) constraint, input);
394 } else if (constraint instanceof ExpressionEvaluation) {
395 return _calculateCost((ExpressionEvaluation) constraint, input);
396 } else if (constraint instanceof Inequality) {
397 return _calculateCost((Inequality) constraint, input);
398 } else if (constraint instanceof AggregatorConstraint) {
399 return _calculateCost((AggregatorConstraint) constraint, input);
400 } else if (constraint instanceof NegativePatternCall) {
401 return _calculateCost((NegativePatternCall) constraint, input);
402 } else if (constraint instanceof PatternMatchCounter) {
403 return _calculateCost((PatternMatchCounter) constraint, input);
404 } else if (constraint instanceof BinaryTransitiveClosure) {
405 return _calculateCost((BinaryTransitiveClosure) constraint, input);
406 } else if (constraint instanceof BinaryReflexiveTransitiveClosure) {
407 return _calculateCost((BinaryReflexiveTransitiveClosure) constraint, input);
408 } else {
409 // Default cost calculation
410 return _calculateCost(constraint, input);
411 }
412 }
413}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/VariableBindingBasedCostFunction.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/VariableBindingBasedCostFunction.java
new file mode 100644
index 00000000..a517af25
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/VariableBindingBasedCostFunction.java
@@ -0,0 +1,95 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Balazs Grill, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.planner.cost.impl;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
14import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
19import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.NegativePatternCall;
20import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
21import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
22
23/**
24 * This class can be used to calculate cost of application of a constraint with a given adornment.
25 *
26 * For now the logic is based on the following principles:
27 *
28 * <li>The transitive closures, NACs and count finds are the most expensive operations
29 *
30 * <li>The number of free variables increase the cost
31 *
32 * <li>If all the variables of a constraint are free, then its cost equals to twice the number of its parameter
33 * variables. This solves the problem of unnecessary iteration over instances at the beginning of a plan (thus causing
34 * very long run times when executing the plan) by applying constraints based on structural features as soon as
35 * possible.
36 *
37 * <br>
38 *
39 * @author Marton Bur
40 * @since 1.4
41 *
42 */
43public class VariableBindingBasedCostFunction implements ICostFunction {
44
45 // Static cost definitions
46 private static int MAX = 1000;
47 private static int exportedParameterCost = MAX - 20;
48 private static int binaryTransitiveClosureCost = MAX - 50;
49 private static int nacCost = MAX - 100;
50 private static int aggregatorCost = MAX - 200;
51 private static int constantCost = 0;
52
53 @Override
54 public double apply(IConstraintEvaluationContext input) {
55 PConstraint constraint = input.getConstraint();
56 Set<PVariable> affectedVariables = constraint.getAffectedVariables();
57
58 int cost = 0;
59
60 // For constants the cost is determined to be 0.0
61 // The following constraints should be checks:
62 // * Binary transitive closure
63 // * NAC
64 // * count
65 // * exported parameter - only a metadata
66 if (constraint instanceof ConstantValue) {
67 cost = constantCost;
68 } else if (constraint instanceof BinaryTransitiveClosure) {
69 cost = binaryTransitiveClosureCost;
70 } else if (constraint instanceof NegativePatternCall) {
71 cost = nacCost;
72 } else if (constraint instanceof AggregatorConstraint) {
73 cost = aggregatorCost;
74 } else if (constraint instanceof ExportedParameter) {
75 cost = exportedParameterCost;
76 } else {
77 // In case of other constraints count the number of unbound variables
78 for (PVariable pVariable : affectedVariables) {
79 if (input.getFreeVariables().contains(pVariable)) {
80 // For each free variable ('without-value-variable') increase cost
81 cost += 1;
82 }
83 }
84 if (cost == affectedVariables.size()) {
85 // If all the variables are free, double the cost.
86 // This ensures that iteration costs more
87 cost *= 2;
88 }
89
90 }
91
92 return Float.valueOf(cost);
93 }
94
95}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/CompilerHelper.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/CompilerHelper.java
new file mode 100644
index 00000000..9b4e9ea5
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/CompilerHelper.java
@@ -0,0 +1,209 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Daniel Segesdi, Akos Horvath, Zoltan Ujhelyi, 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.localsearch.planner.util;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
20import tools.refinery.viatra.runtime.matchers.planning.operations.PApply;
21import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
22import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
25import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
26
27/**
28 *
29 * Helper methods for compiling SubPlans
30 *
31 * @author Marton Bur
32 *
33 */
34public class CompilerHelper {
35
36 private CompilerHelper() {/*Utility class constructor*/}
37
38 private static boolean isUserSpecified(PVariable var) {
39 return !var.isVirtual() && !var.getName().startsWith("_");
40 }
41
42 public static Map<PVariable, Integer> createVariableMapping(SubPlan plan) {
43 Map<PVariable, Integer> variableMapping = new HashMap<>();
44
45 int variableNumber = 0;
46
47 // Important note: this list might contain duplications when parameters are made equal inside the pattern
48 // This is the expected and normal behavior
49 List<PVariable> symbolicParameterVariables = plan.getBody().getSymbolicParameterVariables();
50 for (PVariable pVariable : symbolicParameterVariables) {
51 if (!variableMapping.containsKey(pVariable)) {
52 variableMapping.put(pVariable, variableNumber++);
53 }
54 }
55
56 List<PVariable> allVariables = new ArrayList<>(plan.getBody().getUniqueVariables());
57 Collections.sort(allVariables, (left, right) -> {
58 boolean leftUserSpecified = isUserSpecified(left);
59 boolean rightUserSpecified = isUserSpecified(right);
60 if (leftUserSpecified && !rightUserSpecified) {
61 return -1;
62 } else if (!leftUserSpecified && rightUserSpecified) {
63 return +1;
64 } else {
65 return left.getName().compareTo(right.getName());
66 }
67 });
68 for (PVariable pVariable : allVariables) {
69 if (!variableMapping.containsKey(pVariable)) {
70 variableMapping.put(pVariable, variableNumber++);
71 }
72 }
73
74 return variableMapping;
75 }
76
77 public static Map<PConstraint, Set<Integer>> cacheVariableBindings(SubPlan plan,
78 Map<PVariable, Integer> variableMappings, Set<PParameter> adornment) {
79
80 Set<Integer> externallyBoundVariables = getVariableIndicesForParameters(plan, variableMappings,
81 adornment);
82
83 Map<PConstraint, Set<Integer>> variableBindings = new HashMap<>();
84
85 List<SubPlan> allPlansInHierarchy = getAllParentPlans(plan);
86 for (SubPlan subPlan : allPlansInHierarchy) {
87 POperation operation = subPlan.getOperation();
88
89 if (operation instanceof PApply) {
90 PConstraint pConstraint = ((PApply) operation).getPConstraint();
91 Set<Integer> boundVariableIndices = getParametersBoundByParentPlan(variableMappings, subPlan);
92 boundVariableIndices.addAll(externallyBoundVariables);
93
94 variableBindings.put(pConstraint, boundVariableIndices);
95 }
96 }
97 return variableBindings;
98 }
99
100 /**
101 * Returns the list of variable indexes that are bound by the parent plan.
102 */
103 private static Set<Integer> getParametersBoundByParentPlan(Map<PVariable, Integer> variableMappings,
104 SubPlan subPlan) {
105 if (!subPlan.getParentPlans().isEmpty()) {
106 SubPlan parentPlan = subPlan.getParentPlans().get(0);
107 Set<PConstraint> enforcedConstraints = parentPlan.getAllEnforcedConstraints();
108 Set<PVariable> affectedVariables = getAffectedVariables(enforcedConstraints);
109 return getVariableIndices(variableMappings, affectedVariables);
110 }
111 return Collections.emptySet();
112 }
113
114 /**
115 * @param plan
116 * @return all the ancestor plans including the given plan
117 */
118 private static List<SubPlan> getAllParentPlans(SubPlan plan) {
119 SubPlan currentPlan = plan;
120 List<SubPlan> allPlans = new ArrayList<>();
121 allPlans.add(plan);
122 while (!currentPlan.getParentPlans().isEmpty()) {
123 // In the local search it is assumed that only a single parent exists
124 currentPlan = currentPlan.getParentPlans().get(0);
125 allPlans.add(currentPlan);
126 }
127
128 return allPlans;
129 }
130
131 /**
132 * @param variableMappings
133 * the mapping between variables and their indices
134 * @param variables
135 * variables to get the indices for
136 * @return the set of variable indices for the given variables
137 */
138 private static Set<Integer> getVariableIndices(Map<PVariable, Integer> variableMappings,
139 Iterable<PVariable> variables) {
140 Set<Integer> variableIndices = new HashSet<>();
141 for (PVariable pVariable : variables) {
142 variableIndices.add(variableMappings.get(pVariable));
143 }
144 return variableIndices;
145 }
146
147 /**
148 * Returns all affected variables of the given PConstraints.
149 */
150 private static Set<PVariable> getAffectedVariables(Set<PConstraint> pConstraints) {
151 Set<PVariable> allDeducedVariables = new HashSet<>();
152 for (PConstraint pConstraint : pConstraints) {
153 allDeducedVariables.addAll(pConstraint.getAffectedVariables());
154 }
155 return allDeducedVariables;
156 }
157
158 /**
159 * Transforms the index of a parameter into the index of a variable of the normalized body.
160 *
161 * @param plan
162 * the SubPlan containing the original body and its parameters
163 * @param variableMappings
164 * the mapping of PVariables to their indices
165 * @param parameters
166 * a set of parameters
167 * @return the index of the variable corresponding to the parameter at the given index
168 */
169 private static Set<Integer> getVariableIndicesForParameters(SubPlan plan,
170 Map<PVariable, Integer> variableMappings, Set<PParameter> parameters) {
171 Map<PParameter, PVariable> parameterMapping = new HashMap<>();
172 for (ExportedParameter constraint : plan.getBody().getSymbolicParameters()) {
173 parameterMapping.put(constraint.getPatternParameter(), constraint.getParameterVariable());
174 }
175
176 Set<Integer> variableIndices = new HashSet<>();
177 for (PParameter parameter : parameters) {
178 PVariable parameterVariable = parameterMapping.get(parameter);
179 if (parameterVariable == null) {
180 // XXX In case of older (pre-1.4) VIATRA versions, PParameters were not stable, see bug 498348
181 parameterVariable = plan.getBody().getVariableByNameChecked(parameter.getName());
182 }
183 Integer variableIndex = variableMappings.get(parameterVariable);
184 variableIndices.add(variableIndex);
185 }
186 return variableIndices;
187 }
188
189 /**
190 * Extracts the operations from a SubPlan into a list of POperations in the order of execution
191 *
192 * @param plan
193 * the SubPlan from wich the POperations should be extracted
194 * @return list of POperations extracted from the <code>plan</code>
195 */
196 public static List<POperation> createOperationsList(SubPlan plan) {
197 List<POperation> operationsList = new ArrayList<>();
198 while (plan.getParentPlans().size() > 0) {
199 operationsList.add(plan.getOperation());
200 SubPlan parentPlan = plan.getParentPlans().get(0);
201 plan = parentPlan;
202 }
203 operationsList.add(plan.getOperation());
204
205 Collections.reverse(operationsList);
206 return operationsList;
207 }
208
209}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/OperationCostComparator.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/OperationCostComparator.java
new file mode 100644
index 00000000..58f4fc41
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/util/OperationCostComparator.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Danil 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.localsearch.planner.util;
10
11import java.util.Comparator;
12
13import tools.refinery.viatra.runtime.localsearch.planner.PConstraintInfo;
14
15/**
16 * @author Marton Bur
17 *
18 */
19public class OperationCostComparator implements Comparator<PConstraintInfo>{
20
21 @Override
22 public int compare(PConstraintInfo o1, PConstraintInfo o2) {
23 return Double.compare(o1.getCost(), o2.getCost());
24 }
25
26}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/profiler/LocalSearchProfilerAdapter.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/profiler/LocalSearchProfilerAdapter.java
new file mode 100644
index 00000000..8c50c694
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/profiler/LocalSearchProfilerAdapter.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs 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.profiler;
10
11import java.util.HashMap;
12import java.util.List;
13import java.util.Map;
14import java.util.stream.Collectors;
15
16import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
17import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter;
18import tools.refinery.viatra.runtime.localsearch.matcher.LocalSearchMatcher;
19import tools.refinery.viatra.runtime.localsearch.matcher.MatcherReference;
20import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
21import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
22import tools.refinery.viatra.runtime.localsearch.plan.SearchPlanExecutor;
23
24/**
25 * This is a simple {@link ILocalSearchAdapter} which capable of counting
26 * each search operation execution then printing it in human readably form
27 * (along with the executed plans) using {@link #toString()}
28 * @author Grill Balázs
29 * @since 1.5
30 *
31 */
32public class LocalSearchProfilerAdapter implements ILocalSearchAdapter {
33
34 private final Map<MatcherReference, List<SearchPlan>> planReference = new HashMap<>();
35
36 private final Map<ISearchOperation, Integer> successfulOperationCounts = new HashMap<>();
37 private final Map<ISearchOperation, Integer> failedOperationCounts = new HashMap<>();
38
39 @Override
40 public void patternMatchingStarted(LocalSearchMatcher lsMatcher) {
41 MatcherReference key = new MatcherReference(lsMatcher.getPlanDescriptor().getQuery(),
42 lsMatcher.getPlanDescriptor().getAdornment());
43 planReference.put(key, lsMatcher.getPlan().stream().map(SearchPlanExecutor::getSearchPlan).collect(Collectors.toList()));
44 }
45
46 @Override
47 public void operationExecuted(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isSuccessful) {
48 Map<ISearchOperation, Integer> counts = isSuccessful ? successfulOperationCounts : failedOperationCounts;
49 counts.merge(operation,
50 /*no previous entry*/1,
51 /*increase previous value*/(oldValue, v) -> oldValue + 1);
52 }
53
54 @Override
55 public String toString() {
56 StringBuilder sb = new StringBuilder();
57 for (java.util.Map.Entry<MatcherReference, List<SearchPlan>> entry: planReference.entrySet()){
58 sb.append(entry.getKey());
59 sb.append("\n");
60
61 sb.append(entry.getValue());
62
63 List<SearchPlan> bodies = entry.getValue();
64 sb.append("{\n");
65 for(int i=0;i<bodies.size();i++){
66 sb.append("\tbody #");sb.append(i);sb.append("(\n");
67 for(ISearchOperation operation : bodies.get(i).getOperations()){
68 final int successCount = successfulOperationCounts.computeIfAbsent(operation, op -> 0);
69 final int failCount = failedOperationCounts.computeIfAbsent(operation, op -> 0);
70 sb.append("\t\t");sb.append(successCount);
71 sb.append("\t");sb.append(failCount);
72 sb.append("\t");sb.append(successCount + failCount);
73 sb.append("\t");sb.append(operation);
74 sb.append("\n");
75 }
76 sb.append("\t)\n");
77 }
78 sb.append("}\n");
79 }
80 return sb.toString();
81 }
82
83}