diff options
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api')
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 | *******************************************************************************/ | ||
9 | package 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 | */ | ||
15 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import java.util.Objects; | ||
12 | import java.util.function.Consumer; | ||
13 | |||
14 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
15 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
16 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher; | ||
17 | import 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 | ||
33 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashSet; | ||
13 | import java.util.Set; | ||
14 | import java.util.Timer; | ||
15 | import java.util.TimerTask; | ||
16 | import java.util.concurrent.atomic.AtomicBoolean; | ||
17 | |||
18 | import org.apache.log4j.BasicConfigurator; | ||
19 | import org.apache.log4j.Level; | ||
20 | import org.apache.log4j.Logger; | ||
21 | import org.eclipse.emf.common.notify.Notifier; | ||
22 | import org.eclipse.emf.ecore.EObject; | ||
23 | import org.eclipse.emf.ecore.EPackage; | ||
24 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
25 | import org.eclipse.viatra.dse.base.DesignSpaceManager; | ||
26 | import org.eclipse.viatra.dse.base.GlobalContext; | ||
27 | import org.eclipse.viatra.dse.designspace.api.DesignSpace; | ||
28 | import org.eclipse.viatra.dse.designspace.api.IDesignSpace; | ||
29 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint; | ||
30 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
31 | import org.eclipse.viatra.dse.solutionstore.ISolutionNameProvider; | ||
32 | import org.eclipse.viatra.dse.solutionstore.IdBasedSolutionNameProvider; | ||
33 | import org.eclipse.viatra.dse.solutionstore.SolutionStore; | ||
34 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
35 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
36 | import org.eclipse.viatra.dse.statecoding.simple.SimpleStateCoderFactory; | ||
37 | import org.eclipse.viatra.dse.visualizer.IDesignSpaceVisualizer; | ||
38 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
39 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
40 | import 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 | */ | ||
75 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import org.eclipse.viatra.dse.objectives.impl.CompositeObjective; | ||
12 | import org.eclipse.viatra.dse.objectives.impl.ConstraintsObjective; | ||
13 | import org.eclipse.viatra.dse.objectives.impl.AlwaysSatisfiedDummyHardObjective; | ||
14 | import org.eclipse.viatra.dse.objectives.impl.DepthHardObjective; | ||
15 | import org.eclipse.viatra.dse.objectives.impl.NeverSatisfiedDummyHardObjective; | ||
16 | import org.eclipse.viatra.dse.objectives.impl.NoRuleActivationsHardObjective; | ||
17 | import 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 | */ | ||
26 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashSet; | ||
13 | import java.util.Iterator; | ||
14 | import java.util.Set; | ||
15 | |||
16 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import java.lang.reflect.InvocationTargetException; | ||
12 | import java.util.HashSet; | ||
13 | import java.util.List; | ||
14 | import java.util.Objects; | ||
15 | import java.util.function.Consumer; | ||
16 | |||
17 | import org.eclipse.emf.common.notify.Notifier; | ||
18 | import org.eclipse.emf.edit.command.ChangeCommand; | ||
19 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
20 | import org.eclipse.viatra.dse.base.DseIdPoolHelper; | ||
21 | import org.eclipse.viatra.dse.designspace.api.IBacktrackListener; | ||
22 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
23 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
24 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
25 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
26 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
27 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
28 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
29 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher; | ||
30 | import org.eclipse.viatra.query.runtime.emf.EMFScope; | ||
31 | import org.eclipse.viatra.query.runtime.matchers.ViatraQueryRuntimeException; | ||
32 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
33 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
34 | |||
35 | import 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 | */ | ||
52 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api; | ||
10 | |||
11 | import org.eclipse.viatra.dse.api.strategy.impl.BestFirstStrategy; | ||
12 | import org.eclipse.viatra.dse.api.strategy.impl.BreadthFirstStrategy; | ||
13 | import org.eclipse.viatra.dse.api.strategy.impl.DepthFirstStrategy; | ||
14 | import org.eclipse.viatra.dse.api.strategy.impl.FixedPriorityStrategy; | ||
15 | import org.eclipse.viatra.dse.api.strategy.impl.HillClimbingStrategy; | ||
16 | import 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 | */ | ||
24 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.Arrays; | ||
12 | import java.util.Collection; | ||
13 | import java.util.Iterator; | ||
14 | import java.util.PriorityQueue; | ||
15 | |||
16 | import org.apache.log4j.Logger; | ||
17 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
18 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
19 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
20 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper; | ||
21 | import 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 | */ | ||
39 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Iterator; | ||
13 | import java.util.concurrent.BrokenBarrierException; | ||
14 | import java.util.concurrent.ConcurrentLinkedQueue; | ||
15 | import java.util.concurrent.CyclicBarrier; | ||
16 | import java.util.concurrent.atomic.AtomicBoolean; | ||
17 | |||
18 | import org.apache.log4j.Logger; | ||
19 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
20 | import org.eclipse.viatra.dse.base.GlobalContext; | ||
21 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
22 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
23 | import 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 | */ | ||
39 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Iterator; | ||
13 | import java.util.Random; | ||
14 | import java.util.concurrent.atomic.AtomicBoolean; | ||
15 | |||
16 | import org.apache.log4j.Logger; | ||
17 | import org.eclipse.viatra.dse.api.DSEException; | ||
18 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
19 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
20 | import 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 | */ | ||
36 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashMap; | ||
13 | import java.util.List; | ||
14 | import java.util.Map; | ||
15 | import java.util.Random; | ||
16 | import java.util.concurrent.atomic.AtomicBoolean; | ||
17 | |||
18 | import org.apache.log4j.Logger; | ||
19 | import org.eclipse.viatra.dse.api.DSEException; | ||
20 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
21 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
22 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
23 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
24 | |||
25 | import 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 | */ | ||
37 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.Random; | ||
14 | import java.util.concurrent.atomic.AtomicBoolean; | ||
15 | |||
16 | import org.apache.log4j.Logger; | ||
17 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
18 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
19 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
20 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper; | ||
21 | import org.eclipse.viatra.dse.objectives.TrajectoryFitness; | ||
22 | |||
23 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.impl; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Iterator; | ||
13 | import java.util.Random; | ||
14 | import java.util.concurrent.atomic.AtomicBoolean; | ||
15 | import java.util.concurrent.atomic.AtomicInteger; | ||
16 | |||
17 | import org.apache.log4j.Logger; | ||
18 | import org.eclipse.viatra.dse.api.DSEException; | ||
19 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
20 | import org.eclipse.viatra.dse.base.GlobalContext; | ||
21 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
22 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
23 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
24 | |||
25 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.interfaces; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | import 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 | */ | ||
20 | public 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 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.api.strategy.interfaces; | ||
10 | |||
11 | public interface IStrategyFactory { | ||
12 | IStrategy createStrategy(); | ||
13 | } | ||