aboutsummaryrefslogtreecommitdiffstats
path: root/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api
diff options
context:
space:
mode:
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api')
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSEException.java47
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSETransformationRule.java51
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DesignSpaceExplorer.java622
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Objectives.java153
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Solution.java60
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java345
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java123
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java228
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java220
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java188
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java208
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java142
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java163
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java44
-rw-r--r--Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java13
15 files changed, 2607 insertions, 0 deletions
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSEException.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSEException.java
new file mode 100644
index 00000000..f0da19ed
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSEException.java
@@ -0,0 +1,47 @@
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
11/**
12 * Represents a general runtime exception that happened during the execution of the design space exploration process.
13 * Problems that cause this exception are not recoverable within the scope of the design space exploration process.
14 */
15public class DSEException extends RuntimeException {
16
17 private static final long serialVersionUID = -8312212010574763824L;
18
19 /**
20 * @see RuntimeException#RuntimeException()
21 */
22 public DSEException() {
23 super();
24 }
25
26 /**
27 * @see RuntimeException#RuntimeException(String)
28 */
29 public DSEException(String message) {
30 super(message);
31 }
32
33 /**
34 * @see RuntimeException#RuntimeException(String, Throwable)
35 */
36 public DSEException(String message, Throwable cause) {
37 super(message, cause);
38 }
39
40 /**
41 * @see RuntimeException#RuntimeException(Throwable)
42 */
43 public DSEException(Throwable cause) {
44 super(cause);
45 }
46
47}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSETransformationRule.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSETransformationRule.java
new file mode 100644
index 00000000..8c3511ae
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DSETransformationRule.java
@@ -0,0 +1,51 @@
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.util.Objects;
12import java.util.function.Consumer;
13
14import org.eclipse.viatra.query.runtime.api.IPatternMatch;
15import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
16import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher;
17import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
18
19/**
20 * An instance of this class is a specification of a graph transformation rule on a given metamodel. Such a rule
21 * consists of a left hand side (LHS), which is specified by an {@link IQuerySpecification} and a right hand side (RHS),
22 * which is specified by an {@link Consumer}.
23 *
24 * @author Andras Szabolcs Nagy
25 *
26 * @param <Match>
27 * A VIATRA Query pattern match - left hand side of the rule
28 * @param <Matcher>
29 * A VIATRA Query pattern matcher - left hand side of the rule
30 * @deprecated
31 */
32@Deprecated
33public class DSETransformationRule<Match extends IPatternMatch, Matcher extends ViatraQueryMatcher<Match>> extends
34 BatchTransformationRule<Match, Matcher> {
35
36 public DSETransformationRule(String name, IQuerySpecification<Matcher> querySpec,
37 Consumer<Match> action) {
38 super(name, querySpec, BatchTransformationRule.STATELESS_RULE_LIFECYCLE, action);
39
40 Objects.requireNonNull(name);
41 Objects.requireNonNull(querySpec);
42 Objects.requireNonNull(action);
43
44 }
45
46 public DSETransformationRule(IQuerySpecification<Matcher> querySpec,
47 Consumer<Match> action) {
48 this(querySpec.getFullyQualifiedName(), querySpec, action);
49 }
50
51}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DesignSpaceExplorer.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DesignSpaceExplorer.java
new file mode 100644
index 00000000..9cd6e68a
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/DesignSpaceExplorer.java
@@ -0,0 +1,622 @@
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.util.Collection;
12import java.util.HashSet;
13import java.util.Set;
14import java.util.Timer;
15import java.util.TimerTask;
16import java.util.concurrent.atomic.AtomicBoolean;
17
18import org.apache.log4j.BasicConfigurator;
19import org.apache.log4j.Level;
20import org.apache.log4j.Logger;
21import org.eclipse.emf.common.notify.Notifier;
22import org.eclipse.emf.ecore.EObject;
23import org.eclipse.emf.ecore.EPackage;
24import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
25import org.eclipse.viatra.dse.base.DesignSpaceManager;
26import org.eclipse.viatra.dse.base.GlobalContext;
27import org.eclipse.viatra.dse.designspace.api.DesignSpace;
28import org.eclipse.viatra.dse.designspace.api.IDesignSpace;
29import org.eclipse.viatra.dse.objectives.IGlobalConstraint;
30import org.eclipse.viatra.dse.objectives.IObjective;
31import org.eclipse.viatra.dse.solutionstore.ISolutionNameProvider;
32import org.eclipse.viatra.dse.solutionstore.IdBasedSolutionNameProvider;
33import org.eclipse.viatra.dse.solutionstore.SolutionStore;
34import org.eclipse.viatra.dse.statecode.IStateCoder;
35import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
36import org.eclipse.viatra.dse.statecoding.simple.SimpleStateCoderFactory;
37import org.eclipse.viatra.dse.visualizer.IDesignSpaceVisualizer;
38import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
39import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
40import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
41
42/**
43 * <p>
44 * The {@link DesignSpaceExplorer} is the main API of the <b>Design Space Exploration</b> engine.
45 * </p>
46 *
47 * <p>
48 * To parameterize the algorithm one must use the following methods after instantiating:
49 * <ul>
50 * <li>{@link #setInitialModel(EObject)} or it's overloads to set the starting model.</li>
51 * <li>{@link #addTransformationRule(BatchTransformationRule)} to define the transformations.</li> <li
52 * {@link #addObjective(IObjective)} to define the objective functions. Use the {@link Objectives} helper class for
53 * instantiating built-in, configurable objectives.</li>
54 * <li>{@link #startExploration(IStrategy)} or it's overloads to start an exploration with the given exploration
55 * strategy. Use the {@link Strategies} helper class for instantiating built-in, configurable exploration strategies.
56 * </li>
57 * </ul>
58 * </p>
59 *
60 * <p>
61 * <b>Designs Space Exploration</b> is the process of finding a sequence (or sequences) of predefined transformation
62 * rules ("transitions") that, if applied in order on the starting model, results in a new model state that fulfills the
63 * hard (or goal) constraints and is near optimal with respect to the objectives.
64 * </p>
65 *
66 * <p>
67 * An extension to this paradigm is the introduction of global constraints, which guarantees, that no sequence will be
68 * returned, which if executed, results in an intermediate model state that violates the specified global constraints,
69 * including the final state. You can add constraints by invoking {@link #addGlobalConstraint(IGlobalConstraint)}.
70 * </p>
71 *
72 * @author Andras Szabolcs Nagy & Miklos Foldenyi
73 *
74 */
75public class DesignSpaceExplorer {
76
77 private Notifier model;
78
79 private GlobalContext globalContext = new GlobalContext();
80
81 private final Logger logger = Logger.getLogger(this.getClass());
82
83 private Set<EPackage> metaModelPackages = new HashSet<EPackage>();
84
85 private static final String MODEL_NOT_YET_GIVEN = "The starting model is not given yet. Please call the setInitialModel method first.";
86
87 private boolean deepCopyModel;
88
89 /**
90 * <p>
91 * Creates a {@link DesignSpaceExplorer} object that is able to execute a design space exploration process.
92 * </p>
93 *
94 * <p>
95 * By default the state coder used is the generic (not meta-model specific) {@link GraphHash}. You can provide your
96 * custom state coder by implementing the {@link IStateCoderFactory} and {@link IStateCoder} interfaces, and passing
97 * the former to the {@link #setStateCoderFactory(IStateCoderFactory)} method.
98 *
99 */
100 public DesignSpaceExplorer() {
101 setDesignspace(new DesignSpace());
102 }
103
104 /**
105 * Adds a metamodel in the form of {@link EPackage}, which is needed for certain guidance.
106 *
107 * @param metaModelPackage
108 */
109 public void addMetaModelPackage(EPackage metaModelPackage) {
110 metaModelPackages.add(metaModelPackage);
111 }
112
113 /**
114 * Defines the initial model of the exploration, and whether it is supposed to be used to execute the DSE process or
115 * it should be cloned. Please note, that in multithreaded mode any subsequent threads will be working on cloned
116 * models.
117 *
118 * @param model
119 * The root object of the EMF model.
120 * @param deepCopyModel
121 * If it is set to true, the exploration will run on a cloned model.
122 */
123 public void setInitialModel(Notifier model, boolean deepCopyModel) {
124 this.model = model;
125 this.deepCopyModel = deepCopyModel;
126 }
127
128 /**
129 * Defines the initial model of the exploration. The model will be cloned, which is desired in most cases as the
130 * given model won't be changed.
131 *
132 * @param model
133 * The root object of the EMF model.
134 */
135 public void setInitialModel(Notifier model) {
136 setInitialModel(model, true);
137 }
138
139 /**
140 * Defines the initial model of the exploration. The given model won't be cloned, thus the exploration will modify
141 * it.
142 *
143 * @param model
144 * The root object of the EMF model. It won't be cloned.
145 */
146 public void setInitialModelUncloned(Notifier model) {
147 setInitialModel(model, false);
148 }
149
150 /**
151 * Adds a {@link BatchTransformationRule}.
152 *
153 * @param rule
154 * The transformationRule.
155 */
156 public void addTransformationRule(BatchTransformationRule<?, ?> rule) {
157 Preconditions.checkArgument(rule != null);
158 for (BatchTransformationRule<?, ?> rule2 : globalContext.getTransformations()) {
159 if (rule.getPrecondition().equals(rule2.getPrecondition())) {
160 throw new DSEException(
161 "Two transformation rule ("
162 + rule.getName()
163 + "; "
164 + rule2.getName()
165 + ") uses the same LHS VIATRA Query pattern ("
166 + rule.getPrecondition().getFullyQualifiedName()
167 + "), which may lead to hash collision."
168 + " Please wrap the pattern with an other pattern with the 'find' keyword (or duplicate the code), and use that for one of the rules LHS.");
169 }
170 }
171
172 globalContext.getTransformations().add(rule);
173 }
174
175 /**
176 * Adds a global constraint to the exploration process. Please see the {@link IGlobalConstraint} interface and its
177 * implementations for details.
178 *
179 * @param constraint
180 * The global constraint.
181 * @see IGlobalConstraint
182 */
183 public void addGlobalConstraint(IGlobalConstraint constraint) {
184 globalContext.getGlobalConstraints().add(constraint);
185 }
186
187 /**
188 * Adds an objective the the exploration process. Please see the {@link IObjective} interface and its
189 * implementations for details.
190 *
191 * @param objective
192 * The objective.
193 * @see IObjective
194 */
195 public void addObjective(IObjective objective) {
196 for (IObjective o : globalContext.getObjectives()) {
197 if (o.getName().equals(objective.getName())) {
198 throw new DSEException("Two objectives with the same name cannot be registered:" + o.getName());
199 }
200 }
201 globalContext.getObjectives().add(objective);
202 }
203
204 /**
205 * Sets a {@link IStateCoderFactory} for which will be used for creating {@link IStateCoder}s. The default
206 * implementation is the {@link SimpleStateCoderFactory}, which works well in most of the cases.
207 *
208 * @param stateCoderFactory
209 * The factory.
210 */
211 public final void setStateCoderFactory(IStateCoderFactory stateCoderFactory) {
212 globalContext.setStateCoderFactory(stateCoderFactory);
213 }
214
215 /**
216 * Defines the maximum processing threads that the design space exploration can use. Note, that this is only
217 * limiting the threads doing the actual calculation. By default this value will be set to the number of logical
218 * processors (including HyperThreading) in the computer, reported by {@link Runtime#availableProcessors()}.
219 *
220 * @param maxNumberOfThreads
221 * The number of maximum processing threads available to the design space exploration process.
222 */
223 public void setMaxNumberOfThreads(int maxNumberOfThreads) {
224 globalContext.getThreadPool().setMaximumPoolSize(maxNumberOfThreads);
225 }
226
227 /**
228 * Sets the {@link IDesignSpace} implementation that is to be used during the design space exploration process. By
229 * default, the {@link DesignSpace} implementation is used.
230 *
231 * @param designspace
232 * The {@link IDesignSpace} implementation.
233 */
234 public final void setDesignspace(IDesignSpace designspace) {
235 globalContext.setDesignSpace(designspace);
236 }
237
238 /**
239 * Sets the solution store for strategies. Please see the {@link SolutionStore} for how to configure it.
240 *
241 * @param solutionStore
242 * The parameterized {@link SolutionStore} implementation.
243 */
244 public void setSolutionStore(SolutionStore solutionStore) {
245 globalContext.setSolutionStore(solutionStore);
246 }
247
248 /**
249 * Starts the design space exploration. It returns only when the strategy decides to stop the execution.
250 *
251 * @param strategy
252 * The strategy of the exploration.
253 */
254 public void startExploration(IStrategy strategy) {
255 startExploration(strategy, true, -1);
256 }
257
258 /**
259 * Starts the design space exploration asynchronously. Completion of the process can be verified by calling
260 * {@link DesignSpaceExplorer#isDone()}.
261 *
262 * @param strategy
263 * The strategy of the exploration.
264 */
265 public void startExplorationAsync(IStrategy strategy) {
266 startExploration(strategy, false, -1);
267 }
268
269 /**
270 * Starts the design space exploration with a timeout. It returns only when the strategy decides to stop the
271 * execution or the given timeout is elapsed.
272 *
273 * @param strategy
274 * The strategy of the exploration.
275 * @param timeout
276 * The number of milliseconds before the exploration is forced to stop.
277 * @return Returns true if the exploration stopped by the timeout.
278 */
279 public boolean startExplorationWithTimeout(IStrategy strategy, long timeout) {
280 return startExploration(strategy, true, timeout);
281 }
282
283 /**
284 * Starts the design space exploration asynchronously with a timeout. Completion of the process can be verified by
285 * calling {@link DesignSpaceExplorer#isDone()}.
286 *
287 * @param strategy
288 * The strategy of the exploration.
289 * @param timeout
290 * The number of milliseconds before the exploration is forced to stop.
291 * @return Returns true if the exploration stopped by the timeout.
292 */
293 public boolean startExplorationAsyncWithTimeout(IStrategy strategy, long timeout) {
294 return startExploration(strategy, false, timeout);
295 }
296
297 /**
298 * Starts the design space exploration. If {@code waitForTermination} is true, then it returns only when the
299 * strategy decides to stop the execution or there was a timeout, otherwise when the exploration process is started
300 * it returns immediately. In this case, process completion can be verified by calling
301 * {@link DesignSpaceExplorer#isDone()}.
302 *
303 * @param strategy
304 * The strategy of the exploration.
305 * @param waitForTermination
306 * True if the method must wait for the engine to stop, i.e. whether to start synchronously.
307 * @param timeout
308 * The number of milliseconds before the exploration is forced to stop.
309 * @return Returns true if the exploration stopped by the timeout.
310 */
311 public boolean startExploration(IStrategy strategy, boolean waitForTermination, final long timeout) {
312 initExploration(strategy);
313
314 Timer timer = new Timer();
315 final AtomicBoolean wasTimeout = new AtomicBoolean(false);
316
317 if (timeout > 0) {
318 TimerTask timerTask = new TimerTask() {
319 @Override
320 public void run() {
321 logger.info("Timeout, stopping threads...");
322 globalContext.stopAllThreads();
323 wasTimeout.set(true);
324 }
325 };
326 timer.schedule(timerTask, timeout);
327 }
328
329 if (waitForTermination) {
330 waitForTerminaition();
331 timer.cancel();
332 } else {
333 logger.info("Design space exploration started asynchronously.");
334 }
335
336 return wasTimeout.get();
337
338 }
339
340 private void initExploration(IStrategy strategy) {
341 Preconditions.checkArgument(model != null, MODEL_NOT_YET_GIVEN);
342 Preconditions.checkArgument(strategy != null, "A strategy must be given. Use the Strategies helper class.");
343 Preconditions.checkState(!globalContext.getTransformations().isEmpty(),
344 "At least one transformation rule must be added to start the exploration.");
345
346 if (globalContext.getStateCoderFactory() == null) {
347 if (getMetaModelPackages() == null || getMetaModelPackages().isEmpty()) {
348 throw new DSEException("Cannot initialize state coder."
349 + " Please specifiy the EPackages your model uses with addMetaModelPackage(EPackage)");
350 }
351 globalContext.setStateCoderFactory(new SimpleStateCoderFactory(getMetaModelPackages()));
352 }
353
354 logger.info("DesignSpaceExplorer started exploration.");
355
356 if (deepCopyModel) {
357 globalContext.startFirstThread(strategy, model);
358 } else {
359 globalContext.startFirstThreadWithoutModelClone(strategy, model);
360 }
361 }
362
363 /**
364 * Returns all of the found {@link Solution}s, trajectories. Call it after
365 * {@link DesignSpaceExplorer#startExploration()}. Calling this while the process is running returns the solutions
366 * that have been found <b>so far</b>. The returned {@link Solution} objects may change internal state after they
367 * have been returned, if a shorter trajectory has been found to the referred state.
368 *
369 * @return The found solutions.
370 */
371 public Collection<Solution> getSolutions() {
372 return globalContext.getSolutionStore().getSolutions();
373 }
374
375 /**
376 * Returns an arbitrary solution trajectory or null if the exploration failed to find any.
377 *
378 * @return An arbitrary solution trajectory.
379 */
380 public SolutionTrajectory getArbitrarySolution() {
381 Collection<Solution> solutions = getSolutions();
382 if (solutions.isEmpty()) {
383 return null;
384 }
385 return solutions.iterator().next().getArbitraryTrajectory();
386 }
387
388 /**
389 * Returns the number of distinct states the exploration process has visited so far.
390 *
391 * @return the number of distinct states.
392 */
393 public long getNumberOfStates() {
394 return globalContext.getDesignSpace().getNumberOfStates();
395 }
396
397 /**
398 * Returns the number of distinct transitions the exploration process has discovered (but not necessarily traversed)
399 * so far.
400 *
401 * @return the number of distinct transitions.
402 */
403 public long getNumberOfTransitions() {
404 return globalContext.getDesignSpace().getNumberOfTransitions();
405 }
406
407 /**
408 * Returns the {@link EPackage}s, which were registered with the
409 * {@link DesignSpaceExplorer#addMetaModelPackage(EPackage)} method.
410 *
411 * @return The set of meta model packages.
412 */
413 public Set<EPackage> getMetaModelPackages() {
414 return metaModelPackages;
415 }
416
417 /**
418 * Returns true if the {@link IExplorerThread strategy} decided to stop, and all the threads finished their work.
419 *
420 * @return true if the process has finished, false otherwise.
421 */
422 public boolean isDone() {
423 return globalContext.isDone();
424 }
425
426 /**
427 * Returns the {@link GlobalContext} which holds the configurations such as rule, objectives, etc.
428 *
429 * @return The global context.
430 */
431 public GlobalContext getGlobalContext() {
432 return globalContext;
433 }
434
435 /**
436 * Registers a design space visualizer. Please see the corresponding interface {@link IDesignSpaceVisualizer}.
437 *
438 * @see IDesignSpaceVisualizer
439 *
440 * @param visualizer
441 */
442 public void addDesignSpaceVisulaizer(IDesignSpaceVisualizer visualizer) {
443 globalContext.registerDesignSpaceVisualizer(visualizer);
444 }
445
446 /**
447 * Creates a string containing the state codes of all the found solutions and the found trajectories to these
448 * solutions with fitness values.
449 *
450 * @return A pretty string with the solutions.
451 */
452 public String toStringSolutions() {
453 StringBuilder sb = new StringBuilder();
454 Collection<Solution> solutions = getSolutions();
455 sb.append("Number of solutions: ");
456 sb.append(solutions.size());
457 sb.append("\n");
458 for (Solution solution : solutions) {
459 sb.append("Solution: ");
460 sb.append(solution.getStateCode());
461 sb.append("\n");
462 for (SolutionTrajectory trajectory : solution.getTrajectories()) {
463 sb.append(" ");
464 sb.append(trajectory.toPrettyString());
465 sb.append("\n");
466 }
467 }
468 return sb.toString();
469 }
470
471 /**
472 * A conflict resolver can filter rule activations the DSE engine will see. The primary use of this is symmetry
473 * reduction. This function is subject to change for better API.
474 *
475 * @param conflictResolver
476 */
477 public void setConflictResolver(ConflictResolver conflictResolver) {
478 globalContext.setConflictResolver(conflictResolver);
479 }
480
481 /**
482 * Enumeration for different use cases of logging, including:
483 * <ul>
484 * <li>OFF - no error messages.</li>
485 * <li>WARN - only error and warn messages.</li>
486 * <li>BASIC - logs basic information on how the exploration is going.</li>
487 * <li>VERBOSE_STRATEGY - logs everything the exploration strategy is prepared for.</li>
488 * <li>VERBOSE_FULL - logs every transformation.</li>
489 * </ul>
490 *
491 * @author Andras Szabolcs Nagy
492 *
493 */
494 public enum DseLoggingLevel {
495 OFF, WARN, BASIC, VERBOSE_STRATEGY, VERBOSE_FULL
496 }
497
498 /**
499 * Changes the level of logging. See {@link DseLoggingLevel} for details.
500 *
501 * @param dseLoggingLevel
502 */
503 public static void turnOnLogging(DseLoggingLevel dseLoggingLevel) {
504 switch (dseLoggingLevel) {
505 case OFF:
506 Logger.getLogger(DesignSpaceExplorer.class).setLevel(Level.OFF);
507 Logger.getLogger(IStrategy.class).setLevel(Level.OFF);
508 Logger.getLogger(DesignSpaceManager.class).setLevel(Level.OFF);
509 break;
510 case WARN:
511 Logger.getLogger(DesignSpaceExplorer.class).setLevel(Level.WARN);
512 Logger.getLogger(IStrategy.class).setLevel(Level.WARN);
513 Logger.getLogger(DesignSpaceManager.class).setLevel(Level.WARN);
514 break;
515 case BASIC:
516 Logger.getLogger(DesignSpaceExplorer.class).setLevel(Level.INFO);
517 Logger.getLogger(IStrategy.class).setLevel(Level.INFO);
518 Logger.getLogger(DesignSpaceManager.class).setLevel(Level.WARN);
519 break;
520 case VERBOSE_STRATEGY:
521 Logger.getLogger(DesignSpaceExplorer.class).setLevel(Level.DEBUG);
522 Logger.getLogger(IStrategy.class).setLevel(Level.DEBUG);
523 Logger.getLogger(DesignSpaceManager.class).setLevel(Level.WARN);
524 break;
525 case VERBOSE_FULL:
526 Logger.getLogger(DesignSpaceExplorer.class).setLevel(Level.DEBUG);
527 Logger.getLogger(IStrategy.class).setLevel(Level.DEBUG);
528 Logger.getLogger(DesignSpaceManager.class).setLevel(Level.DEBUG);
529 break;
530 default:
531 throw new DSEException("Not supported logging level.");
532 }
533 }
534
535 /**
536 * Changes the level of logging. See {@link DseLoggingLevel} for details.
537 *
538 * Also configures a basic console appender for log4j.
539 *
540 * @param dseLoggingLevel
541 */
542 public static void turnOnLoggingWithBasicConfig(DseLoggingLevel dseLoggingLevel) {
543 BasicConfigurator.configure();
544 Logger.getRootLogger().setLevel(Level.WARN);
545 turnOnLogging(dseLoggingLevel);
546 }
547
548 /**
549 * Stops the exploration and waits for termination. It has no effect if the exploration is already terminated or not
550 * even started.
551 */
552 public void stopExploration() {
553 if (globalContext.isDone()) {
554 logger.info("Cannot stop exploration - design space exploration has already finished.");
555 } else if (globalContext.isNotStarted()) {
556 logger.info("Cannot stop exploration - design space exploration has not been started.");
557 } else {
558 globalContext.stopAllThreads();
559 waitForTerminaition();
560 }
561 }
562
563 /**
564 * Stops the exploration asynchronously. It has no effect if the exploration is already terminated or not even
565 * started.
566 */
567 public void stopExplorationAsync() {
568 if (globalContext.isDone()) {
569 logger.info("Cannot stop exploration - design space exploration has already finished.");
570 } else if (globalContext.isNotStarted()) {
571 logger.info("Cannot stop exploration - design space exploration has not been started.");
572 } else {
573 globalContext.stopAllThreads();
574 }
575 }
576
577 /**
578 * Waits for termination.
579 */
580 public void waitForTerminaition() {
581 globalContext.waitForTermination();
582 }
583
584 /**
585 * Serializes all the found solutions by transforming the given initial model.
586 * </p>Files will be named <code>solution[id].xmi</code>.
587 * @param model The initial model.
588 */
589 public void saveModels(Notifier model) {
590 this.saveModels(model, "solution", "xmi");
591 }
592
593 /**
594 * Serializes all the found solutions by transforming the given initial model.
595 * </p>Files will be named <code>solution[id].[extension]</code>.
596 * @param model The initial model.
597 * @param extension The extension of the omitted file.
598 */
599 public void saveModels(Notifier model, String extension) {
600 this.saveModels(model, "solution", extension);
601 }
602
603 /**
604 * Serializes all the found solutions by transforming the given initial model.
605 * </p>Files will be named <code>[fileNamePrefix][id].[extension]</code>.
606 * @param model The initial model.
607 * @param fileNamePrefix The prefix (optionally including a file path) of the omitted file.
608 * @param extension The extension of the omitted file.
609 */
610 public void saveModels(Notifier model, String fileNamePrefix, String extension) {
611 globalContext.getSolutionStore().saveModels(model, new IdBasedSolutionNameProvider(fileNamePrefix, extension));
612 }
613
614 /**
615 * Serializes all the found solutions by transforming the given initial model.
616 * </p>Files will be named using the {@link ISolutionNameProvider}.
617 * @param model The initial model.
618 */
619 public void saveModels(Notifier model, ISolutionNameProvider solutionNameProvider) {
620 globalContext.getSolutionStore().saveModels(model, solutionNameProvider);
621 }
622}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Objectives.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Objectives.java
new file mode 100644
index 00000000..3b375fac
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Objectives.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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 org.eclipse.viatra.dse.objectives.impl.CompositeObjective;
12import org.eclipse.viatra.dse.objectives.impl.ConstraintsObjective;
13import org.eclipse.viatra.dse.objectives.impl.AlwaysSatisfiedDummyHardObjective;
14import org.eclipse.viatra.dse.objectives.impl.DepthHardObjective;
15import org.eclipse.viatra.dse.objectives.impl.NeverSatisfiedDummyHardObjective;
16import org.eclipse.viatra.dse.objectives.impl.NoRuleActivationsHardObjective;
17import org.eclipse.viatra.dse.objectives.impl.TrajectoryCostSoftObjective;
18
19/**
20 *
21 * Helper class for creating built-in objectives.
22 *
23 * @author Andras Szabolcs Nagy
24 *
25 */
26public class Objectives {
27
28 private Objectives() {
29 }
30
31 /**
32 * This objective uses VIATRA Queries to calculate fitness and/or goal constraints. Use methods on the returned
33 * objective to configure it.
34 *
35 * @param name
36 * @return The objective.
37 * @see ConstraintsObjective
38 */
39 public static ConstraintsObjective createConstraintsObjective(String name) {
40 return new ConstraintsObjective(name);
41 }
42
43 /**
44 * This objective calculates fitness on the trajectory by adding either fix costs to the rules, or by calculating
45 * custom fitness on activation of rules.
46 *
47 * @param name
48 * @return The objective.
49 * @see TrajectoryCostSoftObjective
50 */
51 public static TrajectoryCostSoftObjective createTrajcetoryCostObjective(String name) {
52 return new TrajectoryCostSoftObjective(name);
53 }
54
55 /**
56 * This objective adds a goal constraint that a solution state should not have any activations.
57 *
58 * @return The objective.
59 * @see NoRuleActivationsHardObjective
60 */
61 public static NoRuleActivationsHardObjective createNoRuleActivationsHardConstraint() {
62 return new NoRuleActivationsHardObjective();
63 }
64
65 /**
66 * This objective adds a goal constraint that a solution state should not have any activations.
67 *
68 * @param name
69 * @return The objective.
70 * @see NoRuleActivationsHardObjective
71 */
72 public static NoRuleActivationsHardObjective createNoRuleActivationsHardConstraint(String name) {
73 return new NoRuleActivationsHardObjective(name);
74 }
75
76 /**
77 * This objective can combine the calculated fitness value of other objectives. Weights are supported.
78 *
79 * @param name
80 * @return The objective.
81 * @see NoRuleActivationsHardObjective
82 */
83 public static CompositeObjective createCompositeObjective(String name) {
84 return new CompositeObjective(name);
85 }
86
87 /**
88 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid
89 * solution.
90 *
91 * @return The objective.
92 * @see AlwaysSatisfiedDummyHardObjective
93 */
94 public static AlwaysSatisfiedDummyHardObjective createAlwaysSatisfiedDummyHardObjective() {
95 return new AlwaysSatisfiedDummyHardObjective();
96 }
97
98 /**
99 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid
100 * solution.
101 *
102 * @param name
103 * @return The objective.
104 * @see AlwaysSatisfiedDummyHardObjective
105 */
106 public static AlwaysSatisfiedDummyHardObjective createDummyHardObjective(String name) {
107 return new AlwaysSatisfiedDummyHardObjective(name);
108 }
109
110 /**
111 * This hard objective is never fulfilled. Use it if all states should be regarded as an invalid solution.
112 *
113 * @return The objective.
114 * @see AlwaysSatisfiedDummyHardObjective
115 */
116 public static NeverSatisfiedDummyHardObjective createNeverSatisfiedDummyHardObjective() {
117 return new NeverSatisfiedDummyHardObjective();
118 }
119
120 /**
121 * This hard objective is never fulfilled. Use it if all states should be regarded as an invalid solution.
122 *
123 * @return The objective.
124 * @see AlwaysSatisfiedDummyHardObjective
125 */
126 public static NeverSatisfiedDummyHardObjective createNeverSatisfiedDummyHardObjective(String name) {
127 return new NeverSatisfiedDummyHardObjective(name);
128 }
129
130 /**
131 * This hard objective is fulfilled if the length of the trajectory is in the specified interval (inclusive). Use
132 * {@link DepthHardObjective#withMinDepth(int)} and {@link DepthHardObjective#withMaxDepth(int)} to configure.
133 *
134 * @return The objective.
135 * @see DepthHardObjective
136 */
137 public static DepthHardObjective createDepthHardObjective() {
138 return new DepthHardObjective();
139 }
140
141 /**
142 * This hard objective is fulfilled if the length of the trajectory is in the specified interval (inclusive). Use
143 * {@link DepthHardObjective#withMinDepth(int)} and {@link DepthHardObjective#withMaxDepth(int)} to configure.
144 *
145 * @param name
146 * @return The objective.
147 * @see DepthHardObjective
148 */
149 public static DepthHardObjective createDepthHardObjective(String name) {
150 return new DepthHardObjective(name);
151 }
152
153}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Solution.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Solution.java
new file mode 100644
index 00000000..b776db7a
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Solution.java
@@ -0,0 +1,60 @@
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.util.Collection;
12import java.util.HashSet;
13import java.util.Iterator;
14import java.util.Set;
15
16public class Solution {
17
18 private Set<SolutionTrajectory> trajectories;
19 private final Object stateId;
20
21 public Solution(Object stateId, SolutionTrajectory trajectory) {
22 this.stateId = stateId;
23 trajectories = new HashSet<>();
24 trajectories.add(trajectory);
25 }
26
27 public void addTrajectory(SolutionTrajectory trajectory) {
28 trajectories.add(trajectory);
29 }
30
31 public SolutionTrajectory getArbitraryTrajectory() {
32 return trajectories.iterator().next();
33 }
34
35 public SolutionTrajectory getShortestTrajectory() {
36 Iterator<SolutionTrajectory> iterator = trajectories.iterator();
37 SolutionTrajectory shortestTrajecotry = iterator.next();
38 int minSize = shortestTrajecotry.getTrajectoryLength();
39
40 while (iterator.hasNext()) {
41 SolutionTrajectory traj = iterator.next();
42 int size = traj.getTrajectoryLength();
43 if (size < minSize) {
44 shortestTrajecotry = traj;
45 minSize = size;
46 }
47 }
48
49 return shortestTrajecotry;
50 }
51
52 public Collection<SolutionTrajectory> getTrajectories() {
53 return trajectories;
54 }
55
56 public Object getStateCode() {
57 return stateId;
58 }
59
60}
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}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java
new file mode 100644
index 00000000..ed7a90da
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java
@@ -0,0 +1,123 @@
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 org.eclipse.viatra.dse.api.strategy.impl.BestFirstStrategy;
12import org.eclipse.viatra.dse.api.strategy.impl.BreadthFirstStrategy;
13import org.eclipse.viatra.dse.api.strategy.impl.DepthFirstStrategy;
14import org.eclipse.viatra.dse.api.strategy.impl.FixedPriorityStrategy;
15import org.eclipse.viatra.dse.api.strategy.impl.HillClimbingStrategy;
16import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
17
18/**
19 * Helper class for instantiating strategies. To implement a new strategy use the {@link IStrategy} interface.
20 *
21 * @author Andras Szabolcs Nagy
22 *
23 */
24public final class Strategies {
25
26 private Strategies() {
27 }
28
29 /**
30 * Creates a depth-first search exploration strategy without a depth limit.
31 *
32 * @return The strategy.
33 * @see DepthFirstStrategy
34 */
35 public static DepthFirstStrategy createDfsStrategy() {
36 return new DepthFirstStrategy();
37 }
38
39 /**
40 * Creates a depth-first search exploration strategy with a depth limit. A negative depth limit means no
41 * depth limit, zero means that it will check the initial state.
42 *
43 * @param depthLimit
44 * @return The strategy.
45 * @see DepthFirstStrategy
46 */
47 public static DepthFirstStrategy createDfsStrategy(int depthLimit) {
48 return new DepthFirstStrategy(depthLimit);
49 }
50
51 /**
52 * Creates a fixed priority exploration strategy without a depth limit. It is a depth-first search exploration
53 * strategy but from a current state it only explores the activations with the highest priority. Priorities can be
54 * defined on the strategy itself.
55 *
56 * @return The strategy.
57 * @see FixedPriorityStrategy
58 */
59 public static FixedPriorityStrategy createFixedPriorityStrategy() {
60 return createFixedPriorityStrategy(-1);
61 }
62
63 /**
64 * Creates a fixed priority exploration strategy with a depth limit, where a zero or negative depth limit means no
65 * depth limit. It is a depth-first search exploration strategy but from a current state it only explores the
66 * activations with the highest priority. Priorities can be defined on the strategy itself.
67 *
68 * @param depthLimit
69 * @return The strategy.
70 * @see FixedPriorityStrategy
71 */
72 public static FixedPriorityStrategy createFixedPriorityStrategy(int depthLimit) {
73 return new FixedPriorityStrategy().withDepthLimit(depthLimit);
74 }
75
76 /**
77 * Creates a breadth-first search exploration strategy without a depth limit.
78 *
79 * @return The strategy.
80 * @see BreadthFirstStrategy
81 */
82 public static BreadthFirstStrategy createBfsStrategy() {
83 return new BreadthFirstStrategy();
84 }
85
86 /**
87 * Creates a breadth-first search exploration strategy with a depth limit. A zero or negative depth limit means no
88 * depth limit.
89 *
90 * @param depthLimit
91 * @return The strategy.
92 * @see BreadthFirstStrategy
93 */
94 public static BreadthFirstStrategy createBfsStrategy(int depthLimit) {
95 return new BreadthFirstStrategy(depthLimit);
96 }
97
98 /**
99 * Creates a hill climbing exploration strategy. By default, it explores all neighborhood states and chooses the
100 * best one to continue with until all neighborhood states are dominated by the current state. Other options are
101 * available on the strategy.
102 *
103 * @return The strategy.
104 * @see HillClimbingStrategy
105 */
106 public static HillClimbingStrategy creatHillClimbingStrategy() {
107 return new HillClimbingStrategy();
108 }
109
110 /**
111 * See {@link BestFirstStrategy}.
112 */
113 public static BestFirstStrategy createBestFirstStrategy() {
114 return new BestFirstStrategy();
115 }
116
117 /**
118 * See {@link BestFirstStrategy}.
119 */
120 public static BestFirstStrategy createBestFirstStrategy(int depthLimit) {
121 return new BestFirstStrategy(depthLimit);
122 }
123}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java
new file mode 100644
index 00000000..fe5604a1
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java
@@ -0,0 +1,228 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Andras Szabolcs Nagy 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.strategy.impl;
10
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.Iterator;
14import java.util.PriorityQueue;
15
16import org.apache.log4j.Logger;
17import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
18import org.eclipse.viatra.dse.base.ThreadContext;
19import org.eclipse.viatra.dse.objectives.Fitness;
20import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
21import org.eclipse.viatra.dse.solutionstore.SolutionStore;
22
23/**
24 * This exploration strategy eventually explorers the whole design space but goes in the most promising directions
25 * first, based on the {@link Fitness}.
26 *
27 * There are a few parameter to tune such as
28 * <ul>
29 * <li>maximum depth</li>
30 * <li>continue the exploration from a state that satisfies the hard objectives (the default that it will
31 * backtrack),</li>
32 * <li>whether to continue the exploration from the newly explored state if it is at least equally good than the
33 * previous one or only if it is better (default is "at least equally good").</li>
34 * </ul>
35 *
36 * @author Andras Szabolcs Nagy
37 *
38 */
39public class BestFirstStrategy implements IStrategy {
40
41 private ThreadContext context;
42 private SolutionStore solutionStore;
43
44 private int maxDepth;
45 private boolean isInterrupted = false;
46 private boolean backTrackIfSolution = true;
47 private boolean onlyBetterFirst = false;
48
49 private PriorityQueue<TrajectoryWithFitness> trajectoiresToExplore;
50 private Logger logger = Logger.getLogger(IStrategy.class);
51
52 private static class TrajectoryWithFitness {
53
54 public Object[] trajectory;
55 public Fitness fitness;
56
57 public TrajectoryWithFitness(Object[] trajectory, Fitness fitness) {
58 super();
59 this.trajectory = trajectory;
60 this.fitness = fitness;
61 }
62
63 @Override
64 public String toString() {
65 return Arrays.toString(trajectory) + fitness.toString();
66 }
67
68 }
69
70 /**
71 * Creates a new best-first search algorithm without depth limit.
72 */
73 public BestFirstStrategy() {
74 this(-1);
75 }
76
77 /**
78 * Creates a new best-first search algorithm with depth limit.
79 *
80 * @param maxDepth
81 * A negative <code>maxDepth</code> means no depth limit, zero means the checking of the initial state.
82 */
83 public BestFirstStrategy(int maxDepth) {
84 if (maxDepth < 0) {
85 this.maxDepth = Integer.MAX_VALUE;
86 } else {
87 this.maxDepth = maxDepth;
88 }
89 }
90
91 public BestFirstStrategy continueIfHardObjectivesFulfilled() {
92 backTrackIfSolution = false;
93 return this;
94 }
95
96 public BestFirstStrategy goOnOnlyIfFitnessIsBetter() {
97 onlyBetterFirst = true;
98 return this;
99 }
100
101 @Override
102 public void initStrategy(ThreadContext context) {
103 this.context = context;
104 this.solutionStore = context.getGlobalContext().getSolutionStore();
105 final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper();
106
107 trajectoiresToExplore = new PriorityQueue<TrajectoryWithFitness>(11,
108 (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness));
109 }
110
111 @Override
112 public void explore() {
113 final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper();
114
115 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
116 if (!globalConstraintsAreSatisfied) {
117 logger.info("Global contraint is not satisifed in the first state. Terminate.");
118 return;
119 }
120
121 final Fitness firstFittness = context.calculateFitness();
122 if (firstFittness.isSatisifiesHardObjectives()) {
123 context.newSolution();
124 logger.info("First state is a solution. Terminate.");
125 return;
126 }
127
128 if (maxDepth == 0) {
129 return;
130 }
131
132 final Object[] firstTrajectory = context.getTrajectory().toArray(new Object[0]);
133 TrajectoryWithFitness currentTrajectoryWithFittness = new TrajectoryWithFitness(firstTrajectory, firstFittness);
134 trajectoiresToExplore.add(currentTrajectoryWithFittness);
135
136 mainLoop: while (!isInterrupted) {
137
138 if (currentTrajectoryWithFittness == null) {
139 if (trajectoiresToExplore.isEmpty()) {
140 logger.debug("State space is fully traversed.");
141 return;
142 } else {
143 currentTrajectoryWithFittness = trajectoiresToExplore.element();
144 if (logger.isDebugEnabled()) {
145 logger.debug("New trajectory is chosen: " + currentTrajectoryWithFittness);
146 }
147 context.getDesignSpaceManager().executeTrajectoryWithMinimalBacktrackWithoutStateCoding(currentTrajectoryWithFittness.trajectory);
148 }
149 }
150
151 Collection<Object> activationIds = context.getUntraversedActivationIds();
152 Iterator<Object> iterator = activationIds.iterator();
153
154 while (!isInterrupted && iterator.hasNext()) {
155 final Object nextActivation = iterator.next();
156 if (!iterator.hasNext()) {
157 logger.debug("Last untraversed activation of the state.");
158 trajectoiresToExplore.remove(currentTrajectoryWithFittness);
159 }
160
161 if (logger.isDebugEnabled()) {
162 logger.debug("Executing new activation: " + nextActivation);
163 }
164 context.executeAcitvationId(nextActivation);
165 if (context.isCurrentStateAlreadyTraversed()) {
166 logger.info("The new state is already visited.");
167 context.backtrack();
168 } else if (!context.checkGlobalConstraints()) {
169 logger.debug("Global contraint is not satisifed.");
170 context.backtrack();
171 } else {
172 final Fitness nextFitness = context.calculateFitness();
173 if (nextFitness.isSatisifiesHardObjectives()) {
174 solutionStore.newSolution(context);
175 logger.debug("Found a solution.");
176 if (backTrackIfSolution) {
177 context.backtrack();
178 continue;
179 }
180 }
181 if (context.getDepth() >= maxDepth) {
182 logger.debug("Reached max depth.");
183 context.backtrack();
184 continue;
185 }
186
187 TrajectoryWithFitness nextTrajectoryWithFittness = new TrajectoryWithFitness(
188 context.getTrajectory().toArray(), nextFitness);
189 trajectoiresToExplore.add(nextTrajectoryWithFittness);
190
191 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFittness.fitness,
192 nextTrajectoryWithFittness.fitness);
193 if (compare < 0) {
194 logger.debug("Better fitness, moving on: " + nextFitness);
195 currentTrajectoryWithFittness = nextTrajectoryWithFittness;
196 continue mainLoop;
197 } else if (compare == 0) {
198 if (onlyBetterFirst) {
199 logger.debug("Equally good fitness, backtrack: " + nextFitness);
200 context.backtrack();
201 continue;
202 } else {
203 logger.debug("Equally good fitness, moving on: " + nextFitness);
204 currentTrajectoryWithFittness = nextTrajectoryWithFittness;
205 continue mainLoop;
206 }
207 } else {
208 logger.debug("Worse fitness.");
209 currentTrajectoryWithFittness = null;
210 continue mainLoop;
211 }
212 }
213 }
214
215 logger.debug("State is fully traversed.");
216 trajectoiresToExplore.remove(currentTrajectoryWithFittness);
217 currentTrajectoryWithFittness = null;
218
219 }
220 logger.info("Interrupted.");
221 }
222
223 @Override
224 public void interruptStrategy() {
225 isInterrupted = true;
226 }
227
228}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java
new file mode 100644
index 00000000..6b7d9817
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java
@@ -0,0 +1,220 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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.strategy.impl;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.concurrent.BrokenBarrierException;
14import java.util.concurrent.ConcurrentLinkedQueue;
15import java.util.concurrent.CyclicBarrier;
16import java.util.concurrent.atomic.AtomicBoolean;
17
18import org.apache.log4j.Logger;
19import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
20import org.eclipse.viatra.dse.base.GlobalContext;
21import org.eclipse.viatra.dse.base.ThreadContext;
22import org.eclipse.viatra.dse.objectives.Fitness;
23import org.eclipse.viatra.dse.solutionstore.SolutionStore;
24
25/**
26 * A breadth-first search algorithm implementation, that
27 * <ul>
28 * <li>can work with multiple threads,</li>
29 * <li>indeterministic,</li>
30 * <li>saves all states (trajectories) as solutions that fulfill all the hard objectives,</li>
31 * <li>can have a depth limit,</li>
32 * <li>will backtrack when a model satisfies the hard objectives (after saving it as a solution) and will not explore
33 * beyond that state.</li>
34 * </ul>
35 *
36 * @author Andras Szabolcs Nagy
37 *
38 */
39public class BreadthFirstStrategy implements IStrategy {
40
41 private static final class BfsSharedObject {
42 private final ConcurrentLinkedQueue<Object[]> trajectoryQueue1 = new ConcurrentLinkedQueue<>();
43 private final ConcurrentLinkedQueue<Object[]> trajectoryQueue2 = new ConcurrentLinkedQueue<>();
44
45 private final AtomicBoolean pushToQueue1 = new AtomicBoolean(false);
46 private final AtomicBoolean designSpaceTraversed = new AtomicBoolean(false);
47
48 public final CyclicBarrier barrier;
49
50 public BfsSharedObject(int numberOfThreads) {
51 barrier = new CyclicBarrier(numberOfThreads, () -> {
52 boolean oldValue = pushToQueue1.get();
53 pushToQueue1.set(!oldValue);
54 if (trajectoryQueue1.isEmpty() && trajectoryQueue2.isEmpty()) {
55 designSpaceTraversed.set(true);
56 }
57 });
58 }
59
60 public Object[] poll() {
61 if (pushToQueue1.get()) {
62 return trajectoryQueue2.poll();
63 } else {
64 return trajectoryQueue1.poll();
65 }
66 }
67
68 public void push(Object[] trajectory) {
69 if (pushToQueue1.get()) {
70 trajectoryQueue1.add(trajectory);
71 } else {
72 trajectoryQueue2.add(trajectory);
73 }
74 }
75
76 public boolean isDesignSpaceTraversed() {
77 return designSpaceTraversed.get();
78 }
79 }
80
81 private int maxDepth = 0;
82 private BfsSharedObject shared;
83 private boolean isInterrupted = false;
84 private ThreadContext context;
85 private Logger logger = Logger.getLogger(IStrategy.class);
86 private SolutionStore solutionStore;
87 private boolean isFirstThread = false;
88
89 /**
90 * Creates a new breadth-first search algorithm without depth limit.
91 */
92 public BreadthFirstStrategy() {
93 this.maxDepth = Integer.MAX_VALUE;
94 }
95
96 /**
97 * Creates a new breadth-first search algorithm with depth limit.
98 *
99 * @param maxDepth
100 * A negative <code>maxDepth</code> means no depth limit, zero means the checking of the initial state.
101 */
102 public BreadthFirstStrategy(int maxDepth) {
103 if (maxDepth < 0) {
104 this.maxDepth = Integer.MAX_VALUE;
105 } else {
106 this.maxDepth = maxDepth;
107 }
108 }
109
110 @Override
111 public void initStrategy(ThreadContext context) {
112 this.context = context;
113 this.solutionStore = context.getGlobalContext().getSolutionStore();
114
115 GlobalContext globalContext = context.getGlobalContext();
116 if (globalContext.getSharedObject() == null) {
117 isFirstThread = true;
118 shared = new BfsSharedObject(globalContext.getThreadPool().getMaximumPoolSize());
119 globalContext.setSharedObject(shared);
120 logger.info("Breadth-first exploration strategy is inited.");
121 } else {
122 shared = (BfsSharedObject) globalContext.getSharedObject();
123 }
124 }
125
126 @Override
127 public void explore() {
128
129 if (isFirstThread) {
130
131 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
132 if (!globalConstraintsAreSatisfied) {
133 logger.info("Global contraint is not satisifed in the first state. Terminate.");
134 return;
135 }
136
137 Fitness fitness = context.calculateFitness();
138 if (fitness.isSatisifiesHardObjectives()) {
139 context.newSolution();
140 logger.info("First state is a solution. Terminate.");
141 return;
142 }
143
144 Object[] currentTrajectory = context.getTrajectory().toArray(new Object[0]);
145
146 shared.push(currentTrajectory);
147
148 startThreads();
149 } else {
150 try {
151 shared.barrier.await();
152 } catch (InterruptedException | BrokenBarrierException e) {
153 }
154 }
155
156 mainLoop: while (!isInterrupted && !shared.isDesignSpaceTraversed()) {
157
158 Object[] next = shared.poll();
159 while (next == null) {
160 try {
161 logger.debug("Reached barrier.");
162 shared.barrier.await();
163 } catch (InterruptedException | BrokenBarrierException e1) {
164 }
165 if (isInterrupted || shared.isDesignSpaceTraversed()) {
166 break mainLoop;
167 }
168 next = shared.poll();
169 }
170
171 context.backtrackUntilRoot();
172
173 context.executeTrajectory(next);
174
175 Collection<Object> activationIds = context.getCurrentActivationIds();
176 int i = activationIds.size() - 1;
177
178 while (!isInterrupted && i >= 0) {
179
180 Iterator<Object> iterator = activationIds.iterator();
181 int index = i--;
182 while (iterator.hasNext() && index > 0) {
183 index--;
184 iterator.next();
185 }
186 Object activationIdToTry = iterator.next();
187
188 context.executeAcitvationId(activationIdToTry);
189
190 if (context.isCurrentStateAlreadyTraversed()) {
191 logger.info("The new state is already visited.");
192 } else if (!context.checkGlobalConstraints()) {
193 logger.debug("Global contraint is not satisifed.");
194 } else if (context.calculateFitness().isSatisifiesHardObjectives()) {
195 solutionStore.newSolution(context);
196 logger.debug("Found a solution.");
197 } else if (context.getDepth() >= maxDepth) {
198 logger.debug("Reached max depth.");
199 } else {
200 Object[] currentTrajectory = context.getTrajectory().toArray(new Object[0]);
201 shared.push(currentTrajectory);
202 }
203
204 context.backtrack();
205 }
206
207 }
208 }
209
210 private void startThreads() {
211 context.startAllThreads(() -> new BreadthFirstStrategy(maxDepth));
212 }
213
214 @Override
215 public void interruptStrategy() {
216 isInterrupted = true;
217 shared.barrier.reset();
218 }
219
220}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java
new file mode 100644
index 00000000..22a4a683
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java
@@ -0,0 +1,188 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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.strategy.impl;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Random;
14import java.util.concurrent.atomic.AtomicBoolean;
15
16import org.apache.log4j.Logger;
17import org.eclipse.viatra.dse.api.DSEException;
18import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
19import org.eclipse.viatra.dse.base.ThreadContext;
20import org.eclipse.viatra.dse.objectives.Fitness;
21
22/**
23 * A depth-first search algorithm implementation, that
24 * <ul>
25 * <li>can work with multiple threads,</li>
26 * <li>randomly traverses the search space,</li>
27 * <li>saves all states (trajectories) as solutions that fulfill all the hard objectives,</li>
28 * <li>can have a depth limit,</li>
29 * <li>will backtrack when a model satisfies the hard objectives (after saving it as a solution), which can be modified
30 * by calling {@link #continueIfHardObjectivesFulfilled()}</li>
31 * </ul>
32 *
33 * @author Andras Szabolcs Nagy
34 *
35 */
36public class DepthFirstStrategy implements IStrategy {
37
38 private int maxDepth;
39 private AtomicBoolean isInterrupted = new AtomicBoolean(false);
40 private ThreadContext context;
41
42 private Logger logger = Logger.getLogger(IStrategy.class);
43
44 private Random random = new Random();
45 private boolean backTrackIfSolution = true;
46
47 /**
48 * Creates a new depth-first search algorithm without depth limit.
49 */
50 public DepthFirstStrategy() {
51 this.maxDepth = Integer.MAX_VALUE;
52 }
53
54 /**
55 * Creates a new depth-first search algorithm with depth limit.
56 *
57 * @param maxDepth
58 * A negative <code>maxDepth</code> means no depth limit, zero means the checking of the initial state.
59 */
60 public DepthFirstStrategy(int maxDepth) {
61 if (maxDepth < 0) {
62 this.maxDepth = Integer.MAX_VALUE;
63 } else {
64 this.maxDepth = maxDepth;
65 }
66 }
67
68 /**
69 * If called, the algorithm will not backtrack after the hard objectives are fulfilled, instead it goes deeper in
70 * the search space.
71 */
72 public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
73 backTrackIfSolution = false;
74 return this;
75 }
76
77 @Override
78 public void initStrategy(ThreadContext context) {
79 this.context = context;
80
81 if (context.getSharedObject() == null) {
82 context.setSharedObject(new Object());
83 logger.info("Depth-first exploration strategy is initied.");
84 startThreads();
85 }
86
87 }
88
89 private void startThreads() {
90 context.startAllThreads(() -> new DepthFirstStrategy(maxDepth));
91 }
92
93 @Override
94 public void explore() {
95
96 mainloop: do {
97
98 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
99 if (!globalConstraintsAreSatisfied) {
100 boolean isSuccessfulUndo = context.backtrack();
101 if (!isSuccessfulUndo) {
102 logger.info("Global contraint is not satisifed and cannot backtrack.");
103 break;
104 } else {
105 logger.debug("Global contraint is not satisifed, backtrack.");
106 continue;
107 }
108 }
109
110 Fitness fitness = context.calculateFitness();
111 if (fitness.isSatisifiesHardObjectives()) {
112 context.newSolution();
113 if (backTrackIfSolution) {
114 boolean isSuccessfulUndo = context.backtrack();
115 if (!isSuccessfulUndo) {
116 logger.info("Found a solution but cannot backtrack.");
117 break;
118 } else {
119 logger.debug("Found a solution, backtrack.");
120 continue;
121 }
122 }
123 }
124
125 if (context.getDepth() >= maxDepth) {
126 boolean isSuccessfulUndo = context.backtrack();
127 if (!isSuccessfulUndo) {
128 logger.info("Reached max depth but cannot bactrack.");
129 break;
130 } else {
131 logger.debug("Reached max depth, bactrack.");
132 continue;
133 }
134 }
135
136 if (isInterrupted.get()) {
137 logger.info("Interrupted, stop exploration.");
138 break;
139 }
140
141 Object activationId = null;
142 Collection<Object> activationIds;
143
144 do {
145 activationIds = context.getUntraversedActivationIds();
146 if (activationIds.isEmpty()) {
147 boolean isSuccessfulUndo = context.backtrack();
148 if (!isSuccessfulUndo) {
149 logger.info("No more transitions from current state and cannot backtrack.");
150 break mainloop;
151 } else {
152 logger.debug("No more transitions from current state, backtrack.");
153 continue;
154 }
155 }
156 } while (activationIds.isEmpty());
157
158 int index = random.nextInt(activationIds.size());
159
160 Iterator<Object> iterator = activationIds.iterator();
161 while (index-- > 0) {
162 iterator.next();
163 }
164 activationId = iterator.next();
165
166 context.executeAcitvationId(activationId);
167
168 boolean loopInTrajectory = context.isCurrentStateInTrajectory();
169 if (loopInTrajectory) {
170 boolean isSuccessfulUndo = context.backtrack();
171 if (!isSuccessfulUndo) {
172 throw new DSEException("The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
173 } else {
174 logger.info("The new state is already visited in the trajectory, backtrack.");
175 }
176 }
177
178 } while (true);
179
180 logger.info("Terminated.");
181 }
182
183 @Override
184 public void interruptStrategy() {
185 isInterrupted.set(true);
186 }
187
188}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java
new file mode 100644
index 00000000..4ccda4ce
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java
@@ -0,0 +1,208 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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.strategy.impl;
10
11import java.util.Collection;
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15import java.util.Random;
16import java.util.concurrent.atomic.AtomicBoolean;
17
18import org.apache.log4j.Logger;
19import org.eclipse.viatra.dse.api.DSEException;
20import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
21import org.eclipse.viatra.dse.base.ThreadContext;
22import org.eclipse.viatra.dse.objectives.Fitness;
23import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
24
25import com.google.common.collect.Lists;
26
27/**
28 * Works as {@link DepthFirstStrategy} but:
29 * <ul>
30 * <li>works only with single thread,</li>
31 * <li>in a given state, it only traverses the activations with locally the highest priority.</li>
32 * </ul>
33 *
34 * @author Andras Szabolcs Nagy
35 *
36 */
37public class FixedPriorityStrategy implements IStrategy {
38
39 private int maxDepth = Integer.MAX_VALUE;
40 private AtomicBoolean isInterrupted = new AtomicBoolean(false);
41 private ThreadContext context;
42
43 private Logger logger = Logger.getLogger(IStrategy.class);
44 private Map<BatchTransformationRule<?, ?>, Integer> priorities = new HashMap<BatchTransformationRule<?, ?>, Integer>();
45
46 private Random random = new Random();
47 private Map<Object, List<Object>> bestPriorityInState = new HashMap<>();
48
49 /**
50 * Adds a depth limit to the strategy.
51 *
52 * @param depthLimit
53 * The depth limit.
54 * @return The actual instance to enable a builder pattern like usage.
55 */
56 public FixedPriorityStrategy withDepthLimit(int maxDepth) {
57 if (maxDepth < 0) {
58 this.maxDepth = Integer.MAX_VALUE;
59 } else {
60 this.maxDepth = maxDepth;
61 }
62 return this;
63 }
64
65 /**
66 * Assigns a priority to a rule. Unassigned rule will have a priority of 0.
67 *
68 * @param rule
69 * The transformation rule.
70 * @param priority
71 * The priority of the rule. Higher is better.
72 * @return The actual instance to enable a builder pattern like usage.
73 */
74 public FixedPriorityStrategy withRulePriority(BatchTransformationRule<?, ?> rule, int priority) {
75 priorities.put(rule, priority);
76 return this;
77 }
78
79 public Map<BatchTransformationRule<?, ?>, Integer> getPriorities() {
80 return priorities;
81 }
82
83 @Override
84 public void initStrategy(ThreadContext context) {
85 this.context = context;
86
87 logger.info("Fixed priority exploration strategy is initied.");
88 }
89
90 @Override
91 public void explore() {
92
93 mainloop: do {
94
95 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
96 if (!globalConstraintsAreSatisfied) {
97 boolean isSuccessfulUndo = context.backtrack();
98 if (!isSuccessfulUndo) {
99 logger.info("Global contraint is not satisifed and cannot backtrack.");
100 break;
101 } else {
102 logger.debug("Global contraint is not satisifed, backtrack.");
103 continue;
104 }
105 }
106
107 Fitness fitness = context.calculateFitness();
108 if (fitness.isSatisifiesHardObjectives()) {
109 context.newSolution();
110 boolean isSuccessfulUndo = context.backtrack();
111 if (!isSuccessfulUndo) {
112 logger.info("Found a solution but cannot backtrack.");
113 break;
114 } else {
115 logger.debug("Found a solution, backtrack.");
116 continue;
117 }
118 }
119
120 if (context.getDepth() >= maxDepth) {
121 boolean isSuccessfulUndo = context.backtrack();
122 if (!isSuccessfulUndo) {
123 logger.info("Reached max depth but cannot bactrack.");
124 break;
125 } else {
126 logger.debug("Reached max depth, bactrack.");
127 continue;
128 }
129 }
130
131 if (isInterrupted.get()) {
132 logger.info("Interrupted, stop exploration.");
133 break;
134 }
135
136 List<Object> transitions;
137
138 do {
139
140 transitions = bestPriorityInState.get(context.getCurrentStateId());
141
142 if (transitions == null) {
143 Integer bestPriority = getBestPriority(context.getCurrentActivationIds());
144 transitions = Lists.newArrayList();
145 for (Object iTransition : context.getCurrentActivationIds()) {
146 Integer integer = priorities.get(context.getRuleByActivationId(iTransition));
147 if (integer == null) {
148 integer = Integer.valueOf(0);
149 }
150 if (integer.equals(bestPriority)) {
151 transitions.add(iTransition);
152 }
153 }
154 bestPriorityInState.put(context.getCurrentStateId(), transitions);
155 }
156
157 if (transitions.isEmpty()) {
158 boolean isSuccessfulUndo = context.backtrack();
159 if (!isSuccessfulUndo) {
160 logger.info("No more transitions from current state and cannot backtrack.");
161 break mainloop;
162 } else {
163 logger.debug("No more transitions from current state, backtrack.");
164 continue;
165 }
166 }
167 } while (transitions.isEmpty());
168
169 int index = random.nextInt(transitions.size());
170 Object transition = transitions.remove(index);
171
172 context.executeAcitvationId(transition);
173
174 boolean loopInTrajectory = context.isCurrentStateInTrajectory();
175 if (loopInTrajectory) {
176 boolean isSuccessfulUndo = context.backtrack();
177 if (!isSuccessfulUndo) {
178 throw new DSEException(
179 "The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
180 } else {
181 logger.info("The new state is already visited in the trajectory, backtrack.");
182 }
183 }
184
185 } while (true);
186
187 logger.info("Terminated.");
188 }
189
190 @Override
191 public void interruptStrategy() {
192 isInterrupted.set(true);
193 }
194
195 private Integer getBestPriority(Collection<? extends Object> transitions) {
196 Integer bestPriority = Integer.MIN_VALUE;
197 for (Object iTransition : transitions) {
198 Integer priority = priorities.get(context.getRuleByActivationId(iTransition));
199 if (priority == null) {
200 priority = Integer.valueOf(0);
201 }
202 if (priority > bestPriority) {
203 bestPriority = priority;
204 }
205 }
206 return bestPriority;
207 }
208}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java
new file mode 100644
index 00000000..0ccb0668
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java
@@ -0,0 +1,142 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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.strategy.impl;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Random;
14import java.util.concurrent.atomic.AtomicBoolean;
15
16import org.apache.log4j.Logger;
17import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
18import org.eclipse.viatra.dse.base.ThreadContext;
19import org.eclipse.viatra.dse.objectives.Fitness;
20import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
21import org.eclipse.viatra.dse.objectives.TrajectoryFitness;
22
23public class HillClimbingStrategy implements IStrategy {
24
25 private AtomicBoolean isInterrupted = new AtomicBoolean(false);
26 private ThreadContext context;
27
28 private Logger logger = Logger.getLogger(IStrategy.class);
29
30 private Random random = new Random();
31 private double percentOfOpenedStates;
32 private ObjectiveComparatorHelper objectiveComparatorHelper;
33
34 public HillClimbingStrategy() {
35 this(2);
36 }
37
38 public HillClimbingStrategy(double percentOfOpenedStates) {
39 this.percentOfOpenedStates = percentOfOpenedStates;
40 }
41
42 @Override
43 public void initStrategy(ThreadContext context) {
44 this.context = context;
45 objectiveComparatorHelper = context.getObjectiveComparatorHelper();
46 logger.info("Hill climbing exploration strategy is initied.");
47 }
48
49 @Override
50 public void explore() {
51
52 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
53 if (!globalConstraintsAreSatisfied) {
54 boolean isSuccessfulUndo = context.backtrack();
55 if (!isSuccessfulUndo) {
56 logger.info("Global contraint is not satisifed and cannot backtrack.");
57 return;
58 }
59 }
60
61 mainloop: do {
62
63 Fitness previousFitness = context.calculateFitness();
64
65 logger.debug("Current depth: " + context.getDepth() + " Fitness: " + previousFitness);
66
67 Collection<Object> transitionsFromCurrentState = context.getCurrentActivationIds();
68
69 while (transitionsFromCurrentState.isEmpty()) {
70 logger.debug("No transitions from current state: considered as a solution.");
71 saveSolutionAndBacktrack();
72 continue mainloop;
73 }
74
75 ArrayList<Object> transitionsToTry = new ArrayList<>(transitionsFromCurrentState.size());
76 for (Object transition : transitionsFromCurrentState) {
77 transitionsToTry.add(transition);
78 }
79 double numberOfTransitionsToTry = transitionsToTry.size() * percentOfOpenedStates;
80
81 for (; numberOfTransitionsToTry > 0 && !transitionsToTry.isEmpty(); numberOfTransitionsToTry--) {
82 int index = random.nextInt(transitionsToTry.size());
83 Object transition = transitionsToTry.remove(index);
84
85 context.executeAcitvationId(transition);
86
87 if (!context.checkGlobalConstraints()) {
88 logger.debug("Global contraint is not satisifed, backtrack.");
89 context.backtrack();
90 continue;
91 }
92 if (context.isCurrentStateInTrajectory()) {
93 logger.debug("Current state is in trajectory, backtrack.");
94 context.backtrack();
95 continue;
96 }
97
98 Fitness fitness = context.calculateFitness();
99 objectiveComparatorHelper.addTrajectoryFitness(
100 new TrajectoryFitness(context.getTrajectoryInfo().getLastActivationId(), fitness));
101 context.backtrack();
102 }
103
104 if (objectiveComparatorHelper.getTrajectoryFitnesses().isEmpty()) {
105 logger.debug("No viable transitions from current state: considered as a solution.");
106 saveSolutionAndBacktrack();
107 continue;
108 }
109
110 TrajectoryFitness randomBestFitness = objectiveComparatorHelper.getRandomBest();
111 objectiveComparatorHelper.clearTrajectoryFitnesses();
112
113 int compare = objectiveComparatorHelper.compare(previousFitness, randomBestFitness.fitness);
114
115 if (compare > 0) {
116 saveSolutionAndBacktrack();
117 continue;
118 } else {
119 previousFitness = randomBestFitness.fitness;
120 Object transition = randomBestFitness.trajectory[randomBestFitness.trajectory.length - 1];
121 context.executeAcitvationId(transition);
122 }
123
124 } while (!isInterrupted.get());
125
126 logger.info("Terminated.");
127 }
128
129 private void saveSolutionAndBacktrack() {
130 context.calculateFitness();
131 context.newSolution();
132 logger.debug("Found solution: " + context.getTrajectoryInfo().toString());
133 logger.debug("Backtrack for more solutions, if needed.");
134 context.backtrackUntilRoot();
135 }
136
137 @Override
138 public void interruptStrategy() {
139 isInterrupted.set(true);
140 }
141
142}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java
new file mode 100644
index 00000000..af8fb8cc
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java
@@ -0,0 +1,163 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, 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.strategy.impl;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Random;
14import java.util.concurrent.atomic.AtomicBoolean;
15import java.util.concurrent.atomic.AtomicInteger;
16
17import org.apache.log4j.Logger;
18import org.eclipse.viatra.dse.api.DSEException;
19import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
20import org.eclipse.viatra.dse.base.GlobalContext;
21import org.eclipse.viatra.dse.base.ThreadContext;
22import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
23import org.eclipse.viatra.dse.objectives.Fitness;
24
25public class RandomSearchStrategy implements IStrategy {
26
27 private static class SharedData {
28 public final AtomicInteger triesLeft;
29 public final int minDepth;
30 public final int maxDepth;
31
32 public SharedData(int minDepth, int maxDepth, int numberOfTries) {
33 this.minDepth = minDepth;
34 this.maxDepth = maxDepth;
35 this.triesLeft = new AtomicInteger(numberOfTries);
36 }
37 }
38
39 private int maxDepth = -1;
40 private Random rnd = new Random();
41 private SharedData shared;
42 private TrajectoryInfo trajectoryInfo;
43 int nth;
44 private ThreadContext context;
45 private AtomicBoolean isInterrupted = new AtomicBoolean(false);
46 private Logger logger = Logger.getLogger(IStrategy.class);
47
48 public RandomSearchStrategy(int minDepth, int maxDepth, int numberOfTries) {
49 shared = new SharedData(minDepth, maxDepth, numberOfTries);
50 }
51
52 private RandomSearchStrategy() {
53 }
54
55 @Override
56 public void initStrategy(ThreadContext context) {
57 this.context = context;
58 trajectoryInfo = context.getTrajectoryInfo();
59 GlobalContext gc = context.getGlobalContext();
60
61 Object sharedObject = gc.getSharedObject();
62 if (sharedObject == null) {
63 gc.setSharedObject(shared);
64 logger.info("Random exploration strategy is initied.");
65 startThreads();
66 } else {
67 shared = (SharedData) sharedObject;
68 }
69
70 maxDepth = rnd.nextInt(shared.maxDepth - shared.minDepth) + shared.minDepth;
71
72 }
73
74 @Override
75 public void explore() {
76
77 do {
78
79 boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
80 if (!globalConstraintsAreSatisfied) {
81 boolean isSuccessfulUndo = context.backtrack();
82 if (!isSuccessfulUndo) {
83 logger.info("Global contraint is not satisifed and cannot backtrack.");
84 break;
85 } else {
86 logger.debug("Global contraint is not satisifed, backtrack.");
87 continue;
88 }
89 }
90
91 Fitness fitness = context.calculateFitness();
92 if (fitness.isSatisifiesHardObjectives()) {
93 context.newSolution();
94 boolean isSuccessfulUndo = context.backtrack();
95 if (!isSuccessfulUndo) {
96 logger.info("Found a solution but cannot backtrack.");
97 break;
98 } else {
99 logger.debug("Found a solution, backtrack.");
100 continue;
101 }
102 }
103
104 if (trajectoryInfo.getDepth() < maxDepth) {
105
106 Collection<Object> transitions = context.getCurrentActivationIds();
107 int index = rnd.nextInt(transitions.size());
108 Object transition = getByIndex(transitions, index);
109 context.executeAcitvationId(transition);
110
111 } else {
112
113 nth = shared.triesLeft.getAndDecrement();
114 logger.debug(nth + " tries left");
115 if (nth > 0) {
116
117 context.backtrackUntilRoot();
118 maxDepth = rnd.nextInt(shared.maxDepth - shared.minDepth) + shared.minDepth;
119
120 } else {
121 break;
122 }
123 }
124
125 boolean loopInTrajectory = context.isCurrentStateInTrajectory();
126 if (loopInTrajectory) {
127 boolean isSuccessfulUndo = context.backtrack();
128 if (!isSuccessfulUndo) {
129 throw new DSEException(
130 "The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
131 } else {
132 logger.info("The new state is already visited in the trajectory, backtrack.");
133 }
134 }
135
136 } while (isInterrupted.get());
137
138 logger.info("Terminated.");
139 }
140
141 @Override
142 public void interruptStrategy() {
143 isInterrupted.set(true);
144 }
145
146 private void startThreads() {
147 context.startAllThreads(RandomSearchStrategy::new);
148 }
149
150 private static Object getByIndex(Collection<Object> availableTransitions, int index) {
151 int i = 0;
152 Iterator<Object> iterator = availableTransitions.iterator();
153 while (iterator.hasNext()) {
154 Object transition = iterator.next();
155 if (i == index) {
156 return transition;
157 } else {
158 ++i;
159 }
160 }
161 throw new IndexOutOfBoundsException("size: " + availableTransitions.size() + ", index: " + index);
162 }
163}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java
new file mode 100644
index 00000000..8c164396
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy 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.strategy.interfaces;
10
11import org.eclipse.viatra.dse.base.ThreadContext;
12import org.eclipse.viatra.dse.solutionstore.SolutionStore;
13
14/**
15 * This high level interface is responsible for defining basic operations of an exploration strategy.
16 *
17 * @author Andras Szabolcs Nagy
18 *
19 */
20public interface IStrategy {
21
22 /**
23 * Initializes the strategy with a specific {@link ThreadContext}.
24 *
25 * @param context
26 * The context.
27 */
28 void initStrategy(ThreadContext context);
29
30 /**
31 * This method explores the design space as the implementation specifies. It will be called only once, hence the
32 * exploration loop is run by the implementation. The termination condition is also specified by the implementation
33 * and when it returns the exploration thread will be disposed.
34 */
35 void explore();
36
37 /**
38 * The implementation of this interface should be ready to be interrupted. If this method is called, the
39 * {@link IStrategy#explore()} method should return ASAP.
40 *
41 * This method is also called by the {@link SolutionStore} class if enough solutions are found.
42 */
43 void interruptStrategy();
44}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java
new file mode 100644
index 00000000..b3352d13
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java
@@ -0,0 +1,13 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy 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.strategy.interfaces;
10
11public interface IStrategyFactory {
12 IStrategy createStrategy();
13}