diff options
Diffstat (limited to 'subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning')
15 files changed, 1584 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java new file mode 100644 index 00000000..c9f4b305 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java | |||
@@ -0,0 +1,108 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2008 Gabor Bergmann 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.matchers.planning; | ||
11 | |||
12 | import java.util.Map; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; | ||
15 | import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator; | ||
16 | import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
19 | |||
20 | /** | ||
21 | * | ||
22 | * An implicit common parameter is the "effort" PatternDescription. This | ||
23 | * indicates that the build request is part of an effort to build the matcher of | ||
24 | * the given pattern; it it important to record this during code generation so | ||
25 | * that the generated code can be separated according to patterns. | ||
26 | * | ||
27 | * @param <Collector> | ||
28 | * the handle of a receiver-like RETE ending to which plans can be | ||
29 | * connected | ||
30 | * @author Gabor Bergmann | ||
31 | * @noimplement This interface is not intended to be implemented by clients. | ||
32 | */ | ||
33 | public interface IOperationCompiler<Collector> { | ||
34 | |||
35 | /** | ||
36 | * @throws ViatraQueryRuntimeException | ||
37 | */ | ||
38 | public Collector patternCollector(PQuery pattern); | ||
39 | |||
40 | public void buildConnection(SubPlan parentPlan, Collector collector); | ||
41 | |||
42 | /** | ||
43 | * @since 0.9 | ||
44 | */ | ||
45 | public void patternFinished(PQuery pattern, Collector collector); | ||
46 | |||
47 | /** | ||
48 | * @throws ViatraQueryRuntimeException | ||
49 | */ | ||
50 | public SubPlan patternCallPlan(Tuple nodes, PQuery supplierKey); | ||
51 | |||
52 | public SubPlan transitiveInstantiationPlan(Tuple nodes); | ||
53 | |||
54 | public SubPlan directInstantiationPlan(Tuple nodes); | ||
55 | |||
56 | public SubPlan transitiveGeneralizationPlan(Tuple nodes); | ||
57 | |||
58 | public SubPlan directGeneralizationPlan(Tuple nodes); | ||
59 | |||
60 | public SubPlan transitiveContainmentPlan(Tuple nodes); | ||
61 | |||
62 | public SubPlan directContainmentPlan(Tuple nodes); | ||
63 | |||
64 | public SubPlan binaryEdgeTypePlan(Tuple nodes, Object supplierKey); | ||
65 | |||
66 | public SubPlan ternaryEdgeTypePlan(Tuple nodes, Object supplierKey); | ||
67 | |||
68 | public SubPlan unaryTypePlan(Tuple nodes, Object supplierKey); | ||
69 | |||
70 | public SubPlan buildStartingPlan(Object[] constantValues, Object[] constantNames); | ||
71 | |||
72 | public SubPlan buildEqualityChecker(SubPlan parentPlan, int[] indices); | ||
73 | |||
74 | public SubPlan buildInjectivityChecker(SubPlan parentPlan, int subject, int[] inequalIndices); | ||
75 | |||
76 | public SubPlan buildTransitiveClosure(SubPlan parentPlan); | ||
77 | |||
78 | public SubPlan buildTrimmer(SubPlan parentPlan, TupleMask trimMask, boolean enforceUniqueness); | ||
79 | |||
80 | public SubPlan buildBetaNode(SubPlan primaryPlan, SubPlan sidePlan, | ||
81 | TupleMask primaryMask, TupleMask sideMask, TupleMask complementer, boolean negative); | ||
82 | |||
83 | public SubPlan buildCounterBetaNode(SubPlan primaryPlan, SubPlan sidePlan, | ||
84 | TupleMask primaryMask, TupleMask originalSideMask, TupleMask complementer, | ||
85 | Object aggregateResultCalibrationElement); | ||
86 | |||
87 | public SubPlan buildCountCheckBetaNode(SubPlan primaryPlan, SubPlan sidePlan, | ||
88 | TupleMask primaryMask, TupleMask originalSideMask, int resultPositionInSignature); | ||
89 | |||
90 | public SubPlan buildPredicateChecker(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap, | ||
91 | SubPlan parentPlan); | ||
92 | public SubPlan buildFunctionEvaluator(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap, | ||
93 | SubPlan parentPlan, Object computedResultCalibrationElement); | ||
94 | |||
95 | /** | ||
96 | * @return an operation compiler that potentially acts on a separate container | ||
97 | */ | ||
98 | public IOperationCompiler<Collector> getNextContainer(); | ||
99 | |||
100 | /** | ||
101 | * @return an operation compiler that puts build actions on the tab of the given pattern | ||
102 | * @since 0.9 | ||
103 | */ | ||
104 | public IOperationCompiler<Collector> putOnTab(PQuery effort /*, IPatternMatcherContext context*/); | ||
105 | |||
106 | public void reinitialize(); | ||
107 | |||
108 | } \ No newline at end of file | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java new file mode 100644 index 00000000..6ce9d91b --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java | |||
@@ -0,0 +1,29 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2010 Gabor Bergmann 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.matchers.planning; | ||
11 | |||
12 | import org.apache.log4j.Logger; | ||
13 | import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; | ||
14 | import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext; | ||
15 | import tools.refinery.viatra.runtime.matchers.psystem.PBody; | ||
16 | |||
17 | /** | ||
18 | * An algorithm that builds a query plan based on a PSystem representation of a body of constraints. This interface is | ||
19 | * for internal use of the various query backends. | ||
20 | * | ||
21 | * @author Gabor Bergmann | ||
22 | */ | ||
23 | public interface IQueryPlannerStrategy { | ||
24 | |||
25 | /** | ||
26 | * @throws ViatraQueryRuntimeException | ||
27 | */ | ||
28 | public SubPlan plan(PBody pSystem, Logger logger, IQueryMetaContext context); | ||
29 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java new file mode 100644 index 00000000..501ddf73 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java | |||
@@ -0,0 +1,102 @@ | |||
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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning; | ||
10 | |||
11 | import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; | ||
12 | |||
13 | /** | ||
14 | * @author Zoltan Ujhelyi | ||
15 | * @since 0.9 | ||
16 | */ | ||
17 | public class QueryProcessingException extends ViatraQueryRuntimeException { | ||
18 | |||
19 | private static final long serialVersionUID = -8272290113656867086L; | ||
20 | /** | ||
21 | * Binding the '{n}' (n = 1..N) strings to contextual conditions in 'context' | ||
22 | * | ||
23 | * @param context | ||
24 | * : array of context-sensitive Strings | ||
25 | */ | ||
26 | protected static String bind(String message, String[] context) { | ||
27 | if (context == null) | ||
28 | return message; | ||
29 | |||
30 | String internal = message; | ||
31 | for (int i = 0; i < context.length; i++) { | ||
32 | internal = internal.replace("{" + (i + 1) + "}", context[i] != null ? context[i] : "<<null>>"); | ||
33 | } | ||
34 | return internal; | ||
35 | } | ||
36 | |||
37 | private Object patternDescription; | ||
38 | private String shortMessage; | ||
39 | |||
40 | /** | ||
41 | * @param message | ||
42 | * The template of the exception message | ||
43 | * @param context | ||
44 | * The data elements to be used to instantiate the template. Can be null if no context parameter is | ||
45 | * defined | ||
46 | * @param patternDescription | ||
47 | * the PatternDescription where the exception occurred | ||
48 | * @since 2.0 | ||
49 | */ | ||
50 | public QueryProcessingException(String message, Object patternDescription) { | ||
51 | super(message); | ||
52 | initializeFields(message, patternDescription); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * @param message | ||
57 | * The template of the exception message | ||
58 | * @param context | ||
59 | * The data elements to be used to instantiate the template. Can be null if no context parameter is | ||
60 | * defined | ||
61 | * @param patternDescription | ||
62 | * the PatternDescription where the exception occurred | ||
63 | */ | ||
64 | public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription) { | ||
65 | super(bind(message, context)); | ||
66 | initializeFields(shortMessage, patternDescription); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * @param message | ||
71 | * The template of the exception message | ||
72 | * @param context | ||
73 | * The data elements to be used to instantiate the template. Can be null if no context parameter is | ||
74 | * defined | ||
75 | * @param patternDescription | ||
76 | * the PatternDescription where the exception occurred | ||
77 | */ | ||
78 | public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription, | ||
79 | Throwable cause) { | ||
80 | super(bind(message, context), cause); | ||
81 | initializeFields(shortMessage, patternDescription); | ||
82 | } | ||
83 | |||
84 | public Object getPatternDescription() { | ||
85 | return patternDescription; | ||
86 | } | ||
87 | |||
88 | public String getShortMessage() { | ||
89 | return shortMessage; | ||
90 | } | ||
91 | |||
92 | private void initializeFields(String shortMessage, Object patternDescription) { | ||
93 | this.patternDescription = patternDescription; | ||
94 | this.shortMessage = shortMessage; | ||
95 | } | ||
96 | |||
97 | |||
98 | public void setPatternDescription(Object patternDescription) { | ||
99 | this.patternDescription = patternDescription; | ||
100 | } | ||
101 | |||
102 | } \ No newline at end of file | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java new file mode 100644 index 00000000..1998df9d --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java | |||
@@ -0,0 +1,240 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2008 Gabor Bergmann 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.matchers.planning; | ||
11 | |||
12 | import java.util.Arrays; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.List; | ||
15 | import java.util.Set; | ||
16 | import java.util.WeakHashMap; | ||
17 | import java.util.stream.Collectors; | ||
18 | |||
19 | import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext; | ||
20 | import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper; | ||
21 | import tools.refinery.viatra.runtime.matchers.planning.operations.POperation; | ||
22 | import tools.refinery.viatra.runtime.matchers.planning.operations.PProject; | ||
23 | import tools.refinery.viatra.runtime.matchers.planning.operations.PStart; | ||
24 | import tools.refinery.viatra.runtime.matchers.psystem.PBody; | ||
25 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
26 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
27 | import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement; | ||
28 | |||
29 | /** | ||
30 | * A plan representing a subset of (or possibly all the) constraints evaluated. A SubPlan instance is responsible for | ||
31 | * representing a state of the plan; but after it is initialized it is expected be immutable | ||
32 | * (exception: inferred constraints, see {@link #inferConstraint(PConstraint)}). | ||
33 | * | ||
34 | * <p> A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans. | ||
35 | * Important maintained information: <ul> | ||
36 | * <li>set of <b>variables</b> whose values are known when the runtime evaluation is at this stage, | ||
37 | * <li>set of <b>constraints</b> that are known to hold true at this point. | ||
38 | * </ul> | ||
39 | * | ||
40 | * <p> Recommended to instantiate via a {@link SubPlanFactory} or subclasses, | ||
41 | * so that query planners can subclass SubPlan if needed. | ||
42 | * | ||
43 | * @author Gabor Bergmann | ||
44 | * | ||
45 | */ | ||
46 | public class SubPlan { | ||
47 | private PBody body; | ||
48 | private List<? extends SubPlan> parentPlans; | ||
49 | private POperation operation; | ||
50 | |||
51 | private final Set<PVariable> visibleVariables; | ||
52 | private final Set<PVariable> allVariables; | ||
53 | private final Set<PVariable> introducedVariables; // delta compared to first parent | ||
54 | private Set<PConstraint> allConstraints; | ||
55 | private Set<PConstraint> deltaConstraints; // delta compared to all parents | ||
56 | private Set<PConstraint> externallyInferredConstraints; // inferred in addition to direct consequences of the operation and parents | ||
57 | |||
58 | |||
59 | |||
60 | |||
61 | |||
62 | /** | ||
63 | * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans. | ||
64 | */ | ||
65 | public SubPlan(PBody body, POperation operation, SubPlan... parentPlans) { | ||
66 | this(body, operation, Arrays.asList(parentPlans)); | ||
67 | } | ||
68 | /** | ||
69 | * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans. | ||
70 | */ | ||
71 | public SubPlan(PBody body, POperation operation, List<? extends SubPlan> parentPlans) { | ||
72 | super(); | ||
73 | this.body = body; | ||
74 | this.parentPlans = parentPlans; | ||
75 | this.operation = operation; | ||
76 | |||
77 | this.externallyInferredConstraints = new HashSet<PConstraint>(); | ||
78 | this.deltaConstraints = new HashSet<PConstraint>(operation.getDeltaConstraints()); | ||
79 | |||
80 | this.allVariables = new HashSet<PVariable>(); | ||
81 | for (PConstraint constraint: deltaConstraints) { | ||
82 | this.allVariables.addAll(constraint.getDeducedVariables()); | ||
83 | } | ||
84 | this.allConstraints = new HashSet<PConstraint>(deltaConstraints); | ||
85 | for (SubPlan parentPlan: parentPlans) { | ||
86 | this.allConstraints.addAll(parentPlan.getAllEnforcedConstraints()); | ||
87 | this.allVariables.addAll(parentPlan.getAllDeducedVariables()); | ||
88 | } | ||
89 | |||
90 | // TODO this is ugly a bit | ||
91 | if (operation instanceof PStart) { | ||
92 | this.visibleVariables = new HashSet<PVariable>(((PStart) operation).getAPrioriVariables()); | ||
93 | this.allVariables.addAll(visibleVariables); | ||
94 | } else if (operation instanceof PProject) { | ||
95 | this.visibleVariables = new HashSet<PVariable>(((PProject) operation).getToVariables()); | ||
96 | } else { | ||
97 | this.visibleVariables = new HashSet<PVariable>(); | ||
98 | for (SubPlan parentPlan: parentPlans) | ||
99 | this.visibleVariables.addAll(parentPlan.getVisibleVariables()); | ||
100 | for (PConstraint constraint: deltaConstraints) | ||
101 | this.visibleVariables.addAll(constraint.getDeducedVariables()); | ||
102 | } | ||
103 | |||
104 | this.introducedVariables = new HashSet<PVariable>(this.visibleVariables); | ||
105 | if (!parentPlans.isEmpty()) | ||
106 | introducedVariables.removeAll(parentPlans.get(0).getVisibleVariables()); | ||
107 | |||
108 | operation.checkConsistency(this); | ||
109 | } | ||
110 | |||
111 | |||
112 | @Override | ||
113 | public String toString() { | ||
114 | return toLongString(); | ||
115 | } | ||
116 | public String toShortString() { | ||
117 | return String.format("Plan{%s}:%s", | ||
118 | visibleVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")), | ||
119 | operation.getShortName()); | ||
120 | } | ||
121 | public String toLongString() { | ||
122 | return String.format("%s<%s>", | ||
123 | toShortString(), | ||
124 | parentPlans.stream().map(Object::toString).collect(Collectors.joining("; "))); | ||
125 | } | ||
126 | |||
127 | |||
128 | /** | ||
129 | * All constraints that are known to hold at this point | ||
130 | */ | ||
131 | public Set<PConstraint> getAllEnforcedConstraints() { | ||
132 | return allConstraints; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * The new constraints enforced at this stage of plan, that aren't yet enforced at parents | ||
137 | * (results are also included in {@link SubPlan#getAllEnforcedConstraints()}) | ||
138 | */ | ||
139 | public Set<PConstraint> getDeltaEnforcedConstraints() { | ||
140 | return deltaConstraints; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * Indicate that a given constraint was found to be automatically satisfied at this point | ||
145 | * without additional operations. | ||
146 | * (results are also included in {@link SubPlan#getDeltaEnforcedConstraints()}) | ||
147 | * | ||
148 | * <p>Warning: not propagated automatically to child plans, | ||
149 | * so best to invoke before constructing further SubPlans. </p> | ||
150 | */ | ||
151 | public void inferConstraint(PConstraint constraint) { | ||
152 | externallyInferredConstraints.add(constraint); | ||
153 | deltaConstraints.add(constraint); | ||
154 | allConstraints.add(constraint); | ||
155 | } | ||
156 | |||
157 | public PBody getBody() { | ||
158 | return body; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * Variables which are assigned a value at this point | ||
163 | * (results are also included in {@link SubPlan#getAllDeducedVariables()}) | ||
164 | */ | ||
165 | public Set<PVariable> getVisibleVariables() { | ||
166 | return visibleVariables; | ||
167 | } | ||
168 | /** | ||
169 | * Variables which have been assigned a value; | ||
170 | * includes visible variables (see {@link #getVisibleVariables()}) | ||
171 | * and additionally any variables hidden by a projection (see {@link PProject}). | ||
172 | */ | ||
173 | public Set<PVariable> getAllDeducedVariables() { | ||
174 | return allVariables; | ||
175 | } | ||
176 | /** | ||
177 | * Delta compared to first parent: variables that are visible here but were not visible at the first parent. | ||
178 | */ | ||
179 | public Set<PVariable> getIntroducedVariables() { | ||
180 | return introducedVariables; | ||
181 | } | ||
182 | public List<? extends SubPlan> getParentPlans() { | ||
183 | return parentPlans; | ||
184 | } | ||
185 | public POperation getOperation() { | ||
186 | return operation; | ||
187 | } | ||
188 | |||
189 | |||
190 | /** | ||
191 | * The closure of all type judgments of enforced constraints at this point. | ||
192 | * <p> No subsumption applied. | ||
193 | */ | ||
194 | public Set<TypeJudgement> getAllImpliedTypeJudgements(IQueryMetaContext context) { | ||
195 | Set<TypeJudgement> impliedJudgements = allImpliedTypeJudgements.get(context); | ||
196 | if (impliedJudgements == null) { | ||
197 | Set<TypeJudgement> equivalentJudgements = TypeHelper.getDirectJudgements(getAllEnforcedConstraints(), context); | ||
198 | impliedJudgements = TypeHelper.typeClosure(equivalentJudgements, context); | ||
199 | |||
200 | allImpliedTypeJudgements.put(context, impliedJudgements); | ||
201 | } | ||
202 | return impliedJudgements; | ||
203 | } | ||
204 | private WeakHashMap<IQueryMetaContext, Set<TypeJudgement>> allImpliedTypeJudgements = new WeakHashMap<IQueryMetaContext, Set<TypeJudgement>>(); | ||
205 | |||
206 | |||
207 | @Override | ||
208 | public int hashCode() { | ||
209 | final int prime = 31; | ||
210 | int result = 1; | ||
211 | result = prime * result | ||
212 | + ((operation == null) ? 0 : operation.hashCode()); | ||
213 | result = prime * result | ||
214 | + ((parentPlans == null) ? 0 : parentPlans.hashCode()); | ||
215 | return result; | ||
216 | } | ||
217 | @Override | ||
218 | public boolean equals(Object obj) { | ||
219 | if (this == obj) | ||
220 | return true; | ||
221 | if (obj == null) | ||
222 | return false; | ||
223 | if (!(obj instanceof SubPlan)) | ||
224 | return false; | ||
225 | SubPlan other = (SubPlan) obj; | ||
226 | if (operation == null) { | ||
227 | if (other.operation != null) | ||
228 | return false; | ||
229 | } else if (!operation.equals(other.operation)) | ||
230 | return false; | ||
231 | if (parentPlans == null) { | ||
232 | if (other.parentPlans != null) | ||
233 | return false; | ||
234 | } else if (!parentPlans.equals(other.parentPlans)) | ||
235 | return false; | ||
236 | return true; | ||
237 | } | ||
238 | |||
239 | |||
240 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java new file mode 100644 index 00000000..d0df5fac --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java | |||
@@ -0,0 +1,33 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning; | ||
10 | |||
11 | import tools.refinery.viatra.runtime.matchers.planning.operations.POperation; | ||
12 | import tools.refinery.viatra.runtime.matchers.psystem.PBody; | ||
13 | |||
14 | /** | ||
15 | * Single entry point for creating subplans. | ||
16 | * Can be subclassed by query planner to provide specialized SubPlans. | ||
17 | * @author Bergmann Gabor | ||
18 | * | ||
19 | */ | ||
20 | public class SubPlanFactory { | ||
21 | |||
22 | protected PBody body; | ||
23 | |||
24 | public SubPlanFactory(PBody body) { | ||
25 | super(); | ||
26 | this.body = body; | ||
27 | } | ||
28 | |||
29 | public SubPlan createSubPlan(POperation operation, SubPlan... parentPlans) { | ||
30 | return new SubPlan(body, operation, parentPlans); | ||
31 | } | ||
32 | |||
33 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java new file mode 100644 index 00000000..ed5d1cbb --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java | |||
@@ -0,0 +1,165 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2010 Gabor Bergmann 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.matchers.planning.helpers; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.Map; | ||
15 | import java.util.Set; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; | ||
18 | import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext; | ||
19 | import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException; | ||
20 | import tools.refinery.viatra.runtime.matchers.planning.SubPlan; | ||
21 | import tools.refinery.viatra.runtime.matchers.planning.SubPlanFactory; | ||
22 | import tools.refinery.viatra.runtime.matchers.planning.operations.PProject; | ||
23 | import tools.refinery.viatra.runtime.matchers.psystem.PBody; | ||
24 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
25 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
26 | import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer; | ||
27 | import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter; | ||
28 | |||
29 | /** | ||
30 | * @author Gabor Bergmann | ||
31 | * | ||
32 | */ | ||
33 | public class BuildHelper { | ||
34 | |||
35 | private BuildHelper() { | ||
36 | // Hiding constructor for utility class | ||
37 | } | ||
38 | |||
39 | // public static SubPlan naturalJoin(IOperationCompiler buildable, | ||
40 | // SubPlan primaryPlan, SubPlan secondaryPlan) { | ||
41 | // JoinHelper joinHelper = new JoinHelper(primaryPlan, secondaryPlan); | ||
42 | // return buildable.buildBetaNode(primaryPlan, secondaryPlan, joinHelper.getPrimaryMask(), | ||
43 | // joinHelper.getSecondaryMask(), joinHelper.getComplementerMask(), false); | ||
44 | // } | ||
45 | |||
46 | |||
47 | /** | ||
48 | * Reduces the number of tuples by trimming (existentially quantifying) the set of variables that <ul> | ||
49 | * <li> are visible in the subplan, | ||
50 | * <li> are not exported parameters, | ||
51 | * <li> have all their constraints already enforced in the subplan, | ||
52 | * </ul> and thus will not be needed anymore. | ||
53 | * | ||
54 | * @param onlyIfNotDetermined if true, no trimming performed unless there is at least one variable that is not functionally determined | ||
55 | * @return the plan after the trimming (possibly the original) | ||
56 | * @since 1.5 | ||
57 | */ | ||
58 | public static SubPlan trimUnneccessaryVariables(SubPlanFactory planFactory, /*IOperationCompiler buildable,*/ | ||
59 | SubPlan plan, boolean onlyIfNotDetermined, QueryAnalyzer analyzer) { | ||
60 | Set<PVariable> canBeTrimmed = new HashSet<PVariable>(); | ||
61 | Set<PVariable> variablesInPlan = plan.getVisibleVariables(); | ||
62 | for (PVariable trimCandidate : variablesInPlan) { | ||
63 | if (trimCandidate.getReferringConstraintsOfType(ExportedParameter.class).isEmpty()) { | ||
64 | if (plan.getAllEnforcedConstraints().containsAll(trimCandidate.getReferringConstraints())) | ||
65 | canBeTrimmed.add(trimCandidate); | ||
66 | } | ||
67 | } | ||
68 | final Set<PVariable> retainedVars = setMinus(variablesInPlan, canBeTrimmed); | ||
69 | if (!canBeTrimmed.isEmpty() && !(onlyIfNotDetermined && areVariablesDetermined(plan, retainedVars, canBeTrimmed, analyzer, false))) { | ||
70 | // TODO add smart ordering? | ||
71 | plan = planFactory.createSubPlan(new PProject(retainedVars), plan); | ||
72 | } | ||
73 | return plan; | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * @return true iff a set of given variables functionally determine all visible variables in the subplan according to the subplan's constraints | ||
78 | * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation; | ||
79 | * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism; | ||
80 | * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance | ||
81 | * @since 1.5 | ||
82 | */ | ||
83 | public static boolean areAllVariablesDetermined(SubPlan plan, Collection<PVariable> determining, QueryAnalyzer analyzer, boolean strict) { | ||
84 | return areVariablesDetermined(plan, determining, plan.getVisibleVariables(), analyzer, strict); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * @return true iff one set of given variables functionally determine the other set according to the subplan's constraints | ||
89 | * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation; | ||
90 | * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism; | ||
91 | * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance | ||
92 | * @since 1.5 | ||
93 | */ | ||
94 | public static boolean areVariablesDetermined(SubPlan plan, Collection<PVariable> determining, Collection<PVariable> determined, | ||
95 | QueryAnalyzer analyzer, boolean strict) { | ||
96 | Map<Set<PVariable>, Set<PVariable>> dependencies = analyzer.getFunctionalDependencies(plan.getAllEnforcedConstraints(), strict); | ||
97 | final Set<PVariable> closure = FunctionalDependencyHelper.closureOf(determining, dependencies); | ||
98 | final boolean isDetermined = closure.containsAll(determined); | ||
99 | return isDetermined; | ||
100 | } | ||
101 | |||
102 | private static <T> Set<T> setMinus(Set<T> a, Set<T> b) { | ||
103 | Set<T> difference = new HashSet<T>(a); | ||
104 | difference.removeAll(b); | ||
105 | return difference; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Finds an arbitrary constraint that is not enforced at the given plan. | ||
110 | * | ||
111 | * @param pSystem | ||
112 | * @param plan | ||
113 | * @return a PConstraint that is not enforced, if any, or null if all are enforced | ||
114 | */ | ||
115 | public static PConstraint getAnyUnenforcedConstraint(PBody pSystem, | ||
116 | SubPlan plan) { | ||
117 | Set<PConstraint> allEnforcedConstraints = plan.getAllEnforcedConstraints(); | ||
118 | Set<PConstraint> constraints = pSystem.getConstraints(); | ||
119 | for (PConstraint pConstraint : constraints) { | ||
120 | if (!allEnforcedConstraints.contains(pConstraint)) | ||
121 | return pConstraint; | ||
122 | } | ||
123 | return null; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Skips the last few steps, if any, that are projections, so that a custom projection can be added instead. | ||
128 | * Useful for connecting body final plans into the production node. | ||
129 | * | ||
130 | * @since 2.1 | ||
131 | */ | ||
132 | public static SubPlan eliminateTrailingProjections(SubPlan plan) { | ||
133 | while (plan.getOperation() instanceof PProject) | ||
134 | plan = plan.getParentPlans().get(0); | ||
135 | return plan; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Verifies whether all constraints are enforced and exported parameters are present. | ||
140 | * | ||
141 | * @param pSystem | ||
142 | * @param plan | ||
143 | * @throws ViatraQueryRuntimeException | ||
144 | */ | ||
145 | public static void finalCheck(final PBody pSystem, SubPlan plan, IQueryMetaContext context) { | ||
146 | PConstraint unenforcedConstraint = getAnyUnenforcedConstraint(pSystem, plan); | ||
147 | if (unenforcedConstraint != null) { | ||
148 | throw new QueryProcessingException( | ||
149 | "Pattern matcher construction terminated without successfully enforcing constraint {1}." | ||
150 | + " Could be caused if the value of some variables can not be deduced, e.g. by circularity of pattern constraints.", | ||
151 | new String[] { unenforcedConstraint.toString() }, "Could not enforce a pattern constraint", null); | ||
152 | } | ||
153 | for (ExportedParameter export : pSystem | ||
154 | .getConstraintsOfType(ExportedParameter.class)) { | ||
155 | if (!export.isReadyAt(plan, context)) { | ||
156 | throw new QueryProcessingException( | ||
157 | "Exported pattern parameter {1} could not be deduced during pattern matcher construction." | ||
158 | + " A pattern constraint is required to positively deduce its value.", | ||
159 | new String[] { export.getParameterName() }, "Could not calculate pattern parameter", | ||
160 | null); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java new file mode 100644 index 00000000..40835f52 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java | |||
@@ -0,0 +1,143 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2013, Adam Dudas, 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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.helpers; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Collections; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.HashSet; | ||
15 | import java.util.Map; | ||
16 | import java.util.Map.Entry; | ||
17 | import java.util.Set; | ||
18 | |||
19 | import tools.refinery.viatra.runtime.matchers.util.Sets; | ||
20 | |||
21 | /** | ||
22 | * Helper utility class for functional dependency analysis. | ||
23 | * | ||
24 | * Throughout this class attribute sets are represented as generic sets and functional dependencies as maps from | ||
25 | * attribute set (generic sets) to attribute set (generic sets) | ||
26 | * | ||
27 | * @author Adam Dudas | ||
28 | * | ||
29 | */ | ||
30 | public class FunctionalDependencyHelper { | ||
31 | |||
32 | private FunctionalDependencyHelper() { | ||
33 | // Hiding constructor for utility class | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * Get the closure of the specified attribute set relative to the specified functional dependencies. | ||
38 | * | ||
39 | * @param attributes | ||
40 | * The attributes to get the closure of. | ||
41 | * @param dependencies | ||
42 | * The functional dependencies of which the closure operation is relative to. | ||
43 | * @return The closure of the specified attribute set relative to the specified functional dependencies. | ||
44 | */ | ||
45 | public static <A> Set<A> closureOf(Collection<A> attributes, Map<Set<A>, Set<A>> dependencies) { | ||
46 | Set<A> closureSet = new HashSet<A>(); | ||
47 | |||
48 | for (Set<A> closureSet1 = new HashSet<A>(attributes); closureSet.addAll(closureSet1);) { | ||
49 | closureSet1 = new HashSet<A>(); | ||
50 | for (Entry<Set<A>, Set<A>> dependency : dependencies.entrySet()) { | ||
51 | if (closureSet.containsAll(dependency.getKey())) | ||
52 | closureSet1.addAll(dependency.getValue()); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | return closureSet; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * @return true if the dependency from the left set to the right set is trivial | ||
61 | * @since 1.5 | ||
62 | */ | ||
63 | public static <A> boolean isTrivial(Set<A> left, Set<A> right) { | ||
64 | return left.containsAll(right); | ||
65 | } | ||
66 | |||
67 | /*** | ||
68 | * Returns the dependency set over attributes in {@link targetAttributes} that are implied by a given source dependency set. | ||
69 | * <p> Note: exponential in the size of the target attribute set. | ||
70 | * <p> Note: minimality of the returned dependency set is currently not guaranteed. | ||
71 | * @param originalDependencies all dependencies that are known to hold on a wider set of attributes | ||
72 | * @param targetAttributes the set of attributes we are interested in | ||
73 | * @since 1.5 | ||
74 | */ | ||
75 | public static <A> Map<Set<A>, Set<A>> projectDependencies(Map<Set<A>, Set<A>> originalDependencies, Set<A> targetAttributes) { | ||
76 | // only those attributes are considered as left-hand-side candidates that occur at least once in dependencies | ||
77 | Set<A> leftCandidates = new HashSet<A>(); | ||
78 | for (Entry<Set<A>, Set<A>> dependency : originalDependencies.entrySet()) { | ||
79 | if (!isTrivial(dependency.getKey(), dependency.getValue())) // only if non-trivial | ||
80 | leftCandidates.addAll(Sets.intersection(dependency.getKey(), targetAttributes)); | ||
81 | } | ||
82 | |||
83 | // Compute an initial list of nontrivial projected dependencies - it does not have to be minimal yet | ||
84 | Map<Set<A>, Set<A>> initialDependencies = new HashMap<Set<A>, Set<A>>(); | ||
85 | for (Set<A> leftSet : Sets.powerSet(leftCandidates)) { | ||
86 | Set<A> rightSet = Sets.intersection(closureOf(leftSet, originalDependencies), targetAttributes); | ||
87 | if (!isTrivial(leftSet, rightSet)) { | ||
88 | initialDependencies.put(leftSet, rightSet); | ||
89 | } | ||
90 | } | ||
91 | // Don't forget to include constants! | ||
92 | Set<A> constants = Sets.intersection(closureOf(Collections.<A>emptySet(), originalDependencies), targetAttributes); | ||
93 | if (! constants.isEmpty()) { | ||
94 | initialDependencies.put(Collections.<A>emptySet(), constants); | ||
95 | } | ||
96 | |||
97 | // Omit those dependencies where the LHS has superfluous attributes | ||
98 | Map<Set<A>, Set<A>> solidDependencies = new HashMap<Set<A>, Set<A>>(); | ||
99 | for (Entry<Set<A>, Set<A>> dependency : initialDependencies.entrySet()) { | ||
100 | Set<A> leftSet = dependency.getKey(); | ||
101 | Set<A> rightSet = dependency.getValue(); | ||
102 | boolean solid = true; | ||
103 | for (A skipped : leftSet) { // what if we skip one attribute from the left set? | ||
104 | Set<A> singleton = Collections.singleton(skipped); | ||
105 | Set<A> candidate = Sets.difference(leftSet, singleton); | ||
106 | Set<A> rightCandidate = initialDependencies.get(candidate); | ||
107 | if (rightCandidate != null) { | ||
108 | if (Sets.union(rightCandidate, singleton).containsAll(rightSet)) { | ||
109 | solid = false; | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | if (solid) { | ||
115 | solidDependencies.put(leftSet, rightSet); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // TODO perform proper minimization, | ||
120 | // see e.g. page 45 in http://www.cs.ubc.ca/~hkhosrav/db/slides/03.design%20theory.pdf | ||
121 | |||
122 | return Collections.unmodifiableMap(solidDependencies); | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * Adds a given dependency to a mutable accumulator. | ||
127 | * @since 1.5 | ||
128 | */ | ||
129 | public static <A> void includeDependency(Map<Set<A>, Set<A>> accumulator, Set<A> left, Set<A> right) { | ||
130 | Set<A> accumulatorRights = accumulator.computeIfAbsent(left, l -> new HashSet<>()); | ||
131 | accumulatorRights.addAll(right); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * Adds all given dependencies to a mutable accumulator. | ||
136 | * @since 1.5 | ||
137 | */ | ||
138 | public static <A> void includeDependencies(Map<Set<A>, Set<A>> accumulator, Map<Set<A>, Set<A>> additionalDependencies) { | ||
139 | for (Entry<Set<A>, Set<A>> entry : additionalDependencies.entrySet()) { | ||
140 | includeDependency(accumulator, entry.getKey(), entry.getValue()); | ||
141 | } | ||
142 | } | ||
143 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java new file mode 100644 index 00000000..b4f848a7 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java | |||
@@ -0,0 +1,62 @@ | |||
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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.helpers; | ||
10 | |||
11 | import java.util.Optional; | ||
12 | import java.util.function.BiFunction; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
15 | import tools.refinery.viatra.runtime.matchers.util.Accuracy; | ||
16 | |||
17 | /** | ||
18 | * Helpers dealing with optionally present statistics information | ||
19 | * | ||
20 | * @author Gabor Bergmann | ||
21 | * @since 2.1 | ||
22 | * | ||
23 | */ | ||
24 | public class StatisticsHelper { | ||
25 | |||
26 | private StatisticsHelper() { | ||
27 | // Hidden utility class constructor | ||
28 | } | ||
29 | |||
30 | public static Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy, | ||
31 | BiFunction<TupleMask, Accuracy, Optional<Long>> estimateCardinality) | ||
32 | { | ||
33 | if (groupMask.isIdentity()) return Optional.of(1.0); | ||
34 | |||
35 | Accuracy numeratorAccuracy = requiredAccuracy; | ||
36 | Accuracy denominatorAccuracy = requiredAccuracy.reciprocal(); | ||
37 | TupleMask identityMask = TupleMask.identity(groupMask.sourceWidth); | ||
38 | |||
39 | Optional<Long> totalCountEstimate = estimateCardinality.apply(identityMask, numeratorAccuracy); | ||
40 | Optional<Long> bucketCountEstimate = estimateCardinality.apply(groupMask, denominatorAccuracy); | ||
41 | |||
42 | return totalCountEstimate.flatMap(matchCount -> | ||
43 | bucketCountEstimate.map(bucketCount -> | ||
44 | bucketCount == 0L ? 0L : ((double) matchCount) / bucketCount | ||
45 | )); | ||
46 | } | ||
47 | |||
48 | public static Optional<Double> min(Optional<Double> a, Optional<Double> b) { | ||
49 | if (b.isPresent()) { | ||
50 | if (a.isPresent()) { | ||
51 | return Optional.of(Math.min(a.get(), b.get())); | ||
52 | } else return b; | ||
53 | } else return a; | ||
54 | } | ||
55 | public static Optional<Double> min(Optional<Double> a, double b) { | ||
56 | if (a.isPresent()) { | ||
57 | return Optional.of(Math.min(a.get(), b)); | ||
58 | } else return Optional.of(b); | ||
59 | } | ||
60 | |||
61 | |||
62 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java new file mode 100644 index 00000000..926a591f --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java | |||
@@ -0,0 +1,217 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2010 Gabor Bergmann 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.matchers.planning.helpers; | ||
11 | |||
12 | import java.util.Collections; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.HashSet; | ||
15 | import java.util.LinkedList; | ||
16 | import java.util.Map; | ||
17 | import java.util.Map.Entry; | ||
18 | import java.util.Queue; | ||
19 | import java.util.Set; | ||
20 | import java.util.stream.Collectors; | ||
21 | |||
22 | import tools.refinery.viatra.runtime.matchers.context.IInputKey; | ||
23 | import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext; | ||
24 | import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint; | ||
25 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
26 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
27 | import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement; | ||
28 | |||
29 | /** | ||
30 | * @author Gabor Bergmann | ||
31 | * @author Tamas Szabo | ||
32 | */ | ||
33 | public class TypeHelper { | ||
34 | |||
35 | private TypeHelper() { | ||
36 | // Hiding constructor for utility class | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * Collects the type constraints for the specified collection of variables. The type constraints consist of the | ||
41 | * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with | ||
42 | * through equalities. | ||
43 | * | ||
44 | * @param variables | ||
45 | * the variables in question | ||
46 | * @param constraints | ||
47 | * the constraints in the pattern body | ||
48 | * @param context | ||
49 | * the query meta context | ||
50 | * @return the mapping from variable to set of type constraints | ||
51 | * @since 1.6 | ||
52 | */ | ||
53 | public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables, | ||
54 | Set<PConstraint> constraints, IQueryMetaContext context) { | ||
55 | Map<PVariable, Set<TypeJudgement>> typeMap = TypeHelper.inferUnaryTypes(constraints, context); | ||
56 | return inferUnaryTypesFor(variables, typeMap); | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Collects the type constraints for the specified collection of variables. The type constraints consist of the | ||
61 | * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with | ||
62 | * through equalities. | ||
63 | * | ||
64 | * The method accepts a type map which is the result of the basic type inference from the | ||
65 | * {@link TypeHelper.inferUnaryTypes} method. The purpose of this method is that the type map can be reused across | ||
66 | * several calls to this method. | ||
67 | * | ||
68 | * @param variables | ||
69 | * the variables in question | ||
70 | * @param typeMap | ||
71 | * the type map of inference results | ||
72 | * @return the mapping from variable to set of type constraints | ||
73 | * @since 1.6 | ||
74 | */ | ||
75 | public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables, | ||
76 | Map<PVariable, Set<TypeJudgement>> typeMap) { | ||
77 | Map<PVariable, Set<IInputKey>> result = new HashMap<PVariable, Set<IInputKey>>(); | ||
78 | |||
79 | for (PVariable original : variables) { | ||
80 | // it can happen that the variable was unified into an other one due to equalities | ||
81 | Set<IInputKey> keys = new HashSet<IInputKey>(); | ||
82 | PVariable current = original; | ||
83 | |||
84 | while (current != null) { | ||
85 | Set<TypeJudgement> judgements = typeMap.get(current); | ||
86 | if (judgements != null) { | ||
87 | for (TypeJudgement judgement : judgements) { | ||
88 | keys.add(judgement.getInputKey()); | ||
89 | } | ||
90 | } | ||
91 | current = current.getDirectUnifiedInto(); | ||
92 | } | ||
93 | |||
94 | result.put(original, keys); | ||
95 | } | ||
96 | |||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * Infers unary type information for variables, based on the given constraints. | ||
102 | * | ||
103 | * Subsumptions are not taken into account. | ||
104 | * | ||
105 | * @param constraints | ||
106 | * the set of constraints to extract type info from | ||
107 | */ | ||
108 | public static Map<PVariable, Set<TypeJudgement>> inferUnaryTypes(Set<PConstraint> constraints, | ||
109 | IQueryMetaContext context) { | ||
110 | Set<TypeJudgement> equivalentJudgements = getDirectJudgements(constraints, context); | ||
111 | Set<TypeJudgement> impliedJudgements = typeClosure(equivalentJudgements, context); | ||
112 | |||
113 | Map<PVariable, Set<TypeJudgement>> results = new HashMap<PVariable, Set<TypeJudgement>>(); | ||
114 | for (TypeJudgement typeJudgement : impliedJudgements) { | ||
115 | final IInputKey inputKey = typeJudgement.getInputKey(); | ||
116 | if (inputKey.getArity() == 1) { | ||
117 | PVariable variable = (PVariable) typeJudgement.getVariablesTuple().get(0); | ||
118 | Set<TypeJudgement> inferredTypes = results.computeIfAbsent(variable, v -> new HashSet<>()); | ||
119 | inferredTypes.add(typeJudgement); | ||
120 | } | ||
121 | } | ||
122 | return results; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * Gets direct judgements reported by constraints. No closure is applied yet. | ||
127 | */ | ||
128 | public static Set<TypeJudgement> getDirectJudgements(Set<PConstraint> constraints, IQueryMetaContext context) { | ||
129 | Set<TypeJudgement> equivalentJudgements = new HashSet<TypeJudgement>(); | ||
130 | for (PConstraint pConstraint : constraints) { | ||
131 | if (pConstraint instanceof ITypeInfoProviderConstraint) { | ||
132 | equivalentJudgements.addAll(((ITypeInfoProviderConstraint) pConstraint).getImpliedJudgements(context)); | ||
133 | } | ||
134 | } | ||
135 | return equivalentJudgements; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Calculates the closure of a set of type judgements, with respect to supertyping. | ||
140 | * | ||
141 | * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes | ||
142 | */ | ||
143 | public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> typesToClose, IQueryMetaContext context) { | ||
144 | return typeClosure(Collections.<TypeJudgement> emptySet(), typesToClose, context); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * Calculates the closure of a set of type judgements (with respect to supertyping), where the closure has been | ||
149 | * calculated before for a given base set, but not for a separate delta set. | ||
150 | * <p> | ||
151 | * Precondition: the set (typesToClose MINUS delta) is already closed w.r.t. supertyping. | ||
152 | * | ||
153 | * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes | ||
154 | * @since 1.6 | ||
155 | */ | ||
156 | public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> preclosedBaseSet, Set<TypeJudgement> delta, | ||
157 | IQueryMetaContext context) { | ||
158 | Queue<TypeJudgement> queue = delta.stream().filter(input -> !preclosedBaseSet.contains(input)).collect(Collectors.toCollection(LinkedList::new)); | ||
159 | if (queue.isEmpty()) | ||
160 | return preclosedBaseSet; | ||
161 | |||
162 | Set<TypeJudgement> closure = new HashSet<TypeJudgement>(preclosedBaseSet); | ||
163 | |||
164 | Map<TypeJudgement, Set<TypeJudgement>> conditionalImplications = new HashMap<>(); | ||
165 | for (TypeJudgement typeJudgement : closure) { | ||
166 | conditionalImplications.putAll(typeJudgement.getConditionalImpliedJudgements(context)); | ||
167 | } | ||
168 | |||
169 | do { | ||
170 | TypeJudgement deltaType = queue.poll(); | ||
171 | if (closure.add(deltaType)) { | ||
172 | // direct implications | ||
173 | queue.addAll(deltaType.getDirectlyImpliedJudgements(context)); | ||
174 | |||
175 | // conditional implications, source key processed before, this is the condition key | ||
176 | final Set<TypeJudgement> implicationSet = conditionalImplications.get(deltaType); | ||
177 | if (implicationSet != null) { | ||
178 | queue.addAll(implicationSet); | ||
179 | } | ||
180 | |||
181 | // conditional implications, this is the source key | ||
182 | Map<TypeJudgement, Set<TypeJudgement>> deltaConditionalImplications = deltaType | ||
183 | .getConditionalImpliedJudgements(context); | ||
184 | for (Entry<TypeJudgement, Set<TypeJudgement>> entry : deltaConditionalImplications.entrySet()) { | ||
185 | if (closure.contains(entry.getKey())) { | ||
186 | // condition processed before | ||
187 | queue.addAll(entry.getValue()); | ||
188 | } else { | ||
189 | // condition not processed yet | ||
190 | conditionalImplications.computeIfAbsent(entry.getKey(), key -> new HashSet<>()) | ||
191 | .addAll(entry.getValue()); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | } while (!queue.isEmpty()); | ||
196 | |||
197 | return closure; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * Calculates a remainder set of types from a larger set, that are not subsumed by a given set of subsuming types. | ||
202 | * | ||
203 | * @param subsumableTypes | ||
204 | * a set of types from which some may be implied by the subsuming types | ||
205 | * @param subsumingTypes | ||
206 | * a set of types that may imply some of the subsuming types | ||
207 | * @return the collection of types in subsumableTypes that are NOT identical to or supertypes of any type in | ||
208 | * subsumingTypes. | ||
209 | */ | ||
210 | public static Set<TypeJudgement> subsumeTypes(Set<TypeJudgement> subsumableTypes, Set<TypeJudgement> subsumingTypes, | ||
211 | IQueryMetaContext context) { | ||
212 | Set<TypeJudgement> closure = typeClosure(subsumingTypes, context); | ||
213 | Set<TypeJudgement> subsumed = new HashSet<TypeJudgement>(subsumableTypes); | ||
214 | subsumed.removeAll(closure); | ||
215 | return subsumed; | ||
216 | } | ||
217 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java new file mode 100644 index 00000000..2c285b54 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java | |||
@@ -0,0 +1,94 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Collections; | ||
12 | import java.util.Set; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.planning.SubPlan; | ||
15 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
16 | import tools.refinery.viatra.runtime.matchers.util.Preconditions; | ||
17 | |||
18 | /** | ||
19 | * Represents a constraint application on a single parent SubPlan. | ||
20 | * <p> Either a "selection" filter operation according to a deferred PConstraint (or transform in case of eval/aggregate), or | ||
21 | * alternatively a shorthand for PJoin + a PEnumerate on the right input for an enumerable PConstraint. | ||
22 | * | ||
23 | * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint, | ||
24 | * it is the responsibility of the compiler to check them for equality. | ||
25 | * | ||
26 | * @author Bergmann Gabor | ||
27 | * | ||
28 | */ | ||
29 | public class PApply extends POperation { | ||
30 | |||
31 | private PConstraint pConstraint; | ||
32 | |||
33 | public PApply(PConstraint pConstraint) { | ||
34 | super(); | ||
35 | this.pConstraint = pConstraint; | ||
36 | } | ||
37 | public PConstraint getPConstraint() { | ||
38 | return pConstraint; | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public String getShortName() { | ||
43 | return String.format("APPLY_%s", pConstraint.toString()); | ||
44 | } | ||
45 | |||
46 | @Override | ||
47 | public Set<? extends PConstraint> getDeltaConstraints() { | ||
48 | return Collections.singleton(pConstraint); | ||
49 | } | ||
50 | |||
51 | @Override | ||
52 | public int numParentSubPlans() { | ||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | @Override | ||
57 | public void checkConsistency(SubPlan subPlan) { | ||
58 | super.checkConsistency(subPlan); | ||
59 | for (SubPlan parentPlan : subPlan.getParentPlans()) | ||
60 | Preconditions.checkArgument(!parentPlan.getAllEnforcedConstraints().contains(pConstraint), | ||
61 | "Double-checking constraint %s", pConstraint); | ||
62 | // TODO obtain context? | ||
63 | //if (pConstraint instanceof DeferredPConstraint) | ||
64 | // Preconditions.checkArgument(((DeferredPConstraint) pConstraint).isReadyAt(subPlan, context)) | ||
65 | } | ||
66 | |||
67 | @Override | ||
68 | public int hashCode() { | ||
69 | final int prime = 31; | ||
70 | int result = 1; | ||
71 | result = prime | ||
72 | * result | ||
73 | + ((pConstraint == null) ? 0 : pConstraint | ||
74 | .hashCode()); | ||
75 | return result; | ||
76 | } | ||
77 | @Override | ||
78 | public boolean equals(Object obj) { | ||
79 | if (this == obj) | ||
80 | return true; | ||
81 | if (obj == null) | ||
82 | return false; | ||
83 | if (!(obj instanceof PApply)) | ||
84 | return false; | ||
85 | PApply other = (PApply) obj; | ||
86 | if (pConstraint == null) { | ||
87 | if (other.pConstraint != null) | ||
88 | return false; | ||
89 | } else if (!pConstraint.equals(other.pConstraint)) | ||
90 | return false; | ||
91 | return true; | ||
92 | } | ||
93 | |||
94 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java new file mode 100644 index 00000000..a975d50c --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java | |||
@@ -0,0 +1,76 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Collections; | ||
12 | import java.util.Set; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint; | ||
15 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
16 | |||
17 | /** | ||
18 | * Represents a base relation defined by the instance set of an enumerable PConstraint; there are no parent SubPlans. | ||
19 | * | ||
20 | * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint, | ||
21 | * it is the responsibility of the compiler to check them for equality. | ||
22 | * @author Bergmann Gabor | ||
23 | * | ||
24 | */ | ||
25 | public class PEnumerate extends POperation { | ||
26 | |||
27 | EnumerablePConstraint enumerablePConstraint; | ||
28 | |||
29 | public PEnumerate(EnumerablePConstraint enumerablePConstraint) { | ||
30 | super(); | ||
31 | this.enumerablePConstraint = enumerablePConstraint; | ||
32 | } | ||
33 | public EnumerablePConstraint getEnumerablePConstraint() { | ||
34 | return enumerablePConstraint; | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public Set<? extends PConstraint> getDeltaConstraints() { | ||
39 | return Collections.singleton(enumerablePConstraint); | ||
40 | } | ||
41 | @Override | ||
42 | public int numParentSubPlans() { | ||
43 | return 0; | ||
44 | } | ||
45 | @Override | ||
46 | public String getShortName() { | ||
47 | return enumerablePConstraint.toString(); | ||
48 | } | ||
49 | @Override | ||
50 | public int hashCode() { | ||
51 | final int prime = 31; | ||
52 | int result = 1; | ||
53 | result = prime | ||
54 | * result | ||
55 | + ((enumerablePConstraint == null) ? 0 : enumerablePConstraint | ||
56 | .hashCode()); | ||
57 | return result; | ||
58 | } | ||
59 | @Override | ||
60 | public boolean equals(Object obj) { | ||
61 | if (this == obj) | ||
62 | return true; | ||
63 | if (obj == null) | ||
64 | return false; | ||
65 | if (!(obj instanceof PEnumerate)) | ||
66 | return false; | ||
67 | PEnumerate other = (PEnumerate) obj; | ||
68 | if (enumerablePConstraint == null) { | ||
69 | if (other.enumerablePConstraint != null) | ||
70 | return false; | ||
71 | } else if (!enumerablePConstraint.equals(other.enumerablePConstraint)) | ||
72 | return false; | ||
73 | return true; | ||
74 | } | ||
75 | |||
76 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java new file mode 100644 index 00000000..10e0a85a --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java | |||
@@ -0,0 +1,64 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Collections; | ||
12 | import java.util.Set; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
15 | |||
16 | /** | ||
17 | * Represents a natural join of two parent SubPlans. | ||
18 | * @author Bergmann Gabor | ||
19 | * | ||
20 | */ | ||
21 | public class PJoin extends POperation { | ||
22 | |||
23 | // // TODO leave here? is this a problem in equivalnece checking? | ||
24 | // private Set<PVariable> onVariables; | ||
25 | |||
26 | public PJoin(/*Set<PVariable> onVariables*/) { | ||
27 | super(); | ||
28 | //this.onVariables = new HashSet<PVariable>(onVariables); | ||
29 | } | ||
30 | // public Set<PVariable> getOnVariables() { | ||
31 | // return onVariables; | ||
32 | // } | ||
33 | |||
34 | @Override | ||
35 | public Set<? extends PConstraint> getDeltaConstraints() { | ||
36 | return Collections.emptySet(); | ||
37 | } | ||
38 | @Override | ||
39 | public int numParentSubPlans() { | ||
40 | return 2; | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public String getShortName() { | ||
45 | return "JOIN"; //String.format("JOIN_{%s}", Joiner.on(",").join(onVariables)); | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public int hashCode() { | ||
50 | return getClass().hashCode(); | ||
51 | } | ||
52 | @Override | ||
53 | public boolean equals(Object obj) { | ||
54 | if (this == obj) | ||
55 | return true; | ||
56 | if (obj == null) | ||
57 | return false; | ||
58 | if (!(obj instanceof PJoin)) | ||
59 | return false; | ||
60 | return true; | ||
61 | } | ||
62 | |||
63 | |||
64 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java new file mode 100644 index 00000000..e71cf217 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java | |||
@@ -0,0 +1,52 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Set; | ||
12 | |||
13 | import tools.refinery.viatra.runtime.matchers.planning.SubPlan; | ||
14 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
15 | import tools.refinery.viatra.runtime.matchers.util.Preconditions; | ||
16 | |||
17 | /** | ||
18 | * Abstract superclass for representing a high-level query evaluation operation. | ||
19 | * | ||
20 | * <p> Subclasses correspond to various POperations modeled after relational algebra. | ||
21 | * | ||
22 | * @author Bergmann Gabor | ||
23 | * | ||
24 | */ | ||
25 | public abstract class POperation { | ||
26 | |||
27 | /** | ||
28 | * Newly enforced constraints | ||
29 | */ | ||
30 | public abstract Set<? extends PConstraint> getDeltaConstraints(); | ||
31 | |||
32 | public abstract String getShortName(); | ||
33 | |||
34 | /** | ||
35 | * @return the number of SubPlans that must be specified as parents | ||
36 | */ | ||
37 | public abstract int numParentSubPlans(); | ||
38 | |||
39 | /** | ||
40 | * Checks whether this constraint can be properly applied at the given SubPlan. | ||
41 | */ | ||
42 | public void checkConsistency(SubPlan subPlan) { | ||
43 | Preconditions.checkArgument(this == subPlan.getOperation(), "POperation misalignment"); | ||
44 | Preconditions.checkArgument(subPlan.getParentPlans().size() == numParentSubPlans(), "Incorrect number of parent SubPlans"); | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public String toString() { | ||
49 | return getShortName(); | ||
50 | } | ||
51 | |||
52 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java new file mode 100644 index 00000000..d0539b2c --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java | |||
@@ -0,0 +1,109 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Collections; | ||
13 | import java.util.List; | ||
14 | import java.util.Set; | ||
15 | import java.util.stream.Collectors; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.planning.SubPlan; | ||
18 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
19 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
20 | import tools.refinery.viatra.runtime.matchers.util.Preconditions; | ||
21 | |||
22 | /** | ||
23 | * Represents a projection of a single parent SubPlan onto a limited set of variables. | ||
24 | * <p> May optionally prescribe an ordering of variables (List, as opposed to Set). | ||
25 | * | ||
26 | * @author Bergmann Gabor | ||
27 | * | ||
28 | */ | ||
29 | public class PProject extends POperation { | ||
30 | |||
31 | private Collection<PVariable> toVariables; | ||
32 | private boolean ordered; | ||
33 | |||
34 | |||
35 | public PProject(Set<PVariable> toVariables) { | ||
36 | super(); | ||
37 | this.toVariables = toVariables; | ||
38 | this.ordered = false; | ||
39 | } | ||
40 | public PProject(List<PVariable> toVariables) { | ||
41 | super(); | ||
42 | this.toVariables = toVariables; | ||
43 | this.ordered = true; | ||
44 | } | ||
45 | |||
46 | public Collection<PVariable> getToVariables() { | ||
47 | return toVariables; | ||
48 | } | ||
49 | public boolean isOrdered() { | ||
50 | return ordered; | ||
51 | } | ||
52 | |||
53 | @Override | ||
54 | public Set<? extends PConstraint> getDeltaConstraints() { | ||
55 | return Collections.emptySet(); | ||
56 | } | ||
57 | @Override | ||
58 | public int numParentSubPlans() { | ||
59 | return 1; | ||
60 | } | ||
61 | @Override | ||
62 | public void checkConsistency(SubPlan subPlan) { | ||
63 | super.checkConsistency(subPlan); | ||
64 | final SubPlan parentPlan = subPlan.getParentPlans().get(0); | ||
65 | |||
66 | Preconditions.checkArgument(parentPlan.getVisibleVariables().containsAll(toVariables), | ||
67 | () -> toVariables.stream() | ||
68 | .filter(input -> !parentPlan.getVisibleVariables().contains(input)).map(PVariable::getName) | ||
69 | .collect(Collectors.joining(",", "Variables missing from project: ", ""))); | ||
70 | } | ||
71 | |||
72 | @Override | ||
73 | public String getShortName() { | ||
74 | return String.format("PROJECT%s_{%s}", ordered? "!" : "", | ||
75 | toVariables.stream().map(PVariable::getName).collect(Collectors.joining(","))); | ||
76 | } | ||
77 | |||
78 | @Override | ||
79 | public int hashCode() { | ||
80 | final int prime = 31; | ||
81 | int result = 1; | ||
82 | result = prime * result + (ordered ? 1231 : 1237); | ||
83 | result = prime * result | ||
84 | + ((toVariables == null) ? 0 : toVariables.hashCode()); | ||
85 | return result; | ||
86 | } | ||
87 | @Override | ||
88 | public boolean equals(Object obj) { | ||
89 | if (this == obj) | ||
90 | return true; | ||
91 | if (obj == null) | ||
92 | return false; | ||
93 | if (!(obj instanceof PProject)) | ||
94 | return false; | ||
95 | PProject other = (PProject) obj; | ||
96 | if (ordered != other.ordered) | ||
97 | return false; | ||
98 | if (toVariables == null) { | ||
99 | if (other.toVariables != null) | ||
100 | return false; | ||
101 | } else if (!toVariables.equals(other.toVariables)) | ||
102 | return false; | ||
103 | return true; | ||
104 | } | ||
105 | |||
106 | |||
107 | |||
108 | |||
109 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java new file mode 100644 index 00000000..9e6ea10e --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java | |||
@@ -0,0 +1,90 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.planning.operations; | ||
10 | |||
11 | import java.util.Arrays; | ||
12 | import java.util.Collections; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.Set; | ||
15 | import java.util.stream.Collectors; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
18 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
19 | |||
20 | /** | ||
21 | * No constraints, and no parent SubPlan, just a (possibly empty) set of a priori known (input) variables. Satisfied by a single tuple. | ||
22 | * | ||
23 | * <p> Can also be used without a priori variables, | ||
24 | * e.g. as a "virtual parent" in extreme cases, | ||
25 | * such as <code>pattern foo(Bar) = {Bar = eval (3*4)} </code> | ||
26 | * | ||
27 | * @author Bergmann Gabor | ||
28 | * | ||
29 | */ | ||
30 | public class PStart extends POperation { | ||
31 | |||
32 | private Set<PVariable> aPrioriVariables; | ||
33 | |||
34 | |||
35 | public PStart(Set<PVariable> aPrioriVariables) { | ||
36 | super(); | ||
37 | this.aPrioriVariables = aPrioriVariables; | ||
38 | } | ||
39 | public PStart(PVariable... aPrioriVariables) { | ||
40 | this(new HashSet<PVariable>(Arrays.asList(aPrioriVariables))); | ||
41 | } | ||
42 | public Set<PVariable> getAPrioriVariables() { | ||
43 | return aPrioriVariables; | ||
44 | } | ||
45 | |||
46 | @Override | ||
47 | public String getShortName() { | ||
48 | return aPrioriVariables.stream().map(PVariable::getName).collect(Collectors.joining(",", "START_{", "}")); | ||
49 | } | ||
50 | @Override | ||
51 | public int numParentSubPlans() { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public Set<? extends PConstraint> getDeltaConstraints() { | ||
57 | return Collections.emptySet(); | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public int hashCode() { | ||
62 | final int prime = 31; | ||
63 | int result = 1; | ||
64 | result = prime | ||
65 | * result | ||
66 | + ((aPrioriVariables == null) ? 0 : aPrioriVariables.hashCode()); | ||
67 | return result; | ||
68 | } | ||
69 | |||
70 | @Override | ||
71 | public boolean equals(Object obj) { | ||
72 | if (this == obj) | ||
73 | return true; | ||
74 | if (obj == null) | ||
75 | return false; | ||
76 | if (!(obj instanceof PStart)) | ||
77 | return false; | ||
78 | PStart other = (PStart) obj; | ||
79 | if (aPrioriVariables == null) { | ||
80 | if (other.aPrioriVariables != null) | ||
81 | return false; | ||
82 | } else if (!aPrioriVariables.equals(other.aPrioriVariables)) | ||
83 | return false; | ||
84 | return true; | ||
85 | } | ||
86 | |||
87 | |||
88 | |||
89 | |||
90 | } | ||