aboutsummaryrefslogtreecommitdiffstats
path: root/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java
diff options
context:
space:
mode:
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java')
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java345
1 files changed, 345 insertions, 0 deletions
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java
new file mode 100644
index 00000000..500dd7d2
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java
@@ -0,0 +1,345 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, 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 *******************************************************************************/
9package org.eclipse.viatra.dse.api;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Objects;
15import java.util.function.Consumer;
16
17import org.eclipse.emf.common.notify.Notifier;
18import org.eclipse.emf.edit.command.ChangeCommand;
19import org.eclipse.emf.edit.domain.EditingDomain;
20import org.eclipse.viatra.dse.base.DseIdPoolHelper;
21import org.eclipse.viatra.dse.designspace.api.IBacktrackListener;
22import org.eclipse.viatra.dse.objectives.Fitness;
23import org.eclipse.viatra.dse.statecode.IStateCoder;
24import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
25import org.eclipse.viatra.dse.util.EMFHelper;
26import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
27import org.eclipse.viatra.query.runtime.api.IPatternMatch;
28import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
29import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher;
30import org.eclipse.viatra.query.runtime.emf.EMFScope;
31import org.eclipse.viatra.query.runtime.matchers.ViatraQueryRuntimeException;
32import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
33import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
34
35import com.google.common.util.concurrent.UncheckedExecutionException;
36
37/**
38 * A SolutionTrajectory represents a trajectory (i.e. sequence of transformation
39 * rule applications), which can transform the initial model to a desired state.
40 * An instance of this class holds the the actual rule sequence and the
41 * corresponding activation codes. Furthermore it can be used to perform the
42 * transformation on a given model (if possible).
43 * <p>
44 * It is also possible to undo the transformation if initialized with an editing
45 * domain.
46 * <p>
47 * The instance of this class can be reused for different models.
48 *
49 * @author Andras Szabolcs Nagy
50 *
51 */
52public class SolutionTrajectory {
53
54 private final List<Object> activationCodes;
55 private final List<BatchTransformationRule<?, ?>> transformationRules;
56 private final IStateCoderFactory stateCoderFactory;
57 private Fitness fitness;
58 private Solution solution;
59
60 private ViatraQueryEngine engine;
61 private Notifier model;
62 private EditingDomain editingDomain;
63 private IStateCoder stateCoder;
64 private IBacktrackListener listener;
65
66 private int currentIndex;
67
68 public SolutionTrajectory(final List<Object> activationCodes,
69 final List<BatchTransformationRule<?, ?>> transformationRules, final IStateCoderFactory stateCoderFactory,
70 final IBacktrackListener backtrackListener) {
71 Objects.requireNonNull(transformationRules, "Parameter transformationRules cannot be null!");
72 Objects.requireNonNull(stateCoderFactory, "Parameter stateCoderFactory cannot be null!");
73 Objects.requireNonNull(activationCodes, "Parameter activations cannot be null!");
74 Preconditions.checkState(transformationRules.size() == activationCodes.size(),
75 "The two List parameters must be the same in size.");
76
77 this.activationCodes = activationCodes;
78 this.transformationRules = transformationRules;
79 this.stateCoderFactory = stateCoderFactory;
80 this.listener = backtrackListener;
81 currentIndex = 0;
82 }
83
84 /**
85 * Initialize this SolutionTrajectory for transforming the model along the
86 * trajectory.
87 *
88 * @param model The model.
89 * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
90 */
91 public void setModel(Notifier model) {
92 editingDomain = null;
93 EMFScope scope = new EMFScope(model);
94 this.engine = ViatraQueryEngine.on(scope);
95 this.model = model;
96 stateCoder = stateCoderFactory.createStateCoder();
97 stateCoder.init(model);
98 currentIndex = 0;
99 DseIdPoolHelper.INSTANCE.disposeByThread();
100 DseIdPoolHelper.INSTANCE.registerRules(rule -> {
101 int id = 0;
102 for (BatchTransformationRule<?, ?> r : transformationRules.subList(0, currentIndex)) {
103 if (r.equals(rule)) {
104 id++;
105 }
106 }
107 return id;
108 }, new HashSet<BatchTransformationRule<?, ?>>(transformationRules));
109 }
110
111 /**
112 * Initialize this SolutionTrajectory for transforming the given model along the
113 * trajectory.
114 * <p>
115 * The transformation will be reversible by creating an {@link EditingDomain} on
116 * the model.
117 *
118 * @param modelRoot The root of the model.
119 * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
120 */
121 public void setModelWithEditingDomain(Notifier modelRoot) {
122 setModel(modelRoot);
123 editingDomain = EMFHelper.createEditingDomain(model);
124 }
125
126 /**
127 * Transforms the given model along the trajectory.
128 *
129 * @param modelRoot The root of the model.
130 * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
131 */
132 public void doTransformation(Notifier modelRoot) {
133 setModel(modelRoot);
134 doTransformation();
135 }
136
137 /**
138 * Transforms the given model along the trajectory.
139 * <p>
140 * The transformation will be reversible by creating an {@link EditingDomain} on
141 * the model.
142 *
143 * @param modelRoot The root of the model.
144 * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
145 */
146 public void doTransformationUndoable(Notifier modelRoot) {
147 setModelWithEditingDomain(modelRoot);
148 doTransformation();
149 }
150
151 /**
152 * Transforms the given model along the trajectory. To initialize the model call
153 * the {@link SolutionTrajectory#setModel(Notifier)} method.
154 *
155 * @throws Exception If the activation to fire is not found.
156 * Possible problems: wrong model, bad state
157 * serializer.
158 * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
159 */
160 public void doTransformation() {
161 while (doNextTransformation())
162 ;
163 }
164
165 /**
166 * Transforms the given model by one step to the solution (makes one step in the
167 * trajectory). To initialize the model call the
168 * {@link SolutionTrajectory#setModel(Notifier)} method.
169 *
170 * @throws ViatraQueryRuntimeException
171 */
172 public boolean doNextTransformation() {
173 if (currentIndex >= activationCodes.size()) {
174 return false;
175 } else {
176 doNextTransformation(currentIndex);
177 currentIndex++;
178 return true;
179 }
180 }
181
182 @SuppressWarnings("unchecked")
183 private void doNextTransformation(int index) {
184 Objects.requireNonNull(model, "The model cannot be null! Use the setModel method.");
185
186 // cast for the ".process(match)" method.
187 BatchTransformationRule<?, ?> tr = transformationRules.get(index);
188 Object activationCode = activationCodes.get(index);
189
190 ViatraQueryMatcher<?> matcher = tr.getPrecondition().getMatcher(engine);
191
192 boolean isActivationFound = false;
193 for (final IPatternMatch match : matcher.getAllMatches()) {
194 Object matchHash = stateCoder.createActivationCode(match);
195 if (matchHash.equals(activationCode)) {
196 @SuppressWarnings("rawtypes")
197 final Consumer action = tr.getAction();
198
199 if (editingDomain == null) {
200 action.accept(match);
201 } else {
202 ChangeCommand cc = new ChangeCommand(model) {
203 @Override
204 protected void doExecute() {
205 action.accept(match);
206 }
207 };
208 long start = System.nanoTime();
209 try {
210 ((AdvancedViatraQueryEngine) engine).delayUpdatePropagation(() -> {
211 editingDomain.getCommandStack().execute(cc);
212 return null;
213 });
214 } catch (InvocationTargetException e) {
215 throw new RuntimeException(e);
216 }
217 listener.forwardWorked(System.nanoTime() - start);
218 }
219
220 isActivationFound = true;
221 break;
222 }
223 }
224 if (!isActivationFound) {
225 throw new UncheckedExecutionException(
226 "Activation was not found for transformation! Possible cause: wrong model, bad state coder. index: "
227 + index + " Activation code: " + activationCode,
228 null);
229 }
230 }
231
232 /**
233 * Call this method to undo the last transformation.
234 *
235 * @return True, if it was successful.
236 */
237 public boolean undoLastTransformation() {
238 Objects.requireNonNull(editingDomain, "To be able to undo the transformation initialize with editing domain.");
239 long start = System.nanoTime();
240 boolean result;
241
242 if (currentIndex > 0) {
243 try {
244 ((AdvancedViatraQueryEngine) engine).delayUpdatePropagation(() -> {
245 editingDomain.getCommandStack().undo();
246 return null;
247 });
248 } catch (InvocationTargetException e) {
249 throw new RuntimeException(e);
250 }
251 currentIndex--;
252 result = true;
253 }
254 result = false;
255 listener.backtrackWorked(System.nanoTime() - start);
256 return result;
257 }
258
259 /**
260 * Call this method to undo the transformation.
261 */
262 public void undoTransformation() {
263 while (undoLastTransformation())
264 ;
265 }
266
267 public List<Object> getActivationCodes() {
268 return activationCodes;
269 }
270
271 public List<BatchTransformationRule<?, ?>> getTransformationRules() {
272 return transformationRules;
273 }
274
275 public IStateCoderFactory getStateCoderFactory() {
276 return stateCoderFactory;
277 }
278
279 public ViatraQueryEngine getEngine() {
280 return engine;
281 }
282
283 public Notifier getModel() {
284 return model;
285 }
286
287 public IStateCoder getStateCoder() {
288 return stateCoder;
289 }
290
291 public int getCurrentIndex() {
292 return currentIndex;
293 }
294
295 public int getTrajectoryLength() {
296 return activationCodes.size();
297 }
298
299 public Fitness getFitness() {
300 return fitness;
301 }
302
303 public void setFitness(Fitness fitness) {
304 this.fitness = fitness;
305 }
306
307 public String toPrettyString() {
308 StringBuilder sb = new StringBuilder();
309 sb.append("Fitness: ");
310 sb.append(fitness.toString());
311 sb.append(" | Trajectory (");
312 sb.append(activationCodes.size());
313 sb.append("): ");
314 for (Object object : activationCodes) {
315 sb.append(object.toString());
316 sb.append(" | ");
317 }
318 return sb.toString();
319 }
320
321 @Override
322 public int hashCode() {
323 return activationCodes.hashCode();
324 }
325
326 @Override
327 public boolean equals(Object obj) {
328 if (this == obj) {
329 return true;
330 }
331 if (obj instanceof SolutionTrajectory) {
332 SolutionTrajectory that = (SolutionTrajectory) obj;
333 return activationCodes.equals(that.activationCodes);
334 }
335 return false;
336 }
337
338 public Solution getSolution() {
339 return solution;
340 }
341
342 public void setSolution(Solution solution) {
343 this.solution = solution;
344 }
345}