aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-localsearch
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-09-14 19:29:36 +0200
committerLibravatar GitHub <noreply@github.com>2023-09-14 19:29:36 +0200
commit98ed3b6db5f4e51961a161050cc31c66015116e8 (patch)
tree8bfd6d9bc8d6ed23b9eb0f889dd40b6c24fe8f92 /subprojects/viatra-runtime-localsearch
parentMerge pull request #38 from nagilooh/design-space-exploration (diff)
parentMerge remote-tracking branch 'upstream/main' into partial-interpretation (diff)
downloadrefinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.gz
refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.zst
refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.zip
Merge pull request #39 from kris7t/partial-interpretation
Implement partial interpretation based model generation
Diffstat (limited to 'subprojects/viatra-runtime-localsearch')
-rw-r--r--subprojects/viatra-runtime-localsearch/about.html26
-rw-r--r--subprojects/viatra-runtime-localsearch/build.gradle.kts14
-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
76 files changed, 8410 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-localsearch/about.html b/subprojects/viatra-runtime-localsearch/about.html
new file mode 100644
index 00000000..d1d5593a
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/about.html
@@ -0,0 +1,26 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
2<html>
3<!--
4 Copyright (c) 2017, Eclipse.org Foundation, Inc.
5
6 SPDX-License-Identifier: LicenseRef-EPL-Steward
7-->
8<head>
9<title>About</title>
10<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
11</head>
12<body lang="EN-US">
13<h2>About This Content</h2>
14
15<p>March 18, 2019</p>
16<h3>License</h3>
17
18<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
19Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is available at <a href="http://www.eclipse.org/org/documents/epl-v20.php">http://www.eclipse.org/legal/epl-v20.html</a>.
20For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
21
22<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
23apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
24indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
25</body>
26</html>
diff --git a/subprojects/viatra-runtime-localsearch/build.gradle.kts b/subprojects/viatra-runtime-localsearch/build.gradle.kts
new file mode 100644
index 00000000..31c0c634
--- /dev/null
+++ b/subprojects/viatra-runtime-localsearch/build.gradle.kts
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 implementation(project(":refinery-viatra-runtime"))
13 implementation(libs.slf4j.log4j)
14}
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}