diff options
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src')
76 files changed, 9108 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..d1a41065 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java | |||
@@ -0,0 +1,338 @@ | |||
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 | editingDomain.getCommandStack().execute(cc); | ||
210 | listener.forwardWorked(System.nanoTime() - start); | ||
211 | } | ||
212 | |||
213 | isActivationFound = true; | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | if (!isActivationFound) { | ||
218 | throw new UncheckedExecutionException( | ||
219 | "Activation was not found for transformation! Possible cause: wrong model, bad state coder. index: " | ||
220 | + index + " Activation code: " + activationCode, | ||
221 | null); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * Call this method to undo the last transformation. | ||
227 | * | ||
228 | * @return True, if it was successful. | ||
229 | */ | ||
230 | public boolean undoLastTransformation() { | ||
231 | Objects.requireNonNull(editingDomain, "To be able to undo the transformation initialize with editing domain."); | ||
232 | long start = System.nanoTime(); | ||
233 | boolean result; | ||
234 | |||
235 | if (currentIndex > 0) { | ||
236 | try { | ||
237 | ((AdvancedViatraQueryEngine) engine).delayUpdatePropagation(() -> { | ||
238 | editingDomain.getCommandStack().undo(); | ||
239 | return null; | ||
240 | }); | ||
241 | } catch (InvocationTargetException e) { | ||
242 | throw new RuntimeException(e); | ||
243 | } | ||
244 | currentIndex--; | ||
245 | result = true; | ||
246 | } | ||
247 | result = false; | ||
248 | listener.backtrackWorked(System.nanoTime() - start); | ||
249 | return result; | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * Call this method to undo the transformation. | ||
254 | */ | ||
255 | public void undoTransformation() { | ||
256 | while (undoLastTransformation()) | ||
257 | ; | ||
258 | } | ||
259 | |||
260 | public List<Object> getActivationCodes() { | ||
261 | return activationCodes; | ||
262 | } | ||
263 | |||
264 | public List<BatchTransformationRule<?, ?>> getTransformationRules() { | ||
265 | return transformationRules; | ||
266 | } | ||
267 | |||
268 | public IStateCoderFactory getStateCoderFactory() { | ||
269 | return stateCoderFactory; | ||
270 | } | ||
271 | |||
272 | public ViatraQueryEngine getEngine() { | ||
273 | return engine; | ||
274 | } | ||
275 | |||
276 | public Notifier getModel() { | ||
277 | return model; | ||
278 | } | ||
279 | |||
280 | public IStateCoder getStateCoder() { | ||
281 | return stateCoder; | ||
282 | } | ||
283 | |||
284 | public int getCurrentIndex() { | ||
285 | return currentIndex; | ||
286 | } | ||
287 | |||
288 | public int getTrajectoryLength() { | ||
289 | return activationCodes.size(); | ||
290 | } | ||
291 | |||
292 | public Fitness getFitness() { | ||
293 | return fitness; | ||
294 | } | ||
295 | |||
296 | public void setFitness(Fitness fitness) { | ||
297 | this.fitness = fitness; | ||
298 | } | ||
299 | |||
300 | public String toPrettyString() { | ||
301 | StringBuilder sb = new StringBuilder(); | ||
302 | sb.append("Fitness: "); | ||
303 | sb.append(fitness.toString()); | ||
304 | sb.append(" | Trajectory ("); | ||
305 | sb.append(activationCodes.size()); | ||
306 | sb.append("): "); | ||
307 | for (Object object : activationCodes) { | ||
308 | sb.append(object.toString()); | ||
309 | sb.append(" | "); | ||
310 | } | ||
311 | return sb.toString(); | ||
312 | } | ||
313 | |||
314 | @Override | ||
315 | public int hashCode() { | ||
316 | return activationCodes.hashCode(); | ||
317 | } | ||
318 | |||
319 | @Override | ||
320 | public boolean equals(Object obj) { | ||
321 | if (this == obj) { | ||
322 | return true; | ||
323 | } | ||
324 | if (obj instanceof SolutionTrajectory) { | ||
325 | SolutionTrajectory that = (SolutionTrajectory) obj; | ||
326 | return activationCodes.equals(that.activationCodes); | ||
327 | } | ||
328 | return false; | ||
329 | } | ||
330 | |||
331 | public Solution getSolution() { | ||
332 | return solution; | ||
333 | } | ||
334 | |||
335 | public void setSolution(Solution solution) { | ||
336 | this.solution = solution; | ||
337 | } | ||
338 | } | ||
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 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java new file mode 100644 index 00000000..d3990c23 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java | |||
@@ -0,0 +1,213 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashMap; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.Map; | ||
15 | import java.util.Objects; | ||
16 | import java.util.Set; | ||
17 | |||
18 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
19 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
20 | import org.eclipse.viatra.transformation.evm.api.Activation; | ||
21 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
22 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
23 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictSet; | ||
24 | |||
25 | public class ActivationCodesConflictSet implements ChangeableConflictSet { | ||
26 | |||
27 | private static class ActivationCodesMultiBiMap { | ||
28 | public Map<Activation<?>, Object> activationsToCodes = new HashMap<>(); | ||
29 | public Map<Object, Set<Activation<?>>> codesToActivations = new HashMap<>(); | ||
30 | |||
31 | public void addActivation(Activation<?> activation, Object activationCode) { | ||
32 | activationsToCodes.put(activation, activationCode); | ||
33 | codesToActivations.computeIfAbsent(activationCode, k -> new HashSet<>()).add(activation); | ||
34 | } | ||
35 | |||
36 | public void removeActivaion(Activation<?> activation) { | ||
37 | Object activationCode = activationsToCodes.remove(activation); | ||
38 | Set<Activation<?>> activations = codesToActivations.get(activationCode); | ||
39 | if (activations != null) { | ||
40 | activations.remove(activation); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | public void clear() { | ||
45 | activationsToCodes.clear(); | ||
46 | codesToActivations.clear(); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | protected ActivationCodesMultiBiMap activationCodes; | ||
51 | protected IStateCoder stateCoder; | ||
52 | |||
53 | protected Set<Activation<?>> newActivations = new HashSet<>(); | ||
54 | protected Set<Activation<?>> removedActivations = new HashSet<>(); | ||
55 | // private Logger logger = Logger.getLogger(getClass()); | ||
56 | |||
57 | private boolean isIncremental = false; | ||
58 | private ConflictSet nextActivationsConflictSet; | ||
59 | |||
60 | public void setIncremental(boolean isIncremental) { | ||
61 | this.isIncremental = isIncremental; | ||
62 | } | ||
63 | |||
64 | public ActivationCodesConflictSet(ConflictSet nextActivationsConflictSet, IStateCoder stateCoder) { | ||
65 | Objects.requireNonNull(nextActivationsConflictSet); | ||
66 | this.nextActivationsConflictSet = nextActivationsConflictSet; | ||
67 | this.stateCoder = stateCoder; | ||
68 | activationCodes = new ActivationCodesMultiBiMap(); | ||
69 | } | ||
70 | |||
71 | private Object createActivationCode(Activation<?> activation) { | ||
72 | return stateCoder.createActivationCode((IPatternMatch) activation.getAtom()); | ||
73 | } | ||
74 | |||
75 | @Override | ||
76 | public boolean removeActivation(Activation<?> activation) { | ||
77 | if (isIncremental) { | ||
78 | //* | ||
79 | removedActivations.add(activation); | ||
80 | newActivations.remove(activation); | ||
81 | /*/ | ||
82 | if(!removedActivations.add(activation)) { | ||
83 | logger.debug("Abnormal: already marked to remove: " + activation); | ||
84 | } else { | ||
85 | logger.debug("marked to remove: " + activation); | ||
86 | } | ||
87 | if(newActivations.remove(activation)) { | ||
88 | logger.debug("Abnormal: removed from new activations: " + activation); | ||
89 | } | ||
90 | //*/ | ||
91 | } | ||
92 | return false; | ||
93 | } | ||
94 | |||
95 | @Override | ||
96 | public boolean addActivation(Activation<?> activation) { | ||
97 | if (isIncremental) { | ||
98 | //* | ||
99 | newActivations.add(activation); | ||
100 | removedActivations.remove(activation); | ||
101 | /*/ | ||
102 | if (activation.isEnabled()) { | ||
103 | if (!newActivations.add(activation)) { | ||
104 | logger.debug("Abnormal: already added as new: " + activation); | ||
105 | } else { | ||
106 | logger.debug("activation added: " + activation); | ||
107 | } | ||
108 | } | ||
109 | if(removedActivations.remove(activation)) { | ||
110 | logger.debug("Abnormal: was already marked to remove: " + activation); | ||
111 | } | ||
112 | //*/ | ||
113 | } | ||
114 | return false; | ||
115 | } | ||
116 | |||
117 | public Object getActivationId(Activation<?> activation) { | ||
118 | return activationCodes.activationsToCodes.get(activation); | ||
119 | } | ||
120 | |||
121 | public Activation<?> getActivation(Object activationId) { | ||
122 | Set<Activation<?>> activationsSet = activationCodes.codesToActivations.get(activationId); | ||
123 | if (activationsSet == null || activationsSet.isEmpty()) { | ||
124 | return null; | ||
125 | } else { | ||
126 | return activationsSet.iterator().next(); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | public void updateActivationCodes() { | ||
131 | // logger.debug("Updating activation codes."); | ||
132 | |||
133 | if (isIncremental) { | ||
134 | for (Activation<?> activation : removedActivations) { | ||
135 | activationCodes.removeActivaion(activation); | ||
136 | // logger.debug("removed activation: " + activationId); | ||
137 | } | ||
138 | |||
139 | for (Activation<?> activation : newActivations) { | ||
140 | if (activation.getState().isInactive()) { | ||
141 | continue; | ||
142 | } | ||
143 | Object activationCode = createActivationCode(activation); | ||
144 | activationCodes.addActivation(activation, activationCode); | ||
145 | // logger.debug("new activation: " + activationId); | ||
146 | // Activation<?> similarActivation = activationIds.inverse().get(activationId); | ||
147 | // if (similarActivation != null) { | ||
148 | // logger.debug("Activation " + toStringAct(activation) + " is already present with id: " + activationId); | ||
149 | // if (similarActivation.isEnabled()) { | ||
150 | // logger.warn("Duplicate activation code: " + activationId); | ||
151 | // } else { | ||
152 | // logger.debug("Force put: " + activationId); | ||
153 | // } | ||
154 | // continue; | ||
155 | // } | ||
156 | // activationIds.put(activation, activationId); | ||
157 | } | ||
158 | removedActivations.clear(); | ||
159 | newActivations.clear(); | ||
160 | } else { | ||
161 | activationCodes.clear(); | ||
162 | for (Activation<?> activation : nextActivationsConflictSet.getNextActivations()) { | ||
163 | Object activationCode = createActivationCode(activation); | ||
164 | activationCodes.addActivation(activation, activationCode); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | |||
169 | } | ||
170 | |||
171 | protected void reinitWithActivations(ConflictSet nextActivationsConflictSet) { | ||
172 | this.nextActivationsConflictSet = nextActivationsConflictSet; | ||
173 | activationCodes.clear(); | ||
174 | for (Activation<?> activation : nextActivationsConflictSet.getNextActivations()) { | ||
175 | Object activationCode = createActivationCode(activation); | ||
176 | activationCodes.addActivation(activation, activationCode); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | @Override | ||
181 | public Activation<?> getNextActivation() { | ||
182 | throw new UnsupportedOperationException(); | ||
183 | } | ||
184 | |||
185 | @Override | ||
186 | public Set<Activation<?>> getNextActivations() { | ||
187 | throw new UnsupportedOperationException(); | ||
188 | } | ||
189 | |||
190 | @Override | ||
191 | public Set<Activation<?>> getConflictingActivations() { | ||
192 | throw new UnsupportedOperationException(); | ||
193 | } | ||
194 | |||
195 | @Override | ||
196 | public ConflictResolver getConflictResolver() { | ||
197 | throw new UnsupportedOperationException(); | ||
198 | } | ||
199 | |||
200 | @Override | ||
201 | public String toString() { | ||
202 | StringBuilder sb = new StringBuilder(); | ||
203 | for (Object activationCode : activationCodes.activationsToCodes.values()) { | ||
204 | sb.append(activationCode); | ||
205 | sb.append(" | "); | ||
206 | } | ||
207 | return sb.toString(); | ||
208 | } | ||
209 | |||
210 | public Collection<Object> getCurrentActivationCodes() { | ||
211 | return activationCodes.activationsToCodes.values(); | ||
212 | } | ||
213 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java new file mode 100644 index 00000000..4c6b4097 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java | |||
@@ -0,0 +1,563 @@ | |||
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.base; | ||
10 | |||
11 | import java.lang.reflect.InvocationTargetException; | ||
12 | import java.util.ArrayList; | ||
13 | import java.util.Collection; | ||
14 | import java.util.HashMap; | ||
15 | import java.util.Iterator; | ||
16 | import java.util.List; | ||
17 | import java.util.Map; | ||
18 | import java.util.Random; | ||
19 | |||
20 | import org.apache.log4j.Logger; | ||
21 | import org.eclipse.emf.common.notify.Notifier; | ||
22 | import org.eclipse.emf.edit.command.ChangeCommand; | ||
23 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
24 | import org.eclipse.viatra.dse.api.DSEException; | ||
25 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
26 | import org.eclipse.viatra.dse.designspace.api.IBacktrackListener; | ||
27 | import org.eclipse.viatra.dse.designspace.api.IDesignSpace; | ||
28 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
29 | import org.eclipse.viatra.dse.objectives.ActivationFitnessProcessor; | ||
30 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
31 | import org.eclipse.viatra.dse.visualizer.IExploreEventHandler; | ||
32 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
33 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
34 | import org.eclipse.viatra.transformation.evm.api.Activation; | ||
35 | import org.eclipse.viatra.transformation.evm.api.Context; | ||
36 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
37 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
38 | |||
39 | public class DesignSpaceManager implements IBacktrackListener { | ||
40 | |||
41 | private final IStateCoder stateCoder; | ||
42 | private final EditingDomain domain; | ||
43 | private Notifier model; | ||
44 | |||
45 | private IDesignSpace designSpace; | ||
46 | |||
47 | private final TrajectoryInfo trajectory; | ||
48 | |||
49 | // the occurence vector callback | ||
50 | private List<IExploreEventHandler> handlers; | ||
51 | |||
52 | // Dummy context for evm | ||
53 | private final Context evmContext = Context.create(); | ||
54 | |||
55 | private Logger logger = Logger.getLogger(this.getClass()); | ||
56 | |||
57 | private boolean isNewState = false; | ||
58 | private Map<BatchTransformationRule<?, ?>, ActivationFitnessProcessor> activationFitnessProcessors; | ||
59 | private Map<BatchTransformationRule<?, ?>, String> activationFitnessProcessorNames; | ||
60 | private ThreadContext context; | ||
61 | |||
62 | private ActivationCodesConflictSet activationCodes; | ||
63 | private ChangeableConflictSet conflictSet; | ||
64 | |||
65 | private AdvancedViatraQueryEngine engine; | ||
66 | |||
67 | private Random random = new Random(); | ||
68 | |||
69 | private long forwardTime = 0; | ||
70 | private long backtrackingTime = 0; | ||
71 | |||
72 | public DesignSpaceManager(ThreadContext context) { | ||
73 | |||
74 | this.context = context; | ||
75 | model = context.getModel(); | ||
76 | designSpace = context.getGlobalContext().getDesignSpace(); | ||
77 | domain = context.getEditingDomain(); | ||
78 | |||
79 | conflictSet = context.getConflictResolver().getLastCreatedConflictSet(); | ||
80 | |||
81 | stateCoder = context.getStateCoder(); | ||
82 | Object initialStateId = stateCoder.createStateCode(); | ||
83 | designSpace.addState(null, null, initialStateId); | ||
84 | |||
85 | activationCodes = context.getActivationCodesConflictSet(); | ||
86 | |||
87 | engine = (AdvancedViatraQueryEngine) context.getQueryEngine(); | ||
88 | |||
89 | this.trajectory = new TrajectoryInfo(initialStateId); | ||
90 | |||
91 | logger.debug("DesignSpaceManager initialized with initial model: " + initialStateId); | ||
92 | } | ||
93 | |||
94 | public void fireActivation(final Object transition) { | ||
95 | if (fireActivationSilent(transition)) { | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | StringBuilder sb = new StringBuilder(); | ||
100 | sb.append( | ||
101 | "A retrieved Transition SHOULD have a matching Activation. Possible causes: the state serializer is faulty; the algorithm choosed a wrong Transition."); | ||
102 | sb.append("\nSought transition: "); | ||
103 | sb.append(transition); | ||
104 | Object currentStateId = getCurrentState(); | ||
105 | sb.append("\nCurrent known state: "); | ||
106 | sb.append(currentStateId); | ||
107 | Object actualStateId = stateCoder.createStateCode(); | ||
108 | sb.append("\nActual state: "); | ||
109 | sb.append((actualStateId.equals(currentStateId) ? "same as current" : actualStateId)); | ||
110 | sb.append("\n"); | ||
111 | sb.append(trajectory); | ||
112 | sb.append("\nAvailable transitions:"); | ||
113 | for (Activation<?> act : conflictSet.getNextActivations()) { | ||
114 | IPatternMatch match = (IPatternMatch) act.getAtom(); | ||
115 | Object code = generateMatchCode(match); | ||
116 | sb.append("\n\t"); | ||
117 | sb.append(code); | ||
118 | } | ||
119 | |||
120 | throw new DSEException(sb.toString()); | ||
121 | } | ||
122 | |||
123 | public boolean tryFireActivation(final Object transition) { | ||
124 | return fireActivationSilent(transition); | ||
125 | } | ||
126 | |||
127 | private boolean fireActivationSilent(final Object transition) { | ||
128 | final Activation<?> activation = getActivationById(transition); | ||
129 | |||
130 | if (activation == null) { | ||
131 | return false; | ||
132 | } | ||
133 | |||
134 | BatchTransformationRule<?, ?> rule = getRuleByActivation(activation); | ||
135 | |||
136 | Map<String, Double> measureCosts = new HashMap<String, Double>(); | ||
137 | if (activationFitnessProcessors != null && activationFitnessProcessors.containsKey(rule)) { | ||
138 | IPatternMatch match = (IPatternMatch) activation.getAtom(); | ||
139 | ActivationFitnessProcessor processor = activationFitnessProcessors.get(rule); | ||
140 | double fitness = processor.process(match); | ||
141 | measureCosts.put(activationFitnessProcessorNames.get(rule), fitness); | ||
142 | } | ||
143 | |||
144 | ChangeCommand rc = new ChangeCommand(model) { | ||
145 | @Override | ||
146 | protected void doExecute() { | ||
147 | activation.fire(evmContext); | ||
148 | } | ||
149 | }; | ||
150 | |||
151 | Object previousState = trajectory.getCurrentStateId(); | ||
152 | |||
153 | long start = System.nanoTime(); | ||
154 | domain.getCommandStack().execute(rc); | ||
155 | forwardTime += System.nanoTime() - start; | ||
156 | |||
157 | Object newStateId = stateCoder.createStateCode(); | ||
158 | updateActivationCodes(); | ||
159 | |||
160 | if (designSpace != null) { | ||
161 | isNewState = !designSpace.isTraversed(newStateId); | ||
162 | designSpace.addState(previousState, transition, newStateId); | ||
163 | } | ||
164 | |||
165 | trajectory.addStep(transition, rule, newStateId, measureCosts); | ||
166 | |||
167 | if (handlers != null) { | ||
168 | for (IExploreEventHandler iExploreEventHandler : handlers) { | ||
169 | iExploreEventHandler.transitionFired(transition); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | logger.debug("Executed activation: " + transition);/* | ||
174 | * + " from state: " + previousState + " to " + newStateId); | ||
175 | */ | ||
176 | |||
177 | return true; | ||
178 | } | ||
179 | |||
180 | public boolean executeRandomActivationId() { | ||
181 | Collection<Object> transitions = getTransitionsFromCurrentState(); | ||
182 | int size = transitions.size(); | ||
183 | if (size == 0) { | ||
184 | return false; | ||
185 | } | ||
186 | |||
187 | int index = random.nextInt(size); | ||
188 | Iterator<Object> iterator = transitions.iterator(); | ||
189 | for (int i = 0; i < index; ++i) { | ||
190 | iterator.next(); | ||
191 | } | ||
192 | Object transition = iterator.next(); | ||
193 | |||
194 | fireActivation(transition); | ||
195 | return true; | ||
196 | } | ||
197 | |||
198 | public int executeTrajectory(Object[] trajectoryToExecute) { | ||
199 | return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, false, true); | ||
200 | } | ||
201 | |||
202 | public int executeTrajectory(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex) { | ||
203 | return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, false, true); | ||
204 | } | ||
205 | |||
206 | public int executeTrajectoryByTrying(Object[] trajectoryToExecute) { | ||
207 | return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, true, true); | ||
208 | } | ||
209 | |||
210 | public int executeTrajectoryByTrying(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex) { | ||
211 | return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, true, true); | ||
212 | } | ||
213 | |||
214 | public int executeTrajectoryWithoutStateCoding(Object[] trajectoryToExecute) { | ||
215 | return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, false, false); | ||
216 | } | ||
217 | |||
218 | public int executeTrajectoryWithoutStateCoding(Object[] trajectoryToExecute, int fromIncludedIndex, | ||
219 | int toExcludedIndex) { | ||
220 | return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, false, false); | ||
221 | } | ||
222 | |||
223 | public int executeTrajectoryByTryingWithoutStateCoding(Object[] trajectoryToExecute) { | ||
224 | return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, true, false); | ||
225 | } | ||
226 | |||
227 | public int executeTrajectoryByTryingWithoutStateCoding(Object[] trajectoryToExecute, int fromIncludedIndex, | ||
228 | int toExcludedIndex) { | ||
229 | return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, true, false); | ||
230 | } | ||
231 | |||
232 | private int executeTrajectory(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex, | ||
233 | boolean tryAllActivations, boolean createStateCode) { | ||
234 | logger.debug("Executing trajectory."); | ||
235 | int unsuccesfulIndex = -1; | ||
236 | if (tryAllActivations) { | ||
237 | unsuccesfulIndex = 0; | ||
238 | } | ||
239 | for (int i = fromIncludedIndex; i < toExcludedIndex; i++) { | ||
240 | Object activationId = trajectoryToExecute[i]; | ||
241 | final Activation<?> activation = getActivationById(activationId); | ||
242 | |||
243 | if (activation == null) { | ||
244 | logger.debug("Couldn't execute activation: " + activationId); | ||
245 | if (tryAllActivations) { | ||
246 | unsuccesfulIndex++; | ||
247 | continue; | ||
248 | } else { | ||
249 | unsuccesfulIndex = i; | ||
250 | logger.debug("Trajectory execution stopped at index " + i + "/" + trajectoryToExecute.length); | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | BatchTransformationRule<?, ?> rule = getRuleByActivation(activation); | ||
256 | |||
257 | Map<String, Double> measureCosts = new HashMap<String, Double>(); | ||
258 | if (activationFitnessProcessors != null && activationFitnessProcessors.containsKey(rule)) { | ||
259 | IPatternMatch match = (IPatternMatch) activation.getAtom(); | ||
260 | ActivationFitnessProcessor processor = activationFitnessProcessors.get(rule); | ||
261 | double fitness = processor.process(match); | ||
262 | measureCosts.put(activationFitnessProcessorNames.get(rule), fitness); | ||
263 | } | ||
264 | |||
265 | ChangeCommand rc = new ChangeCommand(model) { | ||
266 | @Override | ||
267 | protected void doExecute() { | ||
268 | activation.fire(evmContext); | ||
269 | } | ||
270 | }; | ||
271 | |||
272 | long start = System.nanoTime(); | ||
273 | domain.getCommandStack().execute(rc); | ||
274 | forwardTime += System.nanoTime() - start; | ||
275 | |||
276 | Object newStateId = null; | ||
277 | if (createStateCode) { | ||
278 | newStateId = stateCoder.createStateCode(); | ||
279 | } | ||
280 | updateActivationCodes(); | ||
281 | |||
282 | trajectory.addStep(activationId, rule, newStateId, measureCosts); | ||
283 | |||
284 | logger.debug("Activation executed: " + activationId); | ||
285 | } | ||
286 | if (!createStateCode) { | ||
287 | trajectory.modifyLastStateCode(stateCoder.createStateCode()); | ||
288 | } | ||
289 | logger.debug("Trajectory execution finished."); | ||
290 | return unsuccesfulIndex; | ||
291 | |||
292 | } | ||
293 | |||
294 | public Object getTransitionByActivation(Activation<?> activation) { | ||
295 | return activationCodes.getActivationId(activation); | ||
296 | } | ||
297 | |||
298 | public Activation<?> getActivationById(Object activationId) { | ||
299 | return activationCodes.getActivation(activationId); | ||
300 | } | ||
301 | |||
302 | public BatchTransformationRule<?, ?> getRuleByActivation(Activation<?> activation) { | ||
303 | return context.getGlobalContext().getSpecificationRuleMap().get(activation.getInstance().getSpecification()); | ||
304 | } | ||
305 | |||
306 | public BatchTransformationRule<?, ?> getRuleByActivationId(Object activationId) { | ||
307 | return getRuleByActivation(getActivationById(activationId)); | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * Returns true if the given state is not owned by this crawler. | ||
312 | * | ||
313 | **/ | ||
314 | public boolean isNewModelStateAlreadyTraversed() { | ||
315 | return !isNewState; | ||
316 | } | ||
317 | |||
318 | public List<Object> getTrajectoryFromRoot() { | ||
319 | return trajectory.getTrajectory(); | ||
320 | } | ||
321 | |||
322 | public Collection<Object> getTransitionsFromCurrentState() { | ||
323 | return activationCodes.getCurrentActivationCodes(); | ||
324 | } | ||
325 | |||
326 | public Collection<Object> getUntraversedTransitionsFromCurrentState() { | ||
327 | if (designSpace == null) { | ||
328 | throw new DSEException("Unsupported without a design space"); | ||
329 | } | ||
330 | Object currentState = trajectory.getCurrentStateId(); | ||
331 | Collection<Object> traversedIds = designSpace.getActivationIds(currentState); | ||
332 | |||
333 | List<Object> untraversedTransitions = new ArrayList<>(); | ||
334 | for (Object activationId : activationCodes.getCurrentActivationCodes()) { | ||
335 | if (!traversedIds.contains(activationId)) { | ||
336 | untraversedTransitions.add(activationId); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | return untraversedTransitions; | ||
341 | } | ||
342 | |||
343 | public boolean undoLastTransformation() { | ||
344 | |||
345 | if (!trajectory.canStepBack()) { | ||
346 | return false; | ||
347 | } | ||
348 | |||
349 | long start = System.nanoTime(); | ||
350 | try { | ||
351 | engine.delayUpdatePropagation(() -> { | ||
352 | domain.getCommandStack().undo(); | ||
353 | return null; | ||
354 | }); | ||
355 | } catch (InvocationTargetException e) { | ||
356 | throw new RuntimeException(e); | ||
357 | } | ||
358 | updateActivationCodes(); | ||
359 | |||
360 | Object lastActivationId = trajectory.getLastActivationId(); | ||
361 | |||
362 | trajectory.backtrack(); | ||
363 | |||
364 | if (handlers != null) { | ||
365 | for (IExploreEventHandler iExploreEventHandler : handlers) { | ||
366 | iExploreEventHandler.undo(lastActivationId); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | logger.debug("Backtrack."); | ||
371 | backtrackingTime += System.nanoTime() - start; | ||
372 | |||
373 | return true; | ||
374 | } | ||
375 | |||
376 | public void backtrackXTimes(int steps) { | ||
377 | long start = System.nanoTime(); | ||
378 | try { | ||
379 | engine.delayUpdatePropagation(() -> { | ||
380 | for (int i = steps; i > 0; i--) { | ||
381 | domain.getCommandStack().undo(); | ||
382 | trajectory.backtrack(); | ||
383 | } | ||
384 | return null; | ||
385 | }); | ||
386 | } catch (InvocationTargetException e) { | ||
387 | throw new RuntimeException(e); | ||
388 | } | ||
389 | backtrackingTime += System.nanoTime() - start; | ||
390 | updateActivationCodes(); | ||
391 | logger.debug("Backtracked " + steps + " times."); | ||
392 | } | ||
393 | |||
394 | public int backtrackUntilLastCommonActivation(Object[] newTrajectory) { | ||
395 | long start = System.nanoTime(); | ||
396 | Iterator<Object> currentTrajectoryIterator = trajectory.getTrajectory().iterator(); | ||
397 | if (!currentTrajectoryIterator.hasNext()) { | ||
398 | return 0; | ||
399 | } | ||
400 | int indexOfLastCommonActivation = 0; | ||
401 | for (Object activationCode : newTrajectory) { | ||
402 | if (currentTrajectoryIterator.hasNext()) { | ||
403 | Object activationCodeFromCurrent = currentTrajectoryIterator.next(); | ||
404 | if (activationCodeFromCurrent.equals(activationCode)) { | ||
405 | indexOfLastCommonActivation++; | ||
406 | } else { | ||
407 | break; | ||
408 | } | ||
409 | } else { | ||
410 | // current trajectory is smaller | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | int numberOfBacktracks = trajectory.getDepth() - indexOfLastCommonActivation; | ||
415 | if (numberOfBacktracks > 0) { | ||
416 | try { | ||
417 | engine.delayUpdatePropagation(() -> { | ||
418 | for (int i = numberOfBacktracks; i > 0; i--) { | ||
419 | domain.getCommandStack().undo(); | ||
420 | trajectory.backtrack(); | ||
421 | } | ||
422 | return null; | ||
423 | }); | ||
424 | } catch (InvocationTargetException e) { | ||
425 | throw new RuntimeException(e); | ||
426 | } | ||
427 | } | ||
428 | backtrackingTime += System.nanoTime() - start; | ||
429 | updateActivationCodes(); | ||
430 | logger.debug("Backtracked " + numberOfBacktracks + " times."); | ||
431 | return indexOfLastCommonActivation; | ||
432 | } | ||
433 | |||
434 | public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory) { | ||
435 | executeTrajectoryWithMinimalBacktrack(trajectory, trajectory.length); | ||
436 | } | ||
437 | |||
438 | public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex) { | ||
439 | int fromIndex = backtrackUntilLastCommonActivation(trajectory); | ||
440 | executeTrajectory(trajectory, fromIndex, toExcludedIndex, false, true); | ||
441 | } | ||
442 | |||
443 | public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory) { | ||
444 | executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory, trajectory.length); | ||
445 | } | ||
446 | |||
447 | public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex) { | ||
448 | int fromIndex = backtrackUntilLastCommonActivation(trajectory); | ||
449 | executeTrajectory(trajectory, fromIndex, toExcludedIndex, false, false); | ||
450 | Object stateCode = stateCoder.createStateCode(); | ||
451 | this.trajectory.modifyLastStateCode(stateCode); | ||
452 | } | ||
453 | |||
454 | public void undoUntilRoot() { | ||
455 | long start = System.nanoTime(); | ||
456 | try { | ||
457 | engine.delayUpdatePropagation(() -> { | ||
458 | while (trajectory.canStepBack()) { | ||
459 | domain.getCommandStack().undo(); | ||
460 | trajectory.backtrack(); | ||
461 | } | ||
462 | return null; | ||
463 | }); | ||
464 | } catch (InvocationTargetException e) { | ||
465 | throw new RuntimeException(e); | ||
466 | } | ||
467 | backtrackingTime += System.nanoTime() - start; | ||
468 | updateActivationCodes(); | ||
469 | logger.debug("Backtracked to root."); | ||
470 | } | ||
471 | |||
472 | private Object generateMatchCode(IPatternMatch match) { | ||
473 | return stateCoder.createActivationCode(match); | ||
474 | } | ||
475 | |||
476 | public Object getCurrentState() { | ||
477 | return trajectory.getCurrentStateId(); | ||
478 | } | ||
479 | |||
480 | public SolutionTrajectory createSolutionTrajectroy() { | ||
481 | return trajectory.createSolutionTrajectory(context.getGlobalContext().getStateCoderFactory(), this); | ||
482 | } | ||
483 | |||
484 | public TrajectoryInfo getTrajectoryInfo() { | ||
485 | return trajectory; | ||
486 | } | ||
487 | |||
488 | public void setDesignSpace(IDesignSpace designSpace) { | ||
489 | this.designSpace = designSpace; | ||
490 | } | ||
491 | |||
492 | public IDesignSpace getDesignSpace() { | ||
493 | return designSpace; | ||
494 | } | ||
495 | |||
496 | public void registerExploreEventHandler(IExploreEventHandler handler) { | ||
497 | if (handler == null) { | ||
498 | return; | ||
499 | } | ||
500 | if (handlers == null) { | ||
501 | handlers = new ArrayList<IExploreEventHandler>(); | ||
502 | } | ||
503 | handlers.add(handler); | ||
504 | } | ||
505 | |||
506 | public void deregisterExploreEventHandler(IExploreEventHandler handler) { | ||
507 | if (handler == null) { | ||
508 | return; | ||
509 | } | ||
510 | if (handlers != null) { | ||
511 | handlers.remove(handler); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | public void registerActivationCostProcessor(String name, BatchTransformationRule<?, ?> rule, | ||
516 | ActivationFitnessProcessor activationFitnessProcessor) { | ||
517 | if (activationFitnessProcessors == null || activationFitnessProcessorNames == null) { | ||
518 | activationFitnessProcessors = new HashMap<BatchTransformationRule<?, ?>, ActivationFitnessProcessor>(); | ||
519 | activationFitnessProcessorNames = new HashMap<BatchTransformationRule<?, ?>, String>(); | ||
520 | } | ||
521 | activationFitnessProcessors.put(rule, activationFitnessProcessor); | ||
522 | activationFitnessProcessorNames.put(rule, name); | ||
523 | } | ||
524 | |||
525 | public boolean isCurentStateInTrajectory() { | ||
526 | Object currentStateId = trajectory.getCurrentStateId(); | ||
527 | List<Object> stateTrajectory = trajectory.getStateTrajectory(); | ||
528 | int size = stateTrajectory.size(); | ||
529 | for (int i = 0; i < size - 1; i++) { | ||
530 | Object stateId = stateTrajectory.get(i); | ||
531 | if (currentStateId.equals(stateId)) { | ||
532 | return true; | ||
533 | } | ||
534 | } | ||
535 | return false; | ||
536 | } | ||
537 | |||
538 | public IStateCoder getStateCoder() { | ||
539 | return stateCoder; | ||
540 | } | ||
541 | |||
542 | private void updateActivationCodes() { | ||
543 | activationCodes.updateActivationCodes(); | ||
544 | } | ||
545 | |||
546 | public long getForwardTime() { | ||
547 | return forwardTime; | ||
548 | } | ||
549 | |||
550 | public long getBacktrackingTime() { | ||
551 | return backtrackingTime; | ||
552 | } | ||
553 | |||
554 | @Override | ||
555 | public void forwardWorked(long nanos) { | ||
556 | forwardTime += nanos; | ||
557 | } | ||
558 | |||
559 | @Override | ||
560 | public void backtrackWorked(long nanos) { | ||
561 | backtrackingTime += nanos; | ||
562 | } | ||
563 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java new file mode 100644 index 00000000..35504b56 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java | |||
@@ -0,0 +1,35 @@ | |||
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.base; | ||
10 | |||
11 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
12 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
13 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
14 | |||
15 | public class DseConflictResolver implements ConflictResolver { | ||
16 | |||
17 | private ConflictResolver activationOrderingconflictResolver; | ||
18 | private IStateCoder stateCoder; | ||
19 | private DseConflictSet lastCreatedConflictSet; | ||
20 | |||
21 | public DseConflictResolver(ConflictResolver activationOrderingConflictResolver, IStateCoder stateCoder) { | ||
22 | this.activationOrderingconflictResolver = activationOrderingConflictResolver; | ||
23 | this.stateCoder = stateCoder; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public ChangeableConflictSet createConflictSet() { | ||
28 | lastCreatedConflictSet = new DseConflictSet(this, activationOrderingconflictResolver, stateCoder); | ||
29 | return lastCreatedConflictSet; | ||
30 | } | ||
31 | |||
32 | public DseConflictSet getLastCreatedConflictSet() { | ||
33 | return lastCreatedConflictSet; | ||
34 | } | ||
35 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java new file mode 100644 index 00000000..cba595f4 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java | |||
@@ -0,0 +1,83 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.Set; | ||
12 | |||
13 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
14 | import org.eclipse.viatra.transformation.evm.api.Activation; | ||
15 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
16 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
17 | |||
18 | public class DseConflictSet implements ChangeableConflictSet { | ||
19 | |||
20 | private ActivationCodesConflictSet activationCodesConflictSet; | ||
21 | private ChangeableConflictSet activationOrderingConflictSet; | ||
22 | private ChangeableConflictSet prevActivationOrderingConflictSet; | ||
23 | private ConflictResolver resolver; | ||
24 | |||
25 | public DseConflictSet(ConflictResolver resolver, ConflictResolver activationOrderingConflictResolver, | ||
26 | IStateCoder stateCoder) { | ||
27 | this.resolver = resolver; | ||
28 | activationOrderingConflictSet = activationOrderingConflictResolver.createConflictSet(); | ||
29 | activationCodesConflictSet = new ActivationCodesConflictSet(activationOrderingConflictSet, stateCoder); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Activation<?> getNextActivation() { | ||
34 | return activationOrderingConflictSet.getNextActivation(); | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public Set<Activation<?>> getNextActivations() { | ||
39 | return activationOrderingConflictSet.getNextActivations(); | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public Set<Activation<?>> getConflictingActivations() { | ||
44 | return activationOrderingConflictSet.getConflictingActivations(); | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public ConflictResolver getConflictResolver() { | ||
49 | return resolver; | ||
50 | } | ||
51 | |||
52 | @Override | ||
53 | public boolean addActivation(Activation<?> activation) { | ||
54 | activationCodesConflictSet.addActivation(activation); | ||
55 | return activationOrderingConflictSet.addActivation(activation); | ||
56 | } | ||
57 | |||
58 | @Override | ||
59 | public boolean removeActivation(Activation<?> activation) { | ||
60 | activationCodesConflictSet.removeActivation(activation); | ||
61 | return activationOrderingConflictSet.removeActivation(activation); | ||
62 | } | ||
63 | |||
64 | public ActivationCodesConflictSet getActivationCodesConflictSet() { | ||
65 | return activationCodesConflictSet; | ||
66 | } | ||
67 | |||
68 | public void changeActivationOrderingConflictSet(ChangeableConflictSet newActivationOrderingConflictSet) { | ||
69 | for (Activation<?> activation : activationOrderingConflictSet.getConflictingActivations()) { | ||
70 | newActivationOrderingConflictSet.addActivation(activation); | ||
71 | } | ||
72 | activationCodesConflictSet.reinitWithActivations(newActivationOrderingConflictSet); | ||
73 | ChangeableConflictSet tmp = activationOrderingConflictSet; | ||
74 | activationOrderingConflictSet = newActivationOrderingConflictSet; | ||
75 | prevActivationOrderingConflictSet = tmp; | ||
76 | } | ||
77 | |||
78 | public void changeActivationOrderingConflictSetBack() { | ||
79 | ChangeableConflictSet newActivationOrderingConflictSet = | ||
80 | prevActivationOrderingConflictSet.getConflictResolver().createConflictSet(); | ||
81 | changeActivationOrderingConflictSet(newActivationOrderingConflictSet); | ||
82 | } | ||
83 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java new file mode 100644 index 00000000..838c1d1b --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java | |||
@@ -0,0 +1,21 @@ | |||
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.base; | ||
10 | |||
11 | import org.eclipse.viatra.transformation.evm.api.Agenda; | ||
12 | import org.eclipse.viatra.transformation.evm.api.RuleBase; | ||
13 | import org.eclipse.viatra.transformation.evm.api.event.EventRealm; | ||
14 | |||
15 | public class DseEvmRuleBase extends RuleBase { | ||
16 | |||
17 | public DseEvmRuleBase(EventRealm eventRealm, Agenda agenda) { | ||
18 | super(eventRealm, agenda); | ||
19 | } | ||
20 | |||
21 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java new file mode 100644 index 00000000..f6fee7be --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java | |||
@@ -0,0 +1,68 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashMap; | ||
13 | import java.util.concurrent.ConcurrentHashMap; | ||
14 | |||
15 | import org.eclipse.viatra.dse.api.DSEException; | ||
16 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
17 | |||
18 | public enum DseIdPoolHelper { | ||
19 | |||
20 | INSTANCE; | ||
21 | |||
22 | public static interface IGetRuleExecutions { | ||
23 | int getRuleExecutions(BatchTransformationRule<?, ?> rule); | ||
24 | } | ||
25 | |||
26 | public static class IdProvider { | ||
27 | |||
28 | private final BatchTransformationRule<?, ?> rule; | ||
29 | private IGetRuleExecutions getRuleExecutions; | ||
30 | |||
31 | public IdProvider(IGetRuleExecutions getRuleExecutions, BatchTransformationRule<?, ?> rule) { | ||
32 | this.getRuleExecutions = getRuleExecutions; | ||
33 | this.rule = rule; | ||
34 | } | ||
35 | |||
36 | public int getId() { | ||
37 | return getRuleExecutions.getRuleExecutions(rule); | ||
38 | } | ||
39 | |||
40 | } | ||
41 | |||
42 | private ConcurrentHashMap<Thread, HashMap<BatchTransformationRule<?, ?>, IdProvider>> idProviders = new ConcurrentHashMap<>(); | ||
43 | |||
44 | public int getId(BatchTransformationRule<?, ?> rule) { | ||
45 | Thread currentThread = Thread.currentThread(); | ||
46 | HashMap<BatchTransformationRule<?, ?>, IdProvider> ruleMap = idProviders.get(currentThread); | ||
47 | if (ruleMap == null) { | ||
48 | throw new DSEException("There is no registered id provider"); | ||
49 | } | ||
50 | IdProvider idProvider = ruleMap.get(rule); | ||
51 | return idProvider.getId(); | ||
52 | } | ||
53 | |||
54 | public void registerRules(IGetRuleExecutions getRuleExecutions, Collection<BatchTransformationRule<?, ?>> rules) { | ||
55 | Thread currentThread = Thread.currentThread(); | ||
56 | HashMap<BatchTransformationRule<?, ?>, IdProvider> ruleMap = new HashMap<>(); | ||
57 | for (BatchTransformationRule<?, ?> rule : rules) { | ||
58 | IdProvider idProvider = new IdProvider(getRuleExecutions, rule); | ||
59 | ruleMap.put(rule, idProvider); | ||
60 | } | ||
61 | idProviders.put(currentThread, ruleMap); | ||
62 | } | ||
63 | |||
64 | public void disposeByThread() { | ||
65 | Thread currentThread = Thread.currentThread(); | ||
66 | idProviders.remove(currentThread); | ||
67 | } | ||
68 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java new file mode 100644 index 00000000..f2231e5c --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java | |||
@@ -0,0 +1,88 @@ | |||
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.base; | ||
10 | |||
11 | import org.apache.log4j.Logger; | ||
12 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
13 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
14 | import org.eclipse.viatra.transformation.evm.api.RuleEngine; | ||
15 | |||
16 | /** | ||
17 | * This class implements the {@link Runnable} interface, to able to run an exploration strategy in a separate thread. It | ||
18 | * is also responsible to initialize the exploration, start the exploration (call the {@link IStrategy#explore()} | ||
19 | * method), catch any exception during exploration and to shutdown the thread correctly. | ||
20 | * | ||
21 | * @author Földenyi Miklos & Nagy Andras Szabolcs | ||
22 | * | ||
23 | */ | ||
24 | public class ExplorerThread implements Runnable { | ||
25 | |||
26 | private final ThreadContext threadContext; | ||
27 | |||
28 | private IStrategy strategy; | ||
29 | |||
30 | public ExplorerThread(final ThreadContext context) { | ||
31 | this.threadContext = context; | ||
32 | strategy = threadContext.getStrategy(); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * Signals the {@link IStrategy} instance that execution should be stopped. By contract, the strategy is to | ||
37 | * stop execution at the next stage of execution where stopping and exiting is appropriate. | ||
38 | */ | ||
39 | public void stopRunning() { | ||
40 | strategy.interruptStrategy(); | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Starts the design space exploration. Returns only when the {@link IStrategy#explore()} method returns. | ||
45 | */ | ||
46 | public void run() { | ||
47 | GlobalContext globalContext = threadContext.getGlobalContext(); | ||
48 | try { | ||
49 | |||
50 | threadContext.init(); | ||
51 | |||
52 | strategy.initStrategy(threadContext); | ||
53 | |||
54 | strategy.explore(); | ||
55 | |||
56 | threadContext.backtrackUntilRoot(); | ||
57 | |||
58 | } catch (Throwable e) { | ||
59 | Logger.getLogger(IStrategy.class).error("Thread stopped unexpectedly!", e); | ||
60 | globalContext.registerException(e); | ||
61 | } finally { | ||
62 | globalContext.strategyFinished(this); | ||
63 | dispose(); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * Disposes of this strategy. Recursively calls dispose on the underlying {@link RuleEngine} and | ||
69 | * {@link ViatraQueryEngine}. Calling this is only required if the design space exploration was launched in thread, as | ||
70 | * the underlying engines get collected on the stop of the running {@link Thread}. | ||
71 | */ | ||
72 | public void dispose() { | ||
73 | threadContext.getRuleEngine().dispose(); | ||
74 | DseIdPoolHelper.INSTANCE.disposeByThread(); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Returns the associated {@link ThreadContext} that houses all the thread specific data about the exploration | ||
79 | * process, and is also the gateway to the {@link GlobalContext} which stores data relevant to the design space | ||
80 | * exploration process as a whole. | ||
81 | * | ||
82 | * @return the relevant {@link ThreadContext}. | ||
83 | */ | ||
84 | public ThreadContext getThreadContext() { | ||
85 | return threadContext; | ||
86 | } | ||
87 | |||
88 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java new file mode 100644 index 00000000..7325ead3 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java | |||
@@ -0,0 +1,374 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.HashSet; | ||
15 | import java.util.List; | ||
16 | import java.util.Map; | ||
17 | import java.util.Set; | ||
18 | import java.util.concurrent.ConcurrentLinkedQueue; | ||
19 | import java.util.concurrent.atomic.AtomicBoolean; | ||
20 | |||
21 | import org.apache.log4j.Logger; | ||
22 | import org.eclipse.emf.common.notify.Notifier; | ||
23 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
24 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory; | ||
25 | import org.eclipse.viatra.dse.designspace.api.IDesignSpace; | ||
26 | import org.eclipse.viatra.dse.multithreading.DSEThreadPool; | ||
27 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint; | ||
28 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
29 | import org.eclipse.viatra.dse.objectives.LeveledObjectivesHelper; | ||
30 | import org.eclipse.viatra.dse.solutionstore.SolutionStore; | ||
31 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
32 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
33 | import org.eclipse.viatra.dse.visualizer.IDesignSpaceVisualizer; | ||
34 | import org.eclipse.viatra.transformation.evm.api.RuleSpecification; | ||
35 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
36 | import org.eclipse.viatra.transformation.evm.specific.ConflictResolvers; | ||
37 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
38 | |||
39 | import com.google.common.base.Preconditions; | ||
40 | import com.google.common.collect.ImmutableList; | ||
41 | |||
42 | /** | ||
43 | * Creates new contexts for strategies. It is needed because of the multithreading. | ||
44 | * | ||
45 | * @author Andras Szabolcs Nagy | ||
46 | * | ||
47 | */ | ||
48 | public class GlobalContext { | ||
49 | |||
50 | // **** fields and methods for multi threading *****// | ||
51 | // *************************************************// | ||
52 | |||
53 | public enum ExplorationProcessState { | ||
54 | NOT_STARTED, | ||
55 | RUNNING, | ||
56 | STOPPING, | ||
57 | COMPLETED | ||
58 | } | ||
59 | |||
60 | private ConcurrentLinkedQueue<Throwable> exceptions = new ConcurrentLinkedQueue<Throwable>(); | ||
61 | |||
62 | private volatile ExplorationProcessState state = ExplorationProcessState.NOT_STARTED; | ||
63 | private final Set<ExplorerThread> runningThreads = new HashSet<ExplorerThread>(); | ||
64 | private DSEThreadPool threadPool = new DSEThreadPool(); | ||
65 | private int numberOfStartedThreads = 0; | ||
66 | private IDesignSpace designSpace; | ||
67 | |||
68 | private AtomicBoolean firstThreadContextInited = new AtomicBoolean(false); | ||
69 | private AtomicBoolean firstThreadContextIniting = new AtomicBoolean(false); | ||
70 | |||
71 | private Map<RuleSpecification<?>, BatchTransformationRule<?,?>> specificationRuleMap; | ||
72 | |||
73 | private Object terminationSnycObject = new Object(); | ||
74 | |||
75 | private Logger logger = Logger.getLogger(IStrategy.class); | ||
76 | |||
77 | private boolean isAlreadyInited; | ||
78 | |||
79 | public void waitForTermination() { | ||
80 | synchronized (terminationSnycObject) { | ||
81 | while (!isDone()) { | ||
82 | try { | ||
83 | terminationSnycObject.wait(); | ||
84 | } catch (InterruptedException e) { | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * Starts a new thread to explore the design space. | ||
92 | * | ||
93 | * @param originalThreadContext The context of the thread which starts the new thread. | ||
94 | * @param model The model to start from. | ||
95 | * @param cloneModel It should be true in most cases. | ||
96 | * @param strategy The strategy, the thread will use. | ||
97 | * @return The {@link ExplorerThread} | ||
98 | */ | ||
99 | private synchronized ExplorerThread tryStartNewThread(ThreadContext originalThreadContext, Notifier model, | ||
100 | IStrategy strategy) { | ||
101 | |||
102 | if(!isAlreadyInited) { | ||
103 | isAlreadyInited = true; | ||
104 | init(); | ||
105 | } | ||
106 | |||
107 | if (state != ExplorationProcessState.COMPLETED && state != ExplorationProcessState.STOPPING | ||
108 | && threadPool.canStartNewThread()) { | ||
109 | |||
110 | ThreadContext newThreadContext = new ThreadContext(this, strategy, model); | ||
111 | |||
112 | // TODO : clone undo list? slave strategy can't go further back... | ||
113 | ExplorerThread explorerThread = new ExplorerThread(newThreadContext); | ||
114 | newThreadContext.setExplorerThread(explorerThread); | ||
115 | |||
116 | boolean isSuccessful = threadPool.tryStartNewStrategy(explorerThread); | ||
117 | |||
118 | if (isSuccessful) { | ||
119 | runningThreads.add(explorerThread); | ||
120 | |||
121 | state = ExplorationProcessState.RUNNING; | ||
122 | ++numberOfStartedThreads; | ||
123 | |||
124 | logger.info("New thread started, active threads: " + runningThreads.size()); | ||
125 | |||
126 | return explorerThread; | ||
127 | } | ||
128 | } | ||
129 | return null; | ||
130 | } | ||
131 | |||
132 | public synchronized ExplorerThread tryStartNewThread(ThreadContext originalThreadContext, IStrategy strategy) { | ||
133 | return tryStartNewThread(originalThreadContext, EMFHelper.clone(originalThreadContext.getModel()), strategy); | ||
134 | } | ||
135 | |||
136 | public synchronized ExplorerThread tryStartNewThreadWithoutModelClone(ThreadContext originalThreadContext, | ||
137 | IStrategy strategy) { | ||
138 | return tryStartNewThread(originalThreadContext, originalThreadContext.getModel(), strategy); | ||
139 | } | ||
140 | |||
141 | public synchronized ExplorerThread startFirstThread(IStrategy strategy, Notifier model) { | ||
142 | Preconditions.checkState(!isAlreadyInited, "First thread is already started."); | ||
143 | return tryStartNewThread(null, EMFHelper.clone(model), strategy); | ||
144 | } | ||
145 | |||
146 | public synchronized ExplorerThread startFirstThreadWithoutModelClone(IStrategy strategy, Notifier model) { | ||
147 | Preconditions.checkState(!isAlreadyInited, "First thread is already started."); | ||
148 | return tryStartNewThread(null, model, strategy); | ||
149 | } | ||
150 | |||
151 | public synchronized void startAllThreads(ThreadContext originalThreadContext, IStrategyFactory strategyFactory) { | ||
152 | while (canStartNewThread()) { | ||
153 | tryStartNewThread(originalThreadContext, strategyFactory.createStrategy()); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * Starts a new thread to explore the design space. | ||
159 | * | ||
160 | * @param strategyBase | ||
161 | * The {@link Strategy}. | ||
162 | * @param tedToClone | ||
163 | * The model to clone. Hint: context.getTed() | ||
164 | */ | ||
165 | |||
166 | public synchronized void strategyFinished(ExplorerThread strategy) { | ||
167 | runningThreads.remove(strategy); | ||
168 | |||
169 | logger.info("Thread finished, active threads: " + runningThreads.size()); | ||
170 | |||
171 | // is the first part necessary? | ||
172 | if (runningThreads.isEmpty()) { | ||
173 | state = ExplorationProcessState.COMPLETED; | ||
174 | threadPool.shutdown(); | ||
175 | |||
176 | // if the main thread (which started the exploration) | ||
177 | // is waiting for the solution, than wake it up | ||
178 | synchronized (terminationSnycObject) { | ||
179 | terminationSnycObject.notify(); | ||
180 | logger.info("Exploration terminated."); | ||
181 | } | ||
182 | |||
183 | } | ||
184 | } | ||
185 | |||
186 | public synchronized boolean isDone() { | ||
187 | return state == ExplorationProcessState.COMPLETED && runningThreads.isEmpty(); | ||
188 | } | ||
189 | |||
190 | public synchronized boolean isNotStarted() { | ||
191 | return state == ExplorationProcessState.NOT_STARTED; | ||
192 | } | ||
193 | |||
194 | public boolean canStartNewThread() { | ||
195 | return (state == ExplorationProcessState.NOT_STARTED || state == ExplorationProcessState.RUNNING) | ||
196 | && threadPool.canStartNewThread(); | ||
197 | } | ||
198 | |||
199 | public synchronized void stopAllThreads() { | ||
200 | if (state == ExplorationProcessState.RUNNING) { | ||
201 | state = ExplorationProcessState.STOPPING; | ||
202 | logger.info("Stopping all threads."); | ||
203 | for (ExplorerThread strategy : runningThreads) { | ||
204 | strategy.stopRunning(); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | public void registerException(Throwable e) { | ||
210 | exceptions.add(e); | ||
211 | } | ||
212 | |||
213 | // ******* fields and methods for exploration *******// | ||
214 | // **************************************************// | ||
215 | |||
216 | private List<IObjective> objectives = new ArrayList<IObjective>(); | ||
217 | private IObjective[][] leveledObjectives; | ||
218 | private List<IGlobalConstraint> globalConstraints = new ArrayList<IGlobalConstraint>(); | ||
219 | private Set<BatchTransformationRule<?, ?>> transformations = new HashSet<BatchTransformationRule<?, ?>>(); | ||
220 | private IStateCoderFactory stateCoderFactory; | ||
221 | private SolutionStore solutionStore = new SolutionStore(1); | ||
222 | private Object sharedObject; | ||
223 | private List<IDesignSpaceVisualizer> visualizers; | ||
224 | |||
225 | private ConflictResolver conflictResolver = ConflictResolvers.createArbitraryResolver(); | ||
226 | |||
227 | private void init() { | ||
228 | leveledObjectives = new LeveledObjectivesHelper(objectives).initLeveledObjectives(); | ||
229 | |||
230 | specificationRuleMap = new HashMap<>(); | ||
231 | for (BatchTransformationRule<?,?> rule : transformations) { | ||
232 | specificationRuleMap.put(rule.getRuleSpecification(), rule); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | public List<IDesignSpaceVisualizer> getVisualizers() { | ||
237 | return ImmutableList.copyOf(visualizers); | ||
238 | } | ||
239 | |||
240 | public void registerDesignSpaceVisualizer(IDesignSpaceVisualizer visualizer) { | ||
241 | if (visualizer == null) { | ||
242 | return; | ||
243 | } | ||
244 | if (visualizers == null) { | ||
245 | visualizers = new ArrayList<IDesignSpaceVisualizer>(); | ||
246 | } | ||
247 | visualizers.add(visualizer); | ||
248 | } | ||
249 | |||
250 | public void deregisterDesignSpaceVisualizer(IDesignSpaceVisualizer visualizer) { | ||
251 | if (visualizer == null) { | ||
252 | return; | ||
253 | } | ||
254 | if (visualizers != null) { | ||
255 | visualizers.remove(visualizer); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | public boolean isDesignSpaceVisualizerRegistered(IDesignSpaceVisualizer visualizer) { | ||
260 | if (visualizers != null) { | ||
261 | return visualizers.contains(visualizer); | ||
262 | } | ||
263 | return false; | ||
264 | } | ||
265 | |||
266 | public void initVisualizersForThread(ThreadContext threadContext) { | ||
267 | if (visualizers != null && !visualizers.isEmpty()) { | ||
268 | for (IDesignSpaceVisualizer visualizer : visualizers) { | ||
269 | visualizer.init(threadContext); | ||
270 | threadContext.getDesignSpaceManager().registerExploreEventHandler(visualizer); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | public boolean isExceptionHappendInOtherThread() { | ||
276 | return !exceptions.isEmpty(); | ||
277 | } | ||
278 | |||
279 | public Collection<Throwable> getExceptions() { | ||
280 | return exceptions; | ||
281 | } | ||
282 | |||
283 | public IStateCoderFactory getStateCoderFactory() { | ||
284 | return stateCoderFactory; | ||
285 | } | ||
286 | |||
287 | public void setStateCoderFactory(IStateCoderFactory stateCoderFactory) { | ||
288 | this.stateCoderFactory = stateCoderFactory; | ||
289 | } | ||
290 | |||
291 | public Set<BatchTransformationRule<?, ?>> getTransformations() { | ||
292 | return transformations; | ||
293 | } | ||
294 | |||
295 | public void setTransformations(Set<BatchTransformationRule<?, ?>> transformations) { | ||
296 | this.transformations = transformations; | ||
297 | } | ||
298 | |||
299 | public DSEThreadPool getThreadPool() { | ||
300 | return threadPool; | ||
301 | } | ||
302 | |||
303 | public IDesignSpace getDesignSpace() { | ||
304 | return designSpace; | ||
305 | } | ||
306 | |||
307 | public void setDesignSpace(IDesignSpace designSpace) { | ||
308 | this.designSpace = designSpace; | ||
309 | } | ||
310 | |||
311 | public int getNumberOfStartedThreads() { | ||
312 | return numberOfStartedThreads; | ||
313 | } | ||
314 | |||
315 | public Object getSharedObject() { | ||
316 | return sharedObject; | ||
317 | } | ||
318 | |||
319 | public void setSharedObject(Object sharedObject) { | ||
320 | this.sharedObject = sharedObject; | ||
321 | } | ||
322 | |||
323 | public ExplorationProcessState getState() { | ||
324 | return state; | ||
325 | } | ||
326 | |||
327 | public List<IObjective> getObjectives() { | ||
328 | return objectives; | ||
329 | } | ||
330 | |||
331 | public void setObjectives(List<IObjective> objectives) { | ||
332 | this.objectives = objectives; | ||
333 | } | ||
334 | |||
335 | public List<IGlobalConstraint> getGlobalConstraints() { | ||
336 | return globalConstraints; | ||
337 | } | ||
338 | |||
339 | public void setGlobalConstraints(List<IGlobalConstraint> globalConstraints) { | ||
340 | this.globalConstraints = globalConstraints; | ||
341 | } | ||
342 | |||
343 | AtomicBoolean getFirstThreadContextInited() { | ||
344 | return firstThreadContextInited; | ||
345 | } | ||
346 | |||
347 | AtomicBoolean getFirstThreadContextIniting() { | ||
348 | return firstThreadContextIniting; | ||
349 | } | ||
350 | |||
351 | public IObjective[][] getLeveledObjectives() { | ||
352 | return leveledObjectives; | ||
353 | } | ||
354 | |||
355 | public void setSolutionStore(SolutionStore solutionStore) { | ||
356 | this.solutionStore = solutionStore; | ||
357 | } | ||
358 | |||
359 | public SolutionStore getSolutionStore() { | ||
360 | return solutionStore; | ||
361 | } | ||
362 | |||
363 | public Map<RuleSpecification<?>, BatchTransformationRule<?, ?>> getSpecificationRuleMap() { | ||
364 | return specificationRuleMap; | ||
365 | } | ||
366 | |||
367 | public void setConflictResolver(ConflictResolver conflictResolver) { | ||
368 | this.conflictResolver = conflictResolver; | ||
369 | } | ||
370 | |||
371 | public ConflictResolver getConflictResolver() { | ||
372 | return conflictResolver; | ||
373 | } | ||
374 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java new file mode 100644 index 00000000..d630964f --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java | |||
@@ -0,0 +1,117 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.List; | ||
13 | import java.util.Set; | ||
14 | |||
15 | import org.eclipse.emf.common.notify.Notifier; | ||
16 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
17 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
18 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory; | ||
19 | import org.eclipse.viatra.dse.designspace.api.IDesignSpace; | ||
20 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
21 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
22 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint; | ||
23 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
24 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper; | ||
25 | import org.eclipse.viatra.dse.solutionstore.SolutionStore; | ||
26 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
27 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
28 | import org.eclipse.viatra.transformation.evm.api.Activation; | ||
29 | import org.eclipse.viatra.transformation.evm.api.RuleEngine; | ||
30 | import org.eclipse.viatra.transformation.evm.api.RuleSpecification; | ||
31 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
32 | |||
33 | /** | ||
34 | * This interface is only to overview the required methods for exploration strategies. It is not used explicitly. | ||
35 | * | ||
36 | * @author Andras Szabolcs Nagy | ||
37 | * | ||
38 | */ | ||
39 | public interface IDseStrategyContext { | ||
40 | |||
41 | void init(); | ||
42 | |||
43 | Notifier getModel(); | ||
44 | EditingDomain getEditingDomain(); | ||
45 | ViatraQueryEngine getQueryEngine(); | ||
46 | RuleEngine getRuleEngine(); | ||
47 | IStrategy getStrategy(); | ||
48 | ExplorerThread getExplorerThread(); | ||
49 | List<IObjective> getObjectives(); | ||
50 | IObjective[][] getLeveledObjectives(); | ||
51 | List<IGlobalConstraint> getGlobalConstraints(); | ||
52 | |||
53 | SolutionStore getSolutionStore(); | ||
54 | void newSolution(); | ||
55 | // TODO void newSolution(TrajectoryFitness trajectoryFitness); | ||
56 | |||
57 | |||
58 | ObjectiveComparatorHelper getObjectiveComparatorHelper(); | ||
59 | |||
60 | GlobalContext getGlobalContext(); | ||
61 | Set<BatchTransformationRule<?, ?>> getRules(); | ||
62 | BatchTransformationRule<?, ?> getRuleByRuleSpecification(RuleSpecification<?> ruleSpecification); | ||
63 | ExplorerThread tryStartNewThread(IStrategy strategy); /*IDseStrategyContext originalContext*/ | ||
64 | ExplorerThread tryStartNewThreadWithoutModelClone(IStrategy strategy); | ||
65 | void startAllThreads(IStrategyFactory strategyFactory); | ||
66 | Object getSharedObject(); | ||
67 | void setSharedObject(Object sharedObject); | ||
68 | |||
69 | |||
70 | DesignSpaceManager getDesignSpaceManager(); | ||
71 | IStateCoder getStateCoder(); | ||
72 | IDesignSpace getDesignSpace(); | ||
73 | TrajectoryInfo getTrajectoryInfo(); | ||
74 | List<Object> getTrajectory(); | ||
75 | List<Object> getTrajectoryCopied(); | ||
76 | int getDepth(); | ||
77 | Object getCurrentStateId(); | ||
78 | |||
79 | Object getTransitionByActivation(Activation<?> activation); | ||
80 | Activation<?> getActivationById(Object activationId); | ||
81 | BatchTransformationRule<?, ?> getRuleByActivation(Activation<?> activation); | ||
82 | BatchTransformationRule<?, ?> getRuleByActivationId(Object activationId); | ||
83 | |||
84 | Collection<Object> getCurrentActivationIds(); | ||
85 | Collection<Object> getUntraversedActivationIds(); | ||
86 | // TODO Object getArbitraryActivationId(); | ||
87 | // TODO Object getArbitraryUntraversedActivationId(); | ||
88 | |||
89 | void executeAcitvationId(Object activationId); | ||
90 | boolean tryExecuteAcitvationId(Object activationId); | ||
91 | boolean executeRandomActivationId(); | ||
92 | void executeTrajectory(Object[] activationIds); | ||
93 | void executeTrajectory(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex); | ||
94 | int executeTrajectoryByTrying(Object[] activationIds); | ||
95 | int executeTrajectoryByTrying(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex); | ||
96 | int executeTrajectoryWithoutStateCoding(Object[] activationIds); | ||
97 | int executeTrajectoryWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex); | ||
98 | int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds); | ||
99 | int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex); | ||
100 | void executeTrajectoryWithMinimalBacktrack(Object[] trajectory); | ||
101 | void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex); | ||
102 | void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory); | ||
103 | void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex); | ||
104 | |||
105 | boolean backtrack(); | ||
106 | // TODO int backtrack(int times); | ||
107 | void backtrackUntilLastCommonActivation(Object[] trajectory); | ||
108 | void backtrackUntilRoot(); | ||
109 | |||
110 | Fitness calculateFitness(); | ||
111 | Fitness getLastFitness(); | ||
112 | boolean checkGlobalConstraints(); | ||
113 | boolean isCurrentStateAlreadyTraversed(); | ||
114 | // this needs states stored: | ||
115 | boolean isCurrentStateInTrajectory(); | ||
116 | |||
117 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java new file mode 100644 index 00000000..8c0a715a --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java | |||
@@ -0,0 +1,53 @@ | |||
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.base; | ||
10 | |||
11 | import org.eclipse.viatra.transformation.evm.api.RuleEngine; | ||
12 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
13 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
14 | |||
15 | /** | ||
16 | * | ||
17 | * @author Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public class SingletonSetConflictResolver implements ConflictResolver { | ||
21 | |||
22 | protected ChangeableConflictSet conflictSet; | ||
23 | protected ConflictResolver conflictResolver; | ||
24 | protected ConflictResolver prevConflictResolver; | ||
25 | protected RuleEngine ruleEngine; | ||
26 | |||
27 | public SingletonSetConflictResolver(ConflictResolver conflictResolver) { | ||
28 | this.conflictResolver = conflictResolver; | ||
29 | conflictSet = conflictResolver.createConflictSet(); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public ChangeableConflictSet createConflictSet() { | ||
34 | return conflictSet; | ||
35 | } | ||
36 | |||
37 | public void changeConflictResolver(ConflictResolver conflictResolver) { | ||
38 | ConflictResolver tmp = this.conflictResolver; | ||
39 | this.conflictResolver = conflictResolver; | ||
40 | prevConflictResolver = tmp; | ||
41 | conflictSet = conflictResolver.createConflictSet(); | ||
42 | ruleEngine.setConflictResolver(this); | ||
43 | } | ||
44 | |||
45 | public void changeConflictResolverBack() { | ||
46 | changeConflictResolver(prevConflictResolver); | ||
47 | } | ||
48 | |||
49 | public void setRuleEngine(RuleEngine ruleEngine) { | ||
50 | this.ruleEngine = ruleEngine; | ||
51 | ruleEngine.setConflictResolver(this); | ||
52 | } | ||
53 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java new file mode 100644 index 00000000..b62442ce --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java | |||
@@ -0,0 +1,542 @@ | |||
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.base; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | import java.util.Set; | ||
15 | import java.util.concurrent.atomic.AtomicBoolean; | ||
16 | |||
17 | import org.apache.log4j.Logger; | ||
18 | import org.eclipse.emf.common.notify.Notifier; | ||
19 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
20 | import org.eclipse.viatra.dse.api.DSEException; | ||
21 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
22 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory; | ||
23 | import org.eclipse.viatra.dse.designspace.api.IDesignSpace; | ||
24 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
25 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
26 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint; | ||
27 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
28 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper; | ||
29 | import org.eclipse.viatra.dse.solutionstore.SolutionStore; | ||
30 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
31 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
32 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
33 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
34 | import org.eclipse.viatra.query.runtime.emf.EMFScope; | ||
35 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
36 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
37 | import org.eclipse.viatra.transformation.evm.api.Activation; | ||
38 | import org.eclipse.viatra.transformation.evm.api.RuleEngine; | ||
39 | import org.eclipse.viatra.transformation.evm.api.RuleSpecification; | ||
40 | import org.eclipse.viatra.transformation.evm.api.event.EventFilter; | ||
41 | import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet; | ||
42 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver; | ||
43 | import org.eclipse.viatra.transformation.evm.api.resolver.ConflictSet; | ||
44 | import org.eclipse.viatra.transformation.evm.specific.RuleEngines; | ||
45 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
46 | |||
47 | /** | ||
48 | * This class holds all the information that is related to a single processing thread of the DesignSpaceExploration | ||
49 | * process. For any attributes related to the Design Space Exploration process as a whole, see {@link GlobalContext}. | ||
50 | * | ||
51 | * @author Miklos Foldenyi | ||
52 | * | ||
53 | */ | ||
54 | public class ThreadContext implements IDseStrategyContext{ | ||
55 | |||
56 | private final GlobalContext globalContext; | ||
57 | private final IStrategy strategy; | ||
58 | private ExplorerThread explorerThread; | ||
59 | private RuleEngine ruleEngine; | ||
60 | private ViatraQueryEngine queryEngine; | ||
61 | private EditingDomain domain; | ||
62 | private Notifier model; | ||
63 | private DesignSpaceManager designSpaceManager; | ||
64 | private List<IObjective> objectives; | ||
65 | private List<IGlobalConstraint> globalConstraints; | ||
66 | private Fitness lastFitness; | ||
67 | private ObjectiveComparatorHelper objectiveComparatorHelper; | ||
68 | private IStateCoder stateCoder; | ||
69 | private DseConflictResolver dseConflictResolver; | ||
70 | private DseConflictSet dseConflictSet; | ||
71 | private ActivationCodesConflictSet activationCodesConflictSet; | ||
72 | |||
73 | /** | ||
74 | * This value is true after the {@link ThreadContext} has been initialized in it's own thread. | ||
75 | */ | ||
76 | private AtomicBoolean inited = new AtomicBoolean(false); | ||
77 | |||
78 | private boolean isFirstThread = false; | ||
79 | private IObjective[][] leveledObjectives; | ||
80 | |||
81 | private static class GetRuleExecutionsImpl implements DseIdPoolHelper.IGetRuleExecutions { | ||
82 | |||
83 | private List<BatchTransformationRule<?, ?>> executedRules; | ||
84 | |||
85 | public GetRuleExecutionsImpl(List<BatchTransformationRule<?, ?>> executedRulesView) { | ||
86 | this.executedRules = executedRulesView; | ||
87 | } | ||
88 | |||
89 | @Override | ||
90 | public int getRuleExecutions(BatchTransformationRule<?, ?> rule) { | ||
91 | int nextId = 0; | ||
92 | for (BatchTransformationRule<?, ?> r : executedRules) { | ||
93 | if (r.equals(rule)) { | ||
94 | nextId ++; | ||
95 | } | ||
96 | } | ||
97 | return nextId; | ||
98 | } | ||
99 | |||
100 | } | ||
101 | |||
102 | public DseConflictResolver getConflictResolver() { | ||
103 | return dseConflictResolver; | ||
104 | } | ||
105 | |||
106 | public ConflictSet getConflictSet() { | ||
107 | return dseConflictSet; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Creates a {@link ThreadContext} and sets it up to be initialized on the given {@link TransactionalEditingDomain} | ||
112 | * | ||
113 | * @param globalContext | ||
114 | * @param strategyBase | ||
115 | * @param domain | ||
116 | * @param trajectoryInfoToClone | ||
117 | * @param parentGuidance | ||
118 | */ | ||
119 | public ThreadContext(final GlobalContext globalContext, IStrategy strategy, Notifier model) { | ||
120 | Preconditions.checkArgument(model != null, "Cannot initialize ThreadContext on a null model."); | ||
121 | this.globalContext = globalContext; | ||
122 | this.strategy = strategy; | ||
123 | this.model = model; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Initializes the {@link ThreadContext} by initializing the underlying {@link ViatraQueryEngine} and | ||
128 | * {@link RuleEngine}. {@link Guidance} initialization is also happening within this method. | ||
129 | * | ||
130 | * @throws DSEException | ||
131 | */ | ||
132 | public void init() { | ||
133 | |||
134 | AtomicBoolean isFirst = globalContext.getFirstThreadContextIniting(); | ||
135 | AtomicBoolean isFirstReady = globalContext.getFirstThreadContextInited(); | ||
136 | if (!isFirstReady.get()) { | ||
137 | if (!isFirst.compareAndSet(false, true)) { | ||
138 | try { | ||
139 | do { | ||
140 | Thread.sleep(5); | ||
141 | } while (!isFirstReady.get()); | ||
142 | } catch (InterruptedException e) { | ||
143 | } | ||
144 | } else { | ||
145 | isFirstThread = true; | ||
146 | } | ||
147 | } | ||
148 | // prohibit re-initialization | ||
149 | Preconditions.checkArgument(!inited.getAndSet(true), "This Thread context has been initialized already!"); | ||
150 | |||
151 | try { | ||
152 | // initialize query engine | ||
153 | final EMFScope scope = new EMFScope(model); | ||
154 | queryEngine = ViatraQueryEngine.on(scope); | ||
155 | |||
156 | |||
157 | stateCoder = getGlobalContext().getStateCoderFactory().createStateCoder(); | ||
158 | stateCoder.init(model); | ||
159 | stateCoder.createStateCode(); | ||
160 | |||
161 | ConflictResolver activationOrderingCconflictResolver = globalContext.getConflictResolver(); | ||
162 | dseConflictResolver = new DseConflictResolver(activationOrderingCconflictResolver, stateCoder); | ||
163 | |||
164 | ruleEngine = RuleEngines.createViatraQueryRuleEngine(queryEngine); | ||
165 | ruleEngine.setConflictResolver(dseConflictResolver); | ||
166 | for (BatchTransformationRule<?, ?> tr : globalContext.getTransformations()) { | ||
167 | ruleEngine.addRule(tr.getRuleSpecification(), (EventFilter<IPatternMatch>) tr.getFilter()); | ||
168 | } | ||
169 | dseConflictSet = dseConflictResolver.getLastCreatedConflictSet(); | ||
170 | activationCodesConflictSet = dseConflictSet.getActivationCodesConflictSet(); | ||
171 | activationCodesConflictSet.updateActivationCodes(); | ||
172 | |||
173 | |||
174 | } catch (ViatraQueryException e) { | ||
175 | throw new DSEException("Failed to create unmanaged ViatraQueryEngine on the model.", e); | ||
176 | } | ||
177 | |||
178 | if (isFirstThread) { | ||
179 | |||
180 | objectives = globalContext.getObjectives(); | ||
181 | leveledObjectives = globalContext.getLeveledObjectives(); | ||
182 | globalConstraints = globalContext.getGlobalConstraints(); | ||
183 | |||
184 | } else { | ||
185 | objectives = new ArrayList<IObjective>(); | ||
186 | |||
187 | IObjective[][] leveledObjectivesToCopy = globalContext.getLeveledObjectives(); | ||
188 | leveledObjectives = new IObjective[leveledObjectivesToCopy.length][]; | ||
189 | for (int i = 0; i < leveledObjectivesToCopy.length; i++) { | ||
190 | leveledObjectives[i] = new IObjective[leveledObjectivesToCopy[i].length]; | ||
191 | for (int j = 0; j < leveledObjectivesToCopy[i].length; j++) { | ||
192 | leveledObjectives[i][j] = leveledObjectivesToCopy[i][j].createNew(); | ||
193 | objectives.add(leveledObjectives[i][j]); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | globalConstraints = new ArrayList<IGlobalConstraint>(); | ||
198 | for (IGlobalConstraint globalConstraint : globalContext.getGlobalConstraints()) { | ||
199 | globalConstraints.add(globalConstraint.createNew()); | ||
200 | } | ||
201 | |||
202 | } | ||
203 | // create the thread specific DesignSpaceManager | ||
204 | this.domain = EMFHelper.createEditingDomain(model); | ||
205 | designSpaceManager = new DesignSpaceManager(this); | ||
206 | |||
207 | boolean isThereHardObjective = false; | ||
208 | for (IObjective objective : objectives) { | ||
209 | objective.init(this); | ||
210 | if (objective.isHardObjective()) { | ||
211 | isThereHardObjective = true; | ||
212 | } | ||
213 | } | ||
214 | if (!isThereHardObjective) { | ||
215 | Logger.getLogger(IStrategy.class).warn( | ||
216 | "No hard objective is specified: all reachable state is a solution. Use a dummy hard objective to be explicit."); | ||
217 | } | ||
218 | |||
219 | for (IGlobalConstraint globalConstraint : globalConstraints) { | ||
220 | globalConstraint.init(this); | ||
221 | } | ||
222 | |||
223 | DseIdPoolHelper.INSTANCE.registerRules(new GetRuleExecutionsImpl(getDesignSpaceManager().getTrajectoryInfo().getRules()), getRules()); | ||
224 | |||
225 | globalContext.initVisualizersForThread(this); | ||
226 | |||
227 | if (isFirstThread) { | ||
228 | isFirstReady.set(true); | ||
229 | } | ||
230 | |||
231 | } | ||
232 | |||
233 | public Fitness calculateFitness() { | ||
234 | Fitness result = new Fitness(); | ||
235 | |||
236 | boolean satisifiesHardObjectives = true; | ||
237 | |||
238 | for (IObjective objective : objectives) { | ||
239 | Double fitness = objective.getFitness(this); | ||
240 | result.put(objective.getName(), fitness); | ||
241 | if (objective.isHardObjective() && !objective.satisifiesHardObjective(fitness)) { | ||
242 | satisifiesHardObjectives = false; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | result.setSatisifiesHardObjectives(satisifiesHardObjectives); | ||
247 | |||
248 | lastFitness = result; | ||
249 | |||
250 | return result; | ||
251 | } | ||
252 | |||
253 | public boolean checkGlobalConstraints() { | ||
254 | for (IGlobalConstraint globalConstraint : globalContext.getGlobalConstraints()) { | ||
255 | if (!globalConstraint.checkGlobalConstraint(this)) { | ||
256 | return false; | ||
257 | } | ||
258 | } | ||
259 | return true; | ||
260 | } | ||
261 | |||
262 | public RuleEngine getRuleEngine() { | ||
263 | return ruleEngine; | ||
264 | } | ||
265 | |||
266 | public GlobalContext getGlobalContext() { | ||
267 | return globalContext; | ||
268 | } | ||
269 | |||
270 | public DesignSpaceManager getDesignSpaceManager() { | ||
271 | return designSpaceManager; | ||
272 | } | ||
273 | |||
274 | public EditingDomain getEditingDomain() { | ||
275 | return domain; | ||
276 | } | ||
277 | |||
278 | public Notifier getModel() { | ||
279 | return model; | ||
280 | } | ||
281 | |||
282 | public ViatraQueryEngine getQueryEngine() { | ||
283 | return queryEngine; | ||
284 | } | ||
285 | |||
286 | public IStrategy getStrategy() { | ||
287 | return strategy; | ||
288 | } | ||
289 | |||
290 | public ExplorerThread getExplorerThread() { | ||
291 | return explorerThread; | ||
292 | } | ||
293 | |||
294 | public void setExplorerThread(ExplorerThread explorerThread) { | ||
295 | this.explorerThread = explorerThread; | ||
296 | } | ||
297 | |||
298 | public Fitness getLastFitness() { | ||
299 | return lastFitness; | ||
300 | } | ||
301 | |||
302 | public ObjectiveComparatorHelper getObjectiveComparatorHelper() { | ||
303 | if (objectiveComparatorHelper == null) { | ||
304 | objectiveComparatorHelper = new ObjectiveComparatorHelper(leveledObjectives); | ||
305 | } | ||
306 | return objectiveComparatorHelper; | ||
307 | } | ||
308 | |||
309 | public IObjective[][] getLeveledObjectives() { | ||
310 | return leveledObjectives; | ||
311 | } | ||
312 | |||
313 | public List<IObjective> getObjectives() { | ||
314 | return objectives; | ||
315 | } | ||
316 | |||
317 | public List<IGlobalConstraint> getGlobalConstraints() { | ||
318 | return globalConstraints; | ||
319 | } | ||
320 | |||
321 | @Override | ||
322 | public SolutionStore getSolutionStore() { | ||
323 | return globalContext.getSolutionStore(); | ||
324 | } | ||
325 | |||
326 | @Override | ||
327 | public void newSolution() { | ||
328 | globalContext.getSolutionStore().newSolution(this); | ||
329 | } | ||
330 | |||
331 | @Override | ||
332 | public Object getSharedObject() { | ||
333 | return globalContext.getSharedObject(); | ||
334 | } | ||
335 | |||
336 | @Override | ||
337 | public void setSharedObject(Object sharedObject) { | ||
338 | globalContext.setSharedObject(sharedObject); | ||
339 | } | ||
340 | |||
341 | @Override | ||
342 | public Set<BatchTransformationRule<?, ?>> getRules() { | ||
343 | return globalContext.getTransformations(); | ||
344 | } | ||
345 | |||
346 | @Override | ||
347 | public BatchTransformationRule<?, ?> getRuleByRuleSpecification(RuleSpecification<?> ruleSpecification) { | ||
348 | return globalContext.getSpecificationRuleMap().get(ruleSpecification); | ||
349 | } | ||
350 | |||
351 | @Override | ||
352 | public ExplorerThread tryStartNewThread(IStrategy strategy) { | ||
353 | return globalContext.tryStartNewThread(this, strategy); | ||
354 | } | ||
355 | |||
356 | @Override | ||
357 | public ExplorerThread tryStartNewThreadWithoutModelClone(IStrategy strategy) { | ||
358 | return globalContext.tryStartNewThreadWithoutModelClone(this, strategy); | ||
359 | } | ||
360 | |||
361 | @Override | ||
362 | public void startAllThreads(IStrategyFactory strategyFactory) { | ||
363 | globalContext.startAllThreads(this, strategyFactory); | ||
364 | } | ||
365 | |||
366 | @Override | ||
367 | public IStateCoder getStateCoder() { | ||
368 | return stateCoder; | ||
369 | } | ||
370 | |||
371 | @Override | ||
372 | public IDesignSpace getDesignSpace() { | ||
373 | return globalContext.getDesignSpace(); | ||
374 | } | ||
375 | |||
376 | @Override | ||
377 | public TrajectoryInfo getTrajectoryInfo() { | ||
378 | return designSpaceManager.getTrajectoryInfo(); | ||
379 | } | ||
380 | |||
381 | @Override | ||
382 | public List<Object> getTrajectory() { | ||
383 | return designSpaceManager.getTrajectoryInfo().getTrajectory(); | ||
384 | } | ||
385 | |||
386 | @Override | ||
387 | public List<Object> getTrajectoryCopied() { | ||
388 | return new ArrayList<Object>(getTrajectory()); | ||
389 | } | ||
390 | |||
391 | @Override | ||
392 | public int getDepth() { | ||
393 | return designSpaceManager.getTrajectoryInfo().getDepth(); | ||
394 | } | ||
395 | |||
396 | @Override | ||
397 | public Object getCurrentStateId() { | ||
398 | return designSpaceManager.getTrajectoryInfo().getCurrentStateId(); | ||
399 | } | ||
400 | |||
401 | @Override | ||
402 | public Object getTransitionByActivation(Activation<?> activation) { | ||
403 | return designSpaceManager.getTransitionByActivation(activation); | ||
404 | } | ||
405 | |||
406 | @Override | ||
407 | public Activation<?> getActivationById(Object activationId) { | ||
408 | return designSpaceManager.getActivationById(activationId); | ||
409 | } | ||
410 | |||
411 | @Override | ||
412 | public BatchTransformationRule<?, ?> getRuleByActivation(Activation<?> activation) { | ||
413 | return designSpaceManager.getRuleByActivation(activation); | ||
414 | } | ||
415 | |||
416 | @Override | ||
417 | public BatchTransformationRule<?, ?> getRuleByActivationId(Object activationId) { | ||
418 | return designSpaceManager.getRuleByActivationId(activationId); | ||
419 | } | ||
420 | |||
421 | @Override | ||
422 | public Collection<Object> getCurrentActivationIds() { | ||
423 | return designSpaceManager.getTransitionsFromCurrentState(); | ||
424 | } | ||
425 | |||
426 | @Override | ||
427 | public Collection<Object> getUntraversedActivationIds() { | ||
428 | return designSpaceManager.getUntraversedTransitionsFromCurrentState(); | ||
429 | } | ||
430 | |||
431 | @Override | ||
432 | public void executeAcitvationId(Object activationId) { | ||
433 | designSpaceManager.fireActivation(activationId); | ||
434 | } | ||
435 | |||
436 | @Override | ||
437 | public boolean tryExecuteAcitvationId(Object activationId) { | ||
438 | return designSpaceManager.tryFireActivation(activationId); | ||
439 | } | ||
440 | |||
441 | @Override | ||
442 | public boolean executeRandomActivationId() { | ||
443 | return designSpaceManager.executeRandomActivationId(); | ||
444 | } | ||
445 | |||
446 | @Override | ||
447 | public void executeTrajectory(Object[] activationIds) { | ||
448 | designSpaceManager.executeTrajectory(activationIds); | ||
449 | } | ||
450 | |||
451 | @Override | ||
452 | public void executeTrajectory(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) { | ||
453 | designSpaceManager.executeTrajectory(activationIds, fromIncludedIndex, toExcludedIndex); | ||
454 | } | ||
455 | |||
456 | @Override | ||
457 | public int executeTrajectoryByTrying(Object[] activationIds) { | ||
458 | return designSpaceManager.executeTrajectoryByTrying(activationIds); | ||
459 | } | ||
460 | |||
461 | @Override | ||
462 | public int executeTrajectoryByTrying(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) { | ||
463 | return designSpaceManager.executeTrajectoryByTrying(activationIds, fromIncludedIndex, toExcludedIndex); | ||
464 | } | ||
465 | |||
466 | @Override | ||
467 | public int executeTrajectoryWithoutStateCoding(Object[] activationIds) { | ||
468 | return designSpaceManager.executeTrajectoryWithoutStateCoding(activationIds); | ||
469 | } | ||
470 | |||
471 | @Override | ||
472 | public int executeTrajectoryWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) { | ||
473 | return designSpaceManager.executeTrajectoryWithoutStateCoding(activationIds, fromIncludedIndex, toExcludedIndex); | ||
474 | } | ||
475 | |||
476 | @Override | ||
477 | public int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds) { | ||
478 | return designSpaceManager.executeTrajectoryByTryingWithoutStateCoding(activationIds); | ||
479 | } | ||
480 | |||
481 | @Override | ||
482 | public int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) { | ||
483 | return designSpaceManager.executeTrajectoryByTryingWithoutStateCoding(activationIds, fromIncludedIndex, toExcludedIndex); | ||
484 | } | ||
485 | |||
486 | @Override | ||
487 | public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory) { | ||
488 | designSpaceManager.executeTrajectoryWithMinimalBacktrack(trajectory); | ||
489 | } | ||
490 | |||
491 | @Override | ||
492 | public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex) { | ||
493 | designSpaceManager.executeTrajectoryWithMinimalBacktrack(trajectory, toExcludedIndex); | ||
494 | } | ||
495 | |||
496 | @Override | ||
497 | public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory) { | ||
498 | designSpaceManager.executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory); | ||
499 | } | ||
500 | |||
501 | @Override | ||
502 | public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex) { | ||
503 | designSpaceManager.executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory, toExcludedIndex); | ||
504 | } | ||
505 | |||
506 | @Override | ||
507 | public boolean backtrack() { | ||
508 | return designSpaceManager.undoLastTransformation(); | ||
509 | } | ||
510 | |||
511 | @Override | ||
512 | public void backtrackUntilLastCommonActivation(Object[] trajectory) { | ||
513 | designSpaceManager.backtrackUntilLastCommonActivation(trajectory); | ||
514 | } | ||
515 | |||
516 | @Override | ||
517 | public void backtrackUntilRoot() { | ||
518 | designSpaceManager.undoUntilRoot(); | ||
519 | } | ||
520 | |||
521 | @Override | ||
522 | public boolean isCurrentStateAlreadyTraversed() { | ||
523 | return designSpaceManager.isNewModelStateAlreadyTraversed(); | ||
524 | } | ||
525 | |||
526 | @Override | ||
527 | public boolean isCurrentStateInTrajectory() { | ||
528 | return designSpaceManager.isCurentStateInTrajectory(); | ||
529 | } | ||
530 | |||
531 | public ActivationCodesConflictSet getActivationCodesConflictSet() { | ||
532 | return activationCodesConflictSet; | ||
533 | } | ||
534 | |||
535 | public void changeActivationOrdering(ChangeableConflictSet activationOrderingConflictSet) { | ||
536 | this.dseConflictSet.changeActivationOrderingConflictSet(activationOrderingConflictSet); | ||
537 | } | ||
538 | |||
539 | public void changeActivationOrderingBack() { | ||
540 | this.dseConflictSet.changeActivationOrderingConflictSetBack(); | ||
541 | } | ||
542 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java new file mode 100644 index 00000000..bc0f08d4 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java | |||
@@ -0,0 +1,106 @@ | |||
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.designspace.api; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.Collections; | ||
14 | import java.util.HashMap; | ||
15 | import java.util.HashSet; | ||
16 | import java.util.List; | ||
17 | import java.util.Map; | ||
18 | import java.util.Random; | ||
19 | import java.util.Set; | ||
20 | |||
21 | public class DesignSpace implements IDesignSpace { | ||
22 | |||
23 | Set<Object> statesView; | ||
24 | |||
25 | Set<Object> rootStates; | ||
26 | Set<Object> rootStatesView; | ||
27 | |||
28 | Map<Object, List<Object>> statesAndActivations; | ||
29 | |||
30 | Random random = new Random(); | ||
31 | |||
32 | public DesignSpace() { | ||
33 | rootStates = new HashSet<>(); | ||
34 | rootStatesView = Collections.unmodifiableSet(rootStates); | ||
35 | |||
36 | statesAndActivations = new HashMap<>(); | ||
37 | statesView = statesAndActivations.keySet(); | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public synchronized Collection<Object> getStates() { | ||
42 | return statesView; | ||
43 | } | ||
44 | |||
45 | @Override | ||
46 | public synchronized Collection<Object> getRoots() { | ||
47 | return rootStatesView; | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public synchronized void addState(Object sourceStateId, Object firedActivationId, Object newStateId) { | ||
52 | |||
53 | List<Object> activationIds = statesAndActivations.get(newStateId); | ||
54 | |||
55 | if (activationIds == null) { | ||
56 | activationIds = new ArrayList<Object>(); | ||
57 | statesAndActivations.put(newStateId, activationIds); | ||
58 | |||
59 | if (sourceStateId == null) { | ||
60 | rootStates.add(newStateId); | ||
61 | return; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | activationIds = statesAndActivations.get(sourceStateId); | ||
66 | |||
67 | if (activationIds == null) { | ||
68 | activationIds = new ArrayList<Object>(); | ||
69 | activationIds.add(firedActivationId); | ||
70 | statesAndActivations.put(sourceStateId, activationIds); | ||
71 | } else { | ||
72 | activationIds.add(firedActivationId); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public synchronized boolean isTraversed(Object stateId) { | ||
77 | return statesAndActivations.containsKey(stateId); | ||
78 | } | ||
79 | |||
80 | @Override | ||
81 | public synchronized Collection<Object> getActivationIds(Object stateId) { | ||
82 | return statesAndActivations.get(stateId); | ||
83 | } | ||
84 | |||
85 | @Override | ||
86 | public synchronized Object getRandomActivationId(Object stateId) { | ||
87 | List<Object> activations = statesAndActivations.get(stateId); | ||
88 | int index = random.nextInt(activations.size()); | ||
89 | return activations.get(index); | ||
90 | } | ||
91 | |||
92 | @Override | ||
93 | public synchronized long getNumberOfStates() { | ||
94 | return statesAndActivations.size(); | ||
95 | } | ||
96 | |||
97 | @Override | ||
98 | public synchronized long getNumberOfTransitions() { | ||
99 | int numberOfTransitions = 0; | ||
100 | for (List<Object> activations : statesAndActivations.values()) { | ||
101 | numberOfTransitions += activations.size(); | ||
102 | } | ||
103 | return numberOfTransitions; | ||
104 | } | ||
105 | |||
106 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java new file mode 100644 index 00000000..5c688276 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java | |||
@@ -0,0 +1,7 @@ | |||
1 | package org.eclipse.viatra.dse.designspace.api; | ||
2 | |||
3 | public interface IBacktrackListener { | ||
4 | void forwardWorked(long nanos); | ||
5 | |||
6 | void backtrackWorked(long nanos); | ||
7 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java new file mode 100644 index 00000000..a1d64bbf --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java | |||
@@ -0,0 +1,27 @@ | |||
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.designspace.api; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | |||
13 | public interface IDesignSpace { | ||
14 | |||
15 | Collection<Object> getStates(); | ||
16 | Collection<Object> getRoots(); | ||
17 | void addState(Object sourceStateId, Object firedActivationId, Object newStateId); | ||
18 | |||
19 | boolean isTraversed(Object stateId); | ||
20 | |||
21 | Collection<Object> getActivationIds(Object stateId); | ||
22 | Object getRandomActivationId(Object stateId); | ||
23 | |||
24 | long getNumberOfStates(); | ||
25 | long getNumberOfTransitions(); | ||
26 | |||
27 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java new file mode 100644 index 00000000..acd88416 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java | |||
@@ -0,0 +1,154 @@ | |||
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.designspace.api; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collections; | ||
13 | import java.util.List; | ||
14 | import java.util.Map; | ||
15 | import java.util.Objects; | ||
16 | |||
17 | import org.eclipse.viatra.dse.api.DSEException; | ||
18 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
19 | import org.eclipse.viatra.dse.base.DesignSpaceManager; | ||
20 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
21 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
22 | |||
23 | public class TrajectoryInfo { | ||
24 | |||
25 | private final List<Object> trajectory; | ||
26 | private final List<Object> trajectoryView; | ||
27 | private final List<BatchTransformationRule<?, ?>> rules; | ||
28 | private final List<BatchTransformationRule<?, ?>> rulesView; | ||
29 | private final List<Object> stateIds; | ||
30 | private final List<Object> stateIdsView; | ||
31 | private final List<Map<String, Double>> measuredCosts; | ||
32 | |||
33 | public TrajectoryInfo(Object initialStateId) { | ||
34 | Objects.requireNonNull(initialStateId); | ||
35 | |||
36 | stateIds = new ArrayList<>(); | ||
37 | stateIds.add(initialStateId); | ||
38 | |||
39 | trajectory = new ArrayList<>(); | ||
40 | rules = new ArrayList<>(); | ||
41 | measuredCosts = new ArrayList<>(); | ||
42 | |||
43 | trajectoryView = Collections.unmodifiableList(trajectory); | ||
44 | stateIdsView = Collections.unmodifiableList(stateIds); | ||
45 | rulesView = Collections.unmodifiableList(rules); | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * Copy constructor | ||
50 | * | ||
51 | * @since 0.17 | ||
52 | */ | ||
53 | public TrajectoryInfo(TrajectoryInfo other) { | ||
54 | this(other.stateIds, other.trajectory, other.rules, other.measuredCosts); | ||
55 | } | ||
56 | |||
57 | protected TrajectoryInfo(List<Object> stateIds, List<Object> trajectory, List<BatchTransformationRule<?, ?>> rules, List<Map<String, Double>> measuredCosts) { | ||
58 | |||
59 | this.stateIds = new ArrayList<>(stateIds); | ||
60 | this.trajectory = new ArrayList<>(trajectory); | ||
61 | this.rules = new ArrayList<>(rules); | ||
62 | trajectoryView = Collections.unmodifiableList(trajectory); | ||
63 | stateIdsView = Collections.unmodifiableList(stateIds); | ||
64 | rulesView = Collections.unmodifiableList(rules); | ||
65 | this.measuredCosts = new ArrayList<>(measuredCosts); | ||
66 | } | ||
67 | |||
68 | public void addStep(Object activationId, BatchTransformationRule<?, ?> rule, Object newStateId, Map<String, Double> measuredCosts) { | ||
69 | stateIds.add(newStateId); | ||
70 | trajectory.add(activationId); | ||
71 | rules.add(rule); | ||
72 | this.measuredCosts.add(measuredCosts); | ||
73 | } | ||
74 | |||
75 | public void backtrack() { | ||
76 | int size = trajectory.size(); | ||
77 | |||
78 | if (size == 0) { | ||
79 | throw new DSEException("Cannot step back any further!"); | ||
80 | } | ||
81 | |||
82 | trajectory.remove(size - 1); | ||
83 | rules.remove(size - 1); | ||
84 | stateIds.remove(size); | ||
85 | measuredCosts.remove(size - 1); | ||
86 | } | ||
87 | |||
88 | public Object getInitialStateId() { | ||
89 | return stateIds.get(0); | ||
90 | } | ||
91 | |||
92 | public Object getCurrentStateId() { | ||
93 | return stateIds.get(stateIds.size() - 1); | ||
94 | } | ||
95 | |||
96 | public Object getLastActivationId() { | ||
97 | return trajectory.get(trajectory.size() - 1); | ||
98 | } | ||
99 | |||
100 | public List<Object> getTrajectory() { | ||
101 | return trajectoryView; | ||
102 | } | ||
103 | |||
104 | public List<Object> getStateTrajectory() { | ||
105 | return stateIdsView; | ||
106 | } | ||
107 | |||
108 | public List<BatchTransformationRule<?, ?>> getRules() { | ||
109 | return rulesView; | ||
110 | } | ||
111 | |||
112 | public int getDepth() { | ||
113 | return trajectory.size(); | ||
114 | } | ||
115 | |||
116 | public List<Map<String, Double>> getMeasuredCosts() { | ||
117 | return measuredCosts; | ||
118 | } | ||
119 | |||
120 | public SolutionTrajectory createSolutionTrajectory(final IStateCoderFactory stateCoderFactory, final IBacktrackListener listener) { | ||
121 | |||
122 | List<Object> activationIds = new ArrayList<>(trajectory); | ||
123 | List<BatchTransformationRule<?, ?>> copiedRules = new ArrayList<>(rules); | ||
124 | |||
125 | return new SolutionTrajectory(activationIds, copiedRules, stateCoderFactory, listener); | ||
126 | } | ||
127 | |||
128 | public boolean canStepBack() { | ||
129 | return !trajectory.isEmpty(); | ||
130 | } | ||
131 | |||
132 | @Override | ||
133 | public String toString() { | ||
134 | StringBuilder sb = new StringBuilder("Trajectory:\n"); | ||
135 | for (Object activationId : trajectory) { | ||
136 | sb.append(activationId); | ||
137 | sb.append("\n"); | ||
138 | } | ||
139 | return sb.toString(); | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * This method is only used by the {@link DesignSpaceManager}. | ||
144 | * @param stateCode | ||
145 | * @return false if the initial state code is the last one, otherwise true. | ||
146 | */ | ||
147 | public boolean modifyLastStateCode(Object stateCode) { | ||
148 | if (stateIds.size() == 1) { | ||
149 | return false; | ||
150 | } | ||
151 | stateIds.set(stateIds.size() - 1, stateCode); | ||
152 | return true; | ||
153 | } | ||
154 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java new file mode 100644 index 00000000..17e96a75 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java | |||
@@ -0,0 +1,58 @@ | |||
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.multithreading; | ||
10 | |||
11 | import java.util.concurrent.RejectedExecutionException; | ||
12 | import java.util.concurrent.SynchronousQueue; | ||
13 | import java.util.concurrent.ThreadPoolExecutor; | ||
14 | import java.util.concurrent.TimeUnit; | ||
15 | |||
16 | import org.apache.log4j.Logger; | ||
17 | import org.eclipse.viatra.dse.api.DesignSpaceExplorer; | ||
18 | import org.eclipse.viatra.dse.base.ExplorerThread; | ||
19 | |||
20 | /** | ||
21 | * | ||
22 | * @author Andras Szabolcs Nagy | ||
23 | * | ||
24 | */ | ||
25 | public class DSEThreadPool extends ThreadPoolExecutor { | ||
26 | |||
27 | private static final long THREAD_KEEP_ALIVE_IN_SECONDS = 60; | ||
28 | |||
29 | public DSEThreadPool() { | ||
30 | // Based on the Executors.newCachedThreadPool() | ||
31 | super(0, getProcNumber(), THREAD_KEEP_ALIVE_IN_SECONDS, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); | ||
32 | } | ||
33 | |||
34 | // helper for constructor | ||
35 | private static int getProcNumber() { | ||
36 | return Runtime.getRuntime().availableProcessors(); | ||
37 | } | ||
38 | |||
39 | public boolean tryStartNewStrategy(ExplorerThread strategy) { | ||
40 | |||
41 | if (!canStartNewThread()) { | ||
42 | return false; | ||
43 | } | ||
44 | |||
45 | try { | ||
46 | submit(strategy); | ||
47 | } catch (RejectedExecutionException e) { | ||
48 | Logger.getLogger(DesignSpaceExplorer.class).info("Couldn't start new thread.", e); | ||
49 | return false; | ||
50 | } | ||
51 | |||
52 | return true; | ||
53 | } | ||
54 | |||
55 | public boolean canStartNewThread() { | ||
56 | return getMaximumPoolSize() > getActiveCount(); | ||
57 | } | ||
58 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java new file mode 100644 index 00000000..c06d2916 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives; | ||
10 | |||
11 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
12 | |||
13 | public interface ActivationFitnessProcessor { | ||
14 | public double process(IPatternMatch match); | ||
15 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java new file mode 100644 index 00000000..b1bd9349 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives; | ||
10 | |||
11 | import java.util.Comparator; | ||
12 | |||
13 | /** | ||
14 | * This helper class holds comparators for objective implementations. | ||
15 | * | ||
16 | * @author Andras Szabolcs Nagy | ||
17 | * | ||
18 | */ | ||
19 | public class Comparators { | ||
20 | |||
21 | private Comparators() { /*Utility class constructor*/ } | ||
22 | |||
23 | public static final Comparator<Double> HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2); | ||
24 | |||
25 | public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1); | ||
26 | |||
27 | private static final Double ZERO = Double.valueOf(0); | ||
28 | |||
29 | public static final Comparator<Double> DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2)); | ||
30 | |||
31 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java new file mode 100644 index 00000000..8beef3bd --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java | |||
@@ -0,0 +1,29 @@ | |||
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.objectives; | ||
10 | |||
11 | import java.util.HashMap; | ||
12 | |||
13 | public class Fitness extends HashMap<String, Double>{ | ||
14 | |||
15 | private boolean satisifiesHardObjectives; | ||
16 | |||
17 | public boolean isSatisifiesHardObjectives() { | ||
18 | return satisifiesHardObjectives; | ||
19 | } | ||
20 | |||
21 | public void setSatisifiesHardObjectives(boolean satisifiesHardObjectives) { | ||
22 | this.satisifiesHardObjectives = satisifiesHardObjectives; | ||
23 | } | ||
24 | |||
25 | @Override | ||
26 | public String toString() { | ||
27 | return super.toString() + " hardObjectives=" + satisifiesHardObjectives; | ||
28 | } | ||
29 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java new file mode 100644 index 00000000..2f7f0347 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java | |||
@@ -0,0 +1,58 @@ | |||
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.objectives; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | |||
13 | /** | ||
14 | * | ||
15 | * Implementation of this interface represents a global constraint of the DSE problem, which can halt an exploration | ||
16 | * continuing from a state which dissatisfies the global constraint. | ||
17 | * <p> | ||
18 | * Certain global constraints can have inner state for the validation. In this case a new instance is necessary for | ||
19 | * every new thread, and the {@code createNew} method should not return the same instance more than once. | ||
20 | * | ||
21 | * @author Andras Szabolcs Nagy | ||
22 | * | ||
23 | */ | ||
24 | public interface IGlobalConstraint { | ||
25 | |||
26 | /** | ||
27 | * Returns the name of the global constraint. | ||
28 | * | ||
29 | * @return The name of the global constraint. | ||
30 | */ | ||
31 | String getName(); | ||
32 | |||
33 | /** | ||
34 | * Checks whether the current state satisfies the global constraint. | ||
35 | * | ||
36 | * @param context | ||
37 | * The {@link ThreadContext} which contains the necessary information. | ||
38 | * @return True if the state is valid and exploration can be continued from the actual state. | ||
39 | */ | ||
40 | boolean checkGlobalConstraint(ThreadContext context); | ||
41 | |||
42 | /** | ||
43 | * Initializes the global constraint. It is called exactly once for every thread starts. | ||
44 | * | ||
45 | * @param context | ||
46 | * The {@link ThreadContext}. | ||
47 | */ | ||
48 | void init(ThreadContext context); | ||
49 | |||
50 | /** | ||
51 | * Returns an instance of the {@link IGlobalConstraint}. If it returns the same instance, all the methods has to be | ||
52 | * thread save as they are called concurrently. | ||
53 | * | ||
54 | * @return An instance of the global constraint. | ||
55 | */ | ||
56 | IGlobalConstraint createNew(); | ||
57 | |||
58 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java new file mode 100644 index 00000000..849dd4e8 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java | |||
@@ -0,0 +1,110 @@ | |||
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.objectives; | ||
10 | |||
11 | import java.util.Comparator; | ||
12 | |||
13 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
14 | |||
15 | /** | ||
16 | * | ||
17 | * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution | ||
18 | * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated | ||
19 | * value. | ||
20 | * <p> | ||
21 | * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard | ||
22 | * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution. | ||
23 | * <p> | ||
24 | * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary | ||
25 | * for every new thread, and the {@code createNew} method should not return the same instance more than once. | ||
26 | * | ||
27 | * @author Andras Szabolcs Nagy | ||
28 | * | ||
29 | */ | ||
30 | public interface IObjective { | ||
31 | |||
32 | /** | ||
33 | * Returns the name of the objective. | ||
34 | * | ||
35 | * @return The name of the objective. | ||
36 | */ | ||
37 | String getName(); | ||
38 | |||
39 | /** | ||
40 | * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to | ||
41 | * minimize or maximize (or minimize or maximize a delta from a given number). | ||
42 | * | ||
43 | * @param comparator The comparator. | ||
44 | */ | ||
45 | void setComparator(Comparator<Double> comparator); | ||
46 | |||
47 | /** | ||
48 | * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is | ||
49 | * to minimize or maximize (or minimize or maximize a delta from a given number). | ||
50 | * | ||
51 | * @return The comparator. | ||
52 | */ | ||
53 | Comparator<Double> getComparator(); | ||
54 | |||
55 | /** | ||
56 | * Calculates the value of the objective on a given solution (trajectory). | ||
57 | * | ||
58 | * @param context | ||
59 | * The {@link ThreadContext} | ||
60 | * @return The objective value in double. | ||
61 | */ | ||
62 | Double getFitness(ThreadContext context); | ||
63 | |||
64 | /** | ||
65 | * Initializes the objective. It is called exactly once for every thread starts. | ||
66 | * | ||
67 | * @param context | ||
68 | * The {@link ThreadContext}. | ||
69 | */ | ||
70 | void init(ThreadContext context); | ||
71 | |||
72 | /** | ||
73 | * Returns an instance of the {@link IObjective}. If it returns the same instance, all the methods has to be thread | ||
74 | * save as they are called concurrently. | ||
75 | * | ||
76 | * @return An instance of the objective. | ||
77 | */ | ||
78 | IObjective createNew(); | ||
79 | |||
80 | /** | ||
81 | * Returns true if the objective is a hard objective. In such a case the method | ||
82 | * {@link IObjective#satisifiesHardObjective(Double)} is called. | ||
83 | * | ||
84 | * @return True if the objective is a hard objective. | ||
85 | * @see IObjective#satisifiesHardObjective(Double) | ||
86 | * @see IObjective | ||
87 | */ | ||
88 | boolean isHardObjective(); | ||
89 | |||
90 | /** | ||
91 | * Determines if the given fitness value satisfies the hard objective. | ||
92 | * | ||
93 | * @param fitness | ||
94 | * The fitness value of a solution. | ||
95 | * @return True if it satisfies the hard objective or it is a soft constraint. | ||
96 | * @see IObjective | ||
97 | */ | ||
98 | boolean satisifiesHardObjective(Double fitness); | ||
99 | |||
100 | /** | ||
101 | * Set the level of the objective. | ||
102 | */ | ||
103 | void setLevel(int level); | ||
104 | |||
105 | /** | ||
106 | * Gets the level of the objective. | ||
107 | */ | ||
108 | int getLevel(); | ||
109 | |||
110 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java new file mode 100644 index 00000000..2d81629b --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java | |||
@@ -0,0 +1,114 @@ | |||
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.objectives; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Arrays; | ||
13 | import java.util.Comparator; | ||
14 | import java.util.List; | ||
15 | |||
16 | public class LeveledObjectivesHelper { | ||
17 | |||
18 | private List<IObjective> objectives = new ArrayList<IObjective>(); | ||
19 | private IObjective[][] leveledObjectives; | ||
20 | |||
21 | public LeveledObjectivesHelper(List<IObjective> objectives) { | ||
22 | this.objectives = objectives; | ||
23 | } | ||
24 | |||
25 | public IObjective[][] initLeveledObjectives() { | ||
26 | if (objectives.isEmpty()) { | ||
27 | leveledObjectives = new IObjective[0][0]; | ||
28 | return leveledObjectives; | ||
29 | } | ||
30 | |||
31 | int level = objectives.get(0).getLevel(); | ||
32 | boolean oneLevelOnly = true; | ||
33 | for (IObjective objective : objectives) { | ||
34 | if (objective.getLevel() != level) { | ||
35 | oneLevelOnly = false; | ||
36 | break; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | if (oneLevelOnly) { | ||
41 | leveledObjectives = new IObjective[1][objectives.size()]; | ||
42 | for (int i = 0; i < objectives.size(); i++) { | ||
43 | leveledObjectives[0][i] = objectives.get(i); | ||
44 | } | ||
45 | return leveledObjectives; | ||
46 | } | ||
47 | |||
48 | IObjective[] objectivesArray = getSortedByLevelObjectives(objectives); | ||
49 | |||
50 | int numberOfLevels = getNumberOfObjectiveLevels(objectivesArray); | ||
51 | |||
52 | leveledObjectives = new IObjective[numberOfLevels][]; | ||
53 | |||
54 | fillLeveledObjectives(objectivesArray); | ||
55 | |||
56 | return leveledObjectives; | ||
57 | } | ||
58 | |||
59 | private void fillLeveledObjectives(IObjective[] objectivesArray) { | ||
60 | int actLevel = objectivesArray[0].getLevel(); | ||
61 | int levelIndex = 0; | ||
62 | int lastIndex = 0; | ||
63 | int corrigationForLastLevel = 0; | ||
64 | boolean oneObjectiveAtLastLevel = false; | ||
65 | for (int i = 0; i < objectivesArray.length; i++) { | ||
66 | if (i == objectivesArray.length - 1) { | ||
67 | corrigationForLastLevel = 1; | ||
68 | if (objectivesArray[i - 1].getLevel() != objectivesArray[i].getLevel()) { | ||
69 | oneObjectiveAtLastLevel = true; | ||
70 | corrigationForLastLevel = 0; | ||
71 | } | ||
72 | } | ||
73 | if (objectivesArray[i].getLevel() != actLevel || corrigationForLastLevel == 1 || oneObjectiveAtLastLevel) { | ||
74 | leveledObjectives[levelIndex] = new IObjective[i - lastIndex + corrigationForLastLevel]; | ||
75 | for (int j = lastIndex; j < i + corrigationForLastLevel; j++) { | ||
76 | leveledObjectives[levelIndex][j - lastIndex] = objectivesArray[j]; | ||
77 | } | ||
78 | if (oneObjectiveAtLastLevel) { | ||
79 | leveledObjectives[levelIndex + 1] = new IObjective[1]; | ||
80 | leveledObjectives[levelIndex + 1][0] = objectivesArray[i]; | ||
81 | } | ||
82 | actLevel = objectivesArray[i].getLevel(); | ||
83 | levelIndex++; | ||
84 | lastIndex = i; | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | private int getNumberOfObjectiveLevels(IObjective[] objectivesArray) { | ||
90 | |||
91 | int actLevel = objectivesArray[0].getLevel(); | ||
92 | int numberOfLevels = 1; | ||
93 | |||
94 | for (int i = 1; i < objectivesArray.length; i++) { | ||
95 | if (objectivesArray[i].getLevel() != actLevel) { | ||
96 | numberOfLevels++; | ||
97 | actLevel = objectivesArray[i].getLevel(); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | return numberOfLevels; | ||
102 | } | ||
103 | |||
104 | private IObjective[] getSortedByLevelObjectives(List<IObjective> objectives) { | ||
105 | IObjective[] objectivesArray = objectives.toArray(new IObjective[objectives.size()]); | ||
106 | Arrays.sort(objectivesArray, Comparator.comparingInt(IObjective::getLevel)); | ||
107 | return objectivesArray; | ||
108 | } | ||
109 | |||
110 | public IObjective[][] getLeveledObjectives() { | ||
111 | return leveledObjectives; | ||
112 | } | ||
113 | |||
114 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java new file mode 100644 index 00000000..39139bb0 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java | |||
@@ -0,0 +1,217 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Arrays; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.List; | ||
15 | import java.util.Map; | ||
16 | import java.util.Random; | ||
17 | |||
18 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
19 | |||
20 | /** | ||
21 | * This class is responsible to compare and sort fitness values. {@link TrajectoryFitness} instances can be added to an | ||
22 | * instance of this class, that it can sort them. | ||
23 | * | ||
24 | * @author András Szabolcs Nagy | ||
25 | */ | ||
26 | public class ObjectiveComparatorHelper { | ||
27 | |||
28 | private IObjective[][] leveledObjectives; | ||
29 | private List<TrajectoryFitness> trajectoryFitnesses = new ArrayList<TrajectoryFitness>(); | ||
30 | private Random random = new Random(); | ||
31 | private boolean computeCrowdingDistance = false; | ||
32 | |||
33 | public ObjectiveComparatorHelper(IObjective[][] leveledObjectives) { | ||
34 | this.leveledObjectives = leveledObjectives; | ||
35 | } | ||
36 | |||
37 | public void setComputeCrowdingDistance(boolean computeCrowdingDistance) { | ||
38 | this.computeCrowdingDistance = computeCrowdingDistance; | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Compares two fitnesses based on hierarchical dominance. Returns -1 if the second parameter {@code o2} is a better | ||
43 | * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates | ||
44 | * {@code o2}) and returns 0 if they are non-dominating each other. | ||
45 | */ | ||
46 | public int compare(Fitness o1, Fitness o2) { | ||
47 | |||
48 | levelsLoop: for (int i = 0; i < leveledObjectives.length; i++) { | ||
49 | |||
50 | boolean o1HasBetterFitness = false; | ||
51 | boolean o2HasBetterFitness = false; | ||
52 | |||
53 | for (IObjective objective : leveledObjectives[i]) { | ||
54 | String objectiveName = objective.getName(); | ||
55 | int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); | ||
56 | |||
57 | if (sgn < 0) { | ||
58 | o2HasBetterFitness = true; | ||
59 | } | ||
60 | if (sgn > 0) { | ||
61 | o1HasBetterFitness = true; | ||
62 | } | ||
63 | if (o1HasBetterFitness && o2HasBetterFitness) { | ||
64 | continue levelsLoop; | ||
65 | } | ||
66 | } | ||
67 | if (o2HasBetterFitness && !o1HasBetterFitness) { | ||
68 | return -1; | ||
69 | } else if (!o2HasBetterFitness && o1HasBetterFitness) { | ||
70 | return 1; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | |||
76 | } | ||
77 | |||
78 | /** | ||
79 | * Adds a {@link TrajectoryFitness} to an inner list to compare later. | ||
80 | * | ||
81 | * @param trajectoryFitness | ||
82 | */ | ||
83 | public void addTrajectoryFitness(TrajectoryFitness trajectoryFitness) { | ||
84 | trajectoryFitnesses.add(trajectoryFitness); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * Clears the inner {@link TrajectoryFitness} list. | ||
89 | */ | ||
90 | public void clearTrajectoryFitnesses() { | ||
91 | trajectoryFitnesses.clear(); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Returns the inner {@link TrajectoryFitness} list. | ||
96 | */ | ||
97 | public List<TrajectoryFitness> getTrajectoryFitnesses() { | ||
98 | return trajectoryFitnesses; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * Returns a random {@link TrajectoryFitness} from the pareto front. | ||
103 | */ | ||
104 | public TrajectoryFitness getRandomBest() { | ||
105 | List<TrajectoryFitness> paretoFront = getParetoFront(); | ||
106 | int randomIndex = random.nextInt(paretoFront.size()); | ||
107 | return paretoFront.get(randomIndex); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Returns the pareto front of the previously added {@link TrajectoryFitness}. | ||
112 | */ | ||
113 | public List<TrajectoryFitness> getParetoFront() { | ||
114 | return getFronts().get(0); | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * Returns the previously added {@link TrajectoryFitness} instances in fronts. | ||
119 | */ | ||
120 | public List<? extends List<TrajectoryFitness>> getFronts() { | ||
121 | Preconditions.checkArgument(!trajectoryFitnesses.isEmpty(), "No trajectory fitnesses were added."); | ||
122 | List<ArrayList<TrajectoryFitness>> fronts = new ArrayList<ArrayList<TrajectoryFitness>>(); | ||
123 | |||
124 | Map<TrajectoryFitness, ArrayList<TrajectoryFitness>> dominatedInstances = new HashMap<TrajectoryFitness, ArrayList<TrajectoryFitness>>(); | ||
125 | Map<TrajectoryFitness, Integer> dominatingInstances = new HashMap<TrajectoryFitness, Integer>(); | ||
126 | |||
127 | // calculate dominations | ||
128 | for (TrajectoryFitness TrajectoryFitnessP : trajectoryFitnesses) { | ||
129 | dominatedInstances.put(TrajectoryFitnessP, new ArrayList<TrajectoryFitness>()); | ||
130 | dominatingInstances.put(TrajectoryFitnessP, 0); | ||
131 | |||
132 | for (TrajectoryFitness TrajectoryFitnessQ : trajectoryFitnesses) { | ||
133 | int dominates = compare(TrajectoryFitnessP.fitness, TrajectoryFitnessQ.fitness); | ||
134 | if (dominates > 0) { | ||
135 | dominatedInstances.get(TrajectoryFitnessP).add(TrajectoryFitnessQ); | ||
136 | } else if (dominates < 0) { | ||
137 | dominatingInstances.put(TrajectoryFitnessP, dominatingInstances.get(TrajectoryFitnessP) + 1); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | if (dominatingInstances.get(TrajectoryFitnessP) == 0) { | ||
142 | // p belongs to the first front | ||
143 | TrajectoryFitnessP.rank = 1; | ||
144 | if (fronts.isEmpty()) { | ||
145 | ArrayList<TrajectoryFitness> firstDominationFront = new ArrayList<TrajectoryFitness>(); | ||
146 | firstDominationFront.add(TrajectoryFitnessP); | ||
147 | fronts.add(firstDominationFront); | ||
148 | } else { | ||
149 | List<TrajectoryFitness> firstDominationFront = fronts.get(0); | ||
150 | firstDominationFront.add(TrajectoryFitnessP); | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // create fronts | ||
156 | int i = 1; | ||
157 | while (fronts.size() == i) { | ||
158 | ArrayList<TrajectoryFitness> nextDominationFront = new ArrayList<TrajectoryFitness>(); | ||
159 | for (TrajectoryFitness TrajectoryFitnessP : fronts.get(i - 1)) { | ||
160 | for (TrajectoryFitness TrajectoryFitnessQ : dominatedInstances.get(TrajectoryFitnessP)) { | ||
161 | dominatingInstances.put(TrajectoryFitnessQ, dominatingInstances.get(TrajectoryFitnessQ) - 1); | ||
162 | if (dominatingInstances.get(TrajectoryFitnessQ) == 0) { | ||
163 | TrajectoryFitnessQ.rank = i + 1; | ||
164 | nextDominationFront.add(TrajectoryFitnessQ); | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | i++; | ||
169 | if (!nextDominationFront.isEmpty()) { | ||
170 | if (computeCrowdingDistance) { | ||
171 | crowdingDistanceAssignment(nextDominationFront, leveledObjectives); | ||
172 | } | ||
173 | fronts.add(nextDominationFront); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | return fronts; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * Executes the crowding distance assignment for the specified front. | ||
182 | * | ||
183 | * @param front | ||
184 | */ | ||
185 | public static void crowdingDistanceAssignment(List<TrajectoryFitness> front, IObjective[][] leveledObjectives) { | ||
186 | |||
187 | for (TrajectoryFitness InstanceData : front) { | ||
188 | // initialize crowding distance | ||
189 | InstanceData.crowdingDistance = 0; | ||
190 | } | ||
191 | |||
192 | for (final IObjective[] objectives : leveledObjectives) { | ||
193 | for (final IObjective objective : objectives) { | ||
194 | |||
195 | final String m = objective.getName(); | ||
196 | TrajectoryFitness[] sortedFront = front.toArray(new TrajectoryFitness[0]); | ||
197 | // sort using m-th objective value | ||
198 | Arrays.sort(sortedFront, (o1, o2) -> objective.getComparator().compare(o1.fitness.get(m), o2.fitness.get(m))); | ||
199 | // so that boundary points are always selected | ||
200 | sortedFront[0].crowdingDistance = Double.POSITIVE_INFINITY; | ||
201 | sortedFront[sortedFront.length - 1].crowdingDistance = Double.POSITIVE_INFINITY; | ||
202 | // If minimal and maximal fitness value for this objective are | ||
203 | // equal, then do not change crowding distance | ||
204 | if (sortedFront[0].fitness.get(m) != sortedFront[sortedFront.length - 1].fitness.get(m)) { | ||
205 | for (int i = 1; i < sortedFront.length - 1; i++) { | ||
206 | double newCrowdingDistance = sortedFront[i].crowdingDistance; | ||
207 | newCrowdingDistance += (sortedFront[i + 1].fitness.get(m) - sortedFront[i - 1].fitness.get(m)) | ||
208 | / (sortedFront[sortedFront.length - 1].fitness.get(m) - sortedFront[0].fitness.get(m)); | ||
209 | |||
210 | sortedFront[i].crowdingDistance = newCrowdingDistance; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java new file mode 100644 index 00000000..f783afac --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java | |||
@@ -0,0 +1,84 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives; | ||
10 | |||
11 | import java.util.Arrays; | ||
12 | import java.util.List; | ||
13 | |||
14 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
15 | |||
16 | /** | ||
17 | * This class represents a trajectory and its fitness. | ||
18 | * @author Andras Szabolcs Nagy | ||
19 | * | ||
20 | */ | ||
21 | public class TrajectoryFitness { | ||
22 | |||
23 | public Object[] trajectory; | ||
24 | public Fitness fitness; | ||
25 | |||
26 | public int rank; | ||
27 | public double crowdingDistance; | ||
28 | |||
29 | private int hash; | ||
30 | |||
31 | public int survive; | ||
32 | |||
33 | /** | ||
34 | * Creates a {@link TrajectoryFitness} with the full trajectory. | ||
35 | * @param trajectory The trajectory. | ||
36 | * @param fitness The fitness. | ||
37 | */ | ||
38 | public TrajectoryFitness(Object[] trajectory, Fitness fitness) { | ||
39 | this.fitness = fitness; | ||
40 | this.trajectory = trajectory; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Creates a {@link TrajectoryFitness} with the full trajectory. | ||
45 | * @param trajectoryInfo The trajectory. | ||
46 | * @param fitness The fitness. | ||
47 | */ | ||
48 | public TrajectoryFitness(TrajectoryInfo trajectoryInfo, Fitness fitness) { | ||
49 | this.fitness = fitness; | ||
50 | List<Object> fullTraj = trajectoryInfo.getTrajectory(); | ||
51 | trajectory = fullTraj.toArray(new Object[fullTraj.size()]); | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * Creates a {@link TrajectoryFitness} with the given activation id} | ||
56 | * @param transition The transition. | ||
57 | * @param fitness The fitness. | ||
58 | */ | ||
59 | public TrajectoryFitness(Object transition, Fitness fitness) { | ||
60 | this.fitness = fitness; | ||
61 | trajectory = new Object[] {transition}; | ||
62 | } | ||
63 | |||
64 | @Override | ||
65 | public boolean equals(Object obj) { | ||
66 | if (obj instanceof TrajectoryFitness) { | ||
67 | return Arrays.equals(trajectory, ((TrajectoryFitness) obj).trajectory); | ||
68 | } | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | @Override | ||
73 | public int hashCode() { | ||
74 | if (hash == 0 && trajectory.length > 0) { | ||
75 | hash = Arrays.hashCode(trajectory); | ||
76 | } | ||
77 | return hash; | ||
78 | } | ||
79 | |||
80 | @Override | ||
81 | public String toString() { | ||
82 | return Arrays.toString(trajectory) + fitness.toString(); | ||
83 | } | ||
84 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java new file mode 100644 index 00000000..9898a3b5 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java | |||
@@ -0,0 +1,52 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
13 | |||
14 | /** | ||
15 | * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution. | ||
16 | * | ||
17 | * @author Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public class AlwaysSatisfiedDummyHardObjective extends BaseObjective { | ||
21 | |||
22 | private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective"; | ||
23 | |||
24 | public AlwaysSatisfiedDummyHardObjective() { | ||
25 | super(DEFAULT_NAME); | ||
26 | } | ||
27 | |||
28 | public AlwaysSatisfiedDummyHardObjective(String name) { | ||
29 | super(name); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Double getFitness(ThreadContext context) { | ||
34 | return 0d; | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public boolean isHardObjective() { | ||
39 | return true; | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public boolean satisifiesHardObjective(Double fitness) { | ||
44 | return true; | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public IObjective createNew() { | ||
49 | return this; | ||
50 | } | ||
51 | |||
52 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java new file mode 100644 index 00000000..0a1de875 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java | |||
@@ -0,0 +1,150 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives.impl; | ||
10 | |||
11 | import java.util.Comparator; | ||
12 | import java.util.Objects; | ||
13 | |||
14 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
15 | import org.eclipse.viatra.dse.objectives.Comparators; | ||
16 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
17 | |||
18 | /** | ||
19 | * This abstract class implements the basic functionality of an objective ({@link IObjective} namely its name, | ||
20 | * comparator, level and fitness hard constraint. | ||
21 | * | ||
22 | * @author Andras Szabolcs Nagy | ||
23 | * | ||
24 | */ | ||
25 | public abstract class BaseObjective implements IObjective { | ||
26 | |||
27 | protected final String name; | ||
28 | protected Comparator<Double> comparator = Comparators.HIGHER_IS_BETTER; | ||
29 | protected int level = 0; | ||
30 | |||
31 | protected double fitnessConstraint; | ||
32 | protected boolean isThereFitnessConstraint = false; | ||
33 | protected Comparator<Double> fitnessConstraintComparator; | ||
34 | |||
35 | public BaseObjective(String name) { | ||
36 | Objects.requireNonNull(name, "Name of the objective cannot be null."); | ||
37 | this.name = name; | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public String getName() { | ||
42 | return name; | ||
43 | } | ||
44 | |||
45 | @Override | ||
46 | public void setComparator(Comparator<Double> comparator) { | ||
47 | this.comparator = comparator; | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public Comparator<Double> getComparator() { | ||
52 | return comparator; | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public void setLevel(int level) { | ||
57 | this.level = level; | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public int getLevel() { | ||
62 | return level; | ||
63 | } | ||
64 | |||
65 | public BaseObjective withLevel(int level) { | ||
66 | setLevel(level); | ||
67 | return this; | ||
68 | } | ||
69 | |||
70 | public BaseObjective withComparator(Comparator<Double> comparator) { | ||
71 | setComparator(comparator); | ||
72 | return this; | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the | ||
77 | * current state as a solution. | ||
78 | * | ||
79 | * @param fitnessConstraint | ||
80 | * Solutions should be better than this value. | ||
81 | * @param fitnessConstraintComparator | ||
82 | * {@link Comparator} to determine if the current state is better than the given value. | ||
83 | * @return The actual instance to enable builder pattern like usage. | ||
84 | */ | ||
85 | public BaseObjective withHardConstraintOnFitness(double fitnessConstraint, | ||
86 | Comparator<Double> fitnessConstraintComparator) { | ||
87 | this.fitnessConstraint = fitnessConstraint; | ||
88 | this.fitnessConstraintComparator = fitnessConstraintComparator; | ||
89 | this.isThereFitnessConstraint = true; | ||
90 | return this; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the | ||
95 | * current state as a solution. The provided comparator will be used. | ||
96 | * | ||
97 | * @param fitnessConstraint | ||
98 | * Solutions should be better than this value. | ||
99 | * @return The actual instance to enable builder pattern like usage. | ||
100 | */ | ||
101 | public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) { | ||
102 | return withHardConstraintOnFitness(fitnessConstraint, null); | ||
103 | } | ||
104 | |||
105 | @Override | ||
106 | public void init(ThreadContext context) { | ||
107 | if (fitnessConstraintComparator == null) { | ||
108 | fitnessConstraintComparator = comparator; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | @Override | ||
113 | public boolean isHardObjective() { | ||
114 | return isThereFitnessConstraint; | ||
115 | } | ||
116 | |||
117 | @Override | ||
118 | public boolean satisifiesHardObjective(Double fitness) { | ||
119 | if (isThereFitnessConstraint) { | ||
120 | int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint); | ||
121 | if (compare < 0) { | ||
122 | return false; | ||
123 | } | ||
124 | } | ||
125 | return true; | ||
126 | } | ||
127 | |||
128 | @Override | ||
129 | public int hashCode() { | ||
130 | return name.hashCode(); | ||
131 | } | ||
132 | |||
133 | @Override | ||
134 | public boolean equals(Object obj) { | ||
135 | if (this == obj) { | ||
136 | return true; | ||
137 | } | ||
138 | if (obj instanceof BaseObjective) { | ||
139 | BaseObjective baseObjective = (BaseObjective) obj; | ||
140 | return name.equals(baseObjective.getName()); | ||
141 | } | ||
142 | return false; | ||
143 | } | ||
144 | |||
145 | @Override | ||
146 | public String toString() { | ||
147 | return name; | ||
148 | } | ||
149 | |||
150 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java new file mode 100644 index 00000000..cc48d22e --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java | |||
@@ -0,0 +1,137 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.List; | ||
13 | import java.util.Objects; | ||
14 | |||
15 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
16 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
18 | |||
19 | /** | ||
20 | * This objective collects a list of other objectives. It returns the weighted sum of the objectives. | ||
21 | * | ||
22 | * @author Andras Szabolcs Nagy | ||
23 | * | ||
24 | */ | ||
25 | public class CompositeObjective extends BaseObjective { | ||
26 | |||
27 | public static final String DEFAULT_NAME = "CompositeObjective"; | ||
28 | protected List<IObjective> objectives; | ||
29 | protected List<Double> weights; | ||
30 | protected boolean hardObjective; | ||
31 | |||
32 | public CompositeObjective(String name, List<IObjective> objectives, List<Double> weights) { | ||
33 | super(name); | ||
34 | Objects.requireNonNull(objectives, "The list of objectives cannot be null."); | ||
35 | Objects.requireNonNull(weights, "The list of weights cannot be null."); | ||
36 | Preconditions.checkState(objectives.size() == weights.size(), "The size of the objectives and weights must match."); | ||
37 | this.objectives = objectives; | ||
38 | this.weights = weights; | ||
39 | } | ||
40 | |||
41 | public CompositeObjective(List<IObjective> objectives, List<Double> weights) { | ||
42 | this(DEFAULT_NAME, objectives, weights); | ||
43 | } | ||
44 | |||
45 | public CompositeObjective(String name) { | ||
46 | this(name, new ArrayList<IObjective>(), new ArrayList<Double>()); | ||
47 | } | ||
48 | |||
49 | public CompositeObjective() { | ||
50 | this(DEFAULT_NAME, new ArrayList<IObjective>(), new ArrayList<Double>()); | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * Adds a new objective. | ||
55 | * | ||
56 | * @param objective | ||
57 | * @return The actual instance to enable builder pattern like usage. | ||
58 | */ | ||
59 | public CompositeObjective withObjective(IObjective objective) { | ||
60 | objectives.add(objective); | ||
61 | weights.add(1d); | ||
62 | return this; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Adds a new objective. | ||
67 | * | ||
68 | * @param objective | ||
69 | * @return The actual instance to enable builder pattern like usage. | ||
70 | */ | ||
71 | public CompositeObjective withObjective(IObjective objective, double weight) { | ||
72 | objectives.add(objective); | ||
73 | weights.add(weight); | ||
74 | return this; | ||
75 | } | ||
76 | |||
77 | @Override | ||
78 | public Double getFitness(ThreadContext context) { | ||
79 | |||
80 | double result = 0; | ||
81 | |||
82 | for (int i = 0; i < objectives.size(); i++) { | ||
83 | IObjective objective = objectives.get(i); | ||
84 | Double weight = weights.get(i); | ||
85 | result += objective.getFitness(context) * weight; | ||
86 | } | ||
87 | return result; | ||
88 | } | ||
89 | |||
90 | @Override | ||
91 | public void init(ThreadContext context) { | ||
92 | super.init(context); | ||
93 | hardObjective = false; | ||
94 | for (IObjective objective : objectives) { | ||
95 | objective.init(context); | ||
96 | if (objective.isHardObjective()) { | ||
97 | hardObjective = true; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | @Override | ||
103 | public IObjective createNew() { | ||
104 | |||
105 | List<IObjective> newObjectives = new ArrayList<IObjective>(); | ||
106 | |||
107 | for (IObjective objective : objectives) { | ||
108 | newObjectives.add(objective.createNew()); | ||
109 | } | ||
110 | |||
111 | CompositeObjective objective = new CompositeObjective(name, newObjectives, weights); | ||
112 | if (isThereFitnessConstraint) { | ||
113 | objective.withHardConstraintOnFitness(fitnessConstraint, fitnessConstraintComparator); | ||
114 | } | ||
115 | |||
116 | return objective.withComparator(comparator).withLevel(level); | ||
117 | } | ||
118 | |||
119 | @Override | ||
120 | public boolean isHardObjective() { | ||
121 | return hardObjective; | ||
122 | } | ||
123 | |||
124 | @Override | ||
125 | public boolean satisifiesHardObjective(Double fitness) { | ||
126 | |||
127 | boolean hardObjectiveSatisfied = true; | ||
128 | |||
129 | for (IObjective objective : objectives) { | ||
130 | hardObjectiveSatisfied = objective.satisifiesHardObjective(fitness) ? hardObjectiveSatisfied : false; | ||
131 | } | ||
132 | |||
133 | hardObjectiveSatisfied = super.satisifiesHardObjective(fitness) ? hardObjectiveSatisfied : false; | ||
134 | |||
135 | return hardObjectiveSatisfied; | ||
136 | } | ||
137 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java new file mode 100644 index 00000000..77d416f5 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java | |||
@@ -0,0 +1,316 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.List; | ||
13 | import java.util.Objects; | ||
14 | |||
15 | import org.eclipse.viatra.dse.api.DSEException; | ||
16 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
17 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
18 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
19 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
20 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
21 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher; | ||
22 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
23 | |||
24 | /** | ||
25 | * This objective serves as soft and as hard objective at the same time by defining two lists of VIATRA Query | ||
26 | * specifications. | ||
27 | * | ||
28 | * As a soft objective, it collects a list of VIATRA Query specifications, which have predefined weights. Then the | ||
29 | * fitness value of an arbitrary solution is calculated in the following way: | ||
30 | * <p> | ||
31 | * <code>fitness = sum( pattern[i].countMatches() * weight[i] )</code> | ||
32 | * <p> | ||
33 | * As a hard objective it collects a separate list of VIATRA Query specifications. If every one of them has a match the | ||
34 | * hard constraint is considered to be fulfilled. | ||
35 | * | ||
36 | * @author Andras Szabolcs Nagy | ||
37 | * @see IObjective | ||
38 | * | ||
39 | */ | ||
40 | public class ConstraintsObjective extends BaseObjective { | ||
41 | |||
42 | public static final String DEFAULT_NAME = "ConstraintsObjective"; | ||
43 | |||
44 | public static class QueryConstraint { | ||
45 | public final String name; | ||
46 | public final IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> query; | ||
47 | public final Double weight; | ||
48 | public final ModelQueryType type; | ||
49 | |||
50 | public QueryConstraint(String name, | ||
51 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> query, Double weight, | ||
52 | ModelQueryType type) { | ||
53 | this.name = name; | ||
54 | this.query = query; | ||
55 | this.weight = weight; | ||
56 | this.type = type; | ||
57 | } | ||
58 | |||
59 | public QueryConstraint(String name, | ||
60 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> query, Double weight) { | ||
61 | this(name, query, weight, ModelQueryType.MUST_HAVE_MATCH); | ||
62 | } | ||
63 | |||
64 | public QueryConstraint(String name, | ||
65 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> query, ModelQueryType type) { | ||
66 | this(name, query, 0d, type); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | protected List<QueryConstraint> softConstraints; | ||
71 | protected List<QueryConstraint> hardConstraints; | ||
72 | |||
73 | protected List<ViatraQueryMatcher<? extends IPatternMatch>> softMatchers; | ||
74 | protected List<ViatraQueryMatcher<? extends IPatternMatch>> hardMatchers; | ||
75 | protected List<Integer> softMatches; | ||
76 | protected List<Integer> hardMatches; | ||
77 | |||
78 | public ConstraintsObjective(String name, List<QueryConstraint> softConstraints, | ||
79 | List<QueryConstraint> hardConstraints) { | ||
80 | super(name); | ||
81 | Objects.requireNonNull(softConstraints, "The list of soft constraints cannot be null."); | ||
82 | Objects.requireNonNull(hardConstraints, "The list of hard constraints cannot be null."); | ||
83 | |||
84 | this.softConstraints = softConstraints; | ||
85 | this.hardConstraints = hardConstraints; | ||
86 | } | ||
87 | |||
88 | public ConstraintsObjective(String name, List<QueryConstraint> hardConstraints) { | ||
89 | this(name, new ArrayList<QueryConstraint>(), hardConstraints); | ||
90 | } | ||
91 | |||
92 | public ConstraintsObjective(List<QueryConstraint> hardConstraints) { | ||
93 | this(DEFAULT_NAME, new ArrayList<QueryConstraint>(), hardConstraints); | ||
94 | } | ||
95 | |||
96 | public ConstraintsObjective(String name) { | ||
97 | this(name, new ArrayList<QueryConstraint>(), new ArrayList<QueryConstraint>()); | ||
98 | } | ||
99 | |||
100 | public ConstraintsObjective() { | ||
101 | this(DEFAULT_NAME, new ArrayList<QueryConstraint>(), new ArrayList<QueryConstraint>()); | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * Adds a new soft constraint. | ||
106 | * | ||
107 | * @param name | ||
108 | * A name for the soft constraint. | ||
109 | * @param softConstraint | ||
110 | * A VIATRA Query pattern specification. | ||
111 | * @param weight | ||
112 | * The weight of the pattern. | ||
113 | * @return The actual instance to enable builder pattern like usage. | ||
114 | */ | ||
115 | public ConstraintsObjective withSoftConstraint(String name, | ||
116 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> softConstraint, double weight) { | ||
117 | softConstraints.add(new QueryConstraint(name, softConstraint, weight)); | ||
118 | return this; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * Adds a new soft constraint with the name of the query specification's fully qualified name. | ||
123 | * | ||
124 | * @param softConstraint | ||
125 | * A VIATRA Query pattern specification. | ||
126 | * @param weight | ||
127 | * The weight of the pattern. | ||
128 | * @return The actual instance to enable builder pattern like usage. | ||
129 | */ | ||
130 | public ConstraintsObjective withSoftConstraint( | ||
131 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> softConstraint, double weight) { | ||
132 | return withSoftConstraint(softConstraint.getFullyQualifiedName(), softConstraint, weight); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * Adds a new hard constraint. | ||
137 | * | ||
138 | * @param name | ||
139 | * A name for the hard constraint. | ||
140 | * @param softConstraint | ||
141 | * A VIATRA Query pattern specification. | ||
142 | * @param type | ||
143 | * {@link ModelQueryType}, which determines whether the constraint should have at least one match or none | ||
144 | * at all. | ||
145 | * @return The actual instance to enable builder pattern like usage. | ||
146 | */ | ||
147 | public ConstraintsObjective withHardConstraint(String name, | ||
148 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hardConstraint, | ||
149 | ModelQueryType type) { | ||
150 | hardConstraints.add(new QueryConstraint(name, hardConstraint, type)); | ||
151 | return this; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * Adds a new hard constraint with the default {@link ModelQueryType#MUST_HAVE_MATCH}. | ||
156 | * | ||
157 | * @param name | ||
158 | * A name for the hard constraint. | ||
159 | * @param softConstraint | ||
160 | * A VIATRA Query pattern specification. | ||
161 | * @return The actual instance to enable builder pattern like usage. | ||
162 | */ | ||
163 | public ConstraintsObjective withHardConstraint(String name, | ||
164 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hardConstraint) { | ||
165 | hardConstraints.add(new QueryConstraint(name, hardConstraint, ModelQueryType.MUST_HAVE_MATCH)); | ||
166 | return this; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * Adds a new hard constraint with the name of the query specification's fully qualified name and the default | ||
171 | * {@link ModelQueryType#MUST_HAVE_MATCH}. | ||
172 | * | ||
173 | * @param softConstraint | ||
174 | * A VIATRA Query pattern specification. | ||
175 | * @return The actual instance to enable builder pattern like usage. | ||
176 | */ | ||
177 | public ConstraintsObjective withHardConstraint( | ||
178 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hardConstraint) { | ||
179 | return withHardConstraint(hardConstraint.getFullyQualifiedName(), hardConstraint, | ||
180 | ModelQueryType.MUST_HAVE_MATCH); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * Adds a new hard constraint with the name of the query specification's fully qualified name. | ||
185 | * | ||
186 | * @param softConstraint | ||
187 | * A VIATRA Query pattern specification. | ||
188 | * @param type | ||
189 | * {@link ModelQueryType}, which determines whether the constraint should have at least one match or none | ||
190 | * at all. | ||
191 | * @return The actual instance to enable builder pattern like usage. | ||
192 | */ | ||
193 | public ConstraintsObjective withHardConstraint( | ||
194 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hardConstraint, | ||
195 | ModelQueryType type) { | ||
196 | return withHardConstraint(hardConstraint.getFullyQualifiedName(), hardConstraint, type); | ||
197 | } | ||
198 | |||
199 | @Override | ||
200 | public Double getFitness(ThreadContext context) { | ||
201 | |||
202 | if (softConstraints.isEmpty()) { | ||
203 | return 0d; | ||
204 | } | ||
205 | |||
206 | double result = 0; | ||
207 | |||
208 | for (int i = 0; i < softConstraints.size(); i++) { | ||
209 | int countMatches = softMatchers.get(i).countMatches(); | ||
210 | result += countMatches * softConstraints.get(i).weight; | ||
211 | softMatches.set(i, Integer.valueOf(countMatches)); | ||
212 | } | ||
213 | |||
214 | return result; | ||
215 | } | ||
216 | |||
217 | @Override | ||
218 | public void init(ThreadContext context) { | ||
219 | |||
220 | super.init(context); | ||
221 | |||
222 | softMatches = new ArrayList<Integer>(softConstraints.size()); | ||
223 | softMatchers = new ArrayList<ViatraQueryMatcher<? extends IPatternMatch>>(softConstraints.size()); | ||
224 | hardMatches = new ArrayList<Integer>(hardConstraints.size()); | ||
225 | hardMatchers = new ArrayList<ViatraQueryMatcher<? extends IPatternMatch>>(hardConstraints.size()); | ||
226 | for (int i = 0; i < softConstraints.size(); i++) { | ||
227 | softMatches.add(0); | ||
228 | } | ||
229 | for (int i = 0; i < hardConstraints.size(); i++) { | ||
230 | hardMatches.add(0); | ||
231 | } | ||
232 | |||
233 | try { | ||
234 | ViatraQueryEngine queryEngine = context.getQueryEngine(); | ||
235 | |||
236 | for (QueryConstraint qc : softConstraints) { | ||
237 | softMatchers.add(qc.query.getMatcher(queryEngine)); | ||
238 | } | ||
239 | |||
240 | for (QueryConstraint qc : hardConstraints) { | ||
241 | hardMatchers.add(qc.query.getMatcher(queryEngine)); | ||
242 | } | ||
243 | |||
244 | } catch (ViatraQueryException e) { | ||
245 | throw new DSEException("Couldn't initialize the VIATRA Query matcher, see inner exception", e); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | @Override | ||
250 | public IObjective createNew() { | ||
251 | new ArrayList<Double>(softConstraints.size()); | ||
252 | ConstraintsObjective result = new ConstraintsObjective(name, softConstraints, hardConstraints); | ||
253 | if (isThereFitnessConstraint) { | ||
254 | result.withHardConstraintOnFitness(fitnessConstraint, fitnessConstraintComparator); | ||
255 | } | ||
256 | return result.withComparator(comparator).withLevel(level); | ||
257 | } | ||
258 | |||
259 | @Override | ||
260 | public boolean isHardObjective() { | ||
261 | return !hardConstraints.isEmpty() || super.isHardObjective(); | ||
262 | } | ||
263 | |||
264 | @Override | ||
265 | public boolean satisifiesHardObjective(Double fitness) { | ||
266 | |||
267 | boolean result = true; | ||
268 | |||
269 | for (int i = 0; i < hardConstraints.size(); i++) { | ||
270 | ModelQueryType type = hardConstraints.get(i).type; | ||
271 | int countMatches = hardMatchers.get(i).countMatches(); | ||
272 | hardMatches.set(i, Integer.valueOf(countMatches)); | ||
273 | if ((type.equals(ModelQueryType.MUST_HAVE_MATCH) && countMatches <= 0) | ||
274 | || (type.equals(ModelQueryType.NO_MATCH) && countMatches > 0)) { | ||
275 | result = false; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | result = super.satisifiesHardObjective(fitness) ? result : false; | ||
280 | |||
281 | return result; | ||
282 | } | ||
283 | |||
284 | public List<QueryConstraint> getSoftConstraints() { | ||
285 | return softConstraints; | ||
286 | } | ||
287 | |||
288 | public List<QueryConstraint> getHardConstraints() { | ||
289 | return hardConstraints; | ||
290 | } | ||
291 | |||
292 | public String getSoftName(int index) { | ||
293 | return softConstraints.get(index).name; | ||
294 | } | ||
295 | |||
296 | public String getHardName(int index) { | ||
297 | return hardConstraints.get(index).name; | ||
298 | } | ||
299 | |||
300 | public List<Integer> getSoftMatches() { | ||
301 | return softMatches; | ||
302 | } | ||
303 | |||
304 | public List<Integer> getHardMatches() { | ||
305 | return hardMatches; | ||
306 | } | ||
307 | |||
308 | public List<String> getSoftNames() { | ||
309 | List<String> softNames = new ArrayList<>(softConstraints.size()); | ||
310 | for (QueryConstraint qc : softConstraints) { | ||
311 | softNames.add(qc.name); | ||
312 | } | ||
313 | return softNames; | ||
314 | } | ||
315 | |||
316 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java new file mode 100644 index 00000000..b21da397 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java | |||
@@ -0,0 +1,89 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
13 | |||
14 | /** | ||
15 | * This hard objective is fulfilled if the trajectory is in the specified interval (inclusive). | ||
16 | * | ||
17 | * @author Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public class DepthHardObjective extends BaseObjective { | ||
21 | |||
22 | private static final String DEFAULT_NAME = "DepthHardObjective"; | ||
23 | protected int minDepth; | ||
24 | protected int maxDepth; | ||
25 | private ThreadContext context; | ||
26 | |||
27 | public DepthHardObjective() { | ||
28 | this(DEFAULT_NAME, 0, Integer.MAX_VALUE); | ||
29 | } | ||
30 | |||
31 | public DepthHardObjective(String name) { | ||
32 | this(name, 0, Integer.MAX_VALUE); | ||
33 | } | ||
34 | |||
35 | public DepthHardObjective(int minDepth) { | ||
36 | this(DEFAULT_NAME, minDepth, Integer.MAX_VALUE); | ||
37 | } | ||
38 | |||
39 | public DepthHardObjective(String name, int minDepth) { | ||
40 | this(name, minDepth, Integer.MAX_VALUE); | ||
41 | } | ||
42 | |||
43 | public DepthHardObjective(int minDepth, int maxDepth) { | ||
44 | this(DEFAULT_NAME, minDepth, maxDepth); | ||
45 | } | ||
46 | |||
47 | public DepthHardObjective(String name, int minDepth, int maxDepth) { | ||
48 | super(name); | ||
49 | this.minDepth = minDepth; | ||
50 | this.maxDepth = maxDepth; | ||
51 | } | ||
52 | |||
53 | public DepthHardObjective withMinDepth(int minDepth) { | ||
54 | this.minDepth = minDepth; | ||
55 | return this; | ||
56 | } | ||
57 | |||
58 | public DepthHardObjective withMaxDepth(int maxDepth) { | ||
59 | this.maxDepth = maxDepth; | ||
60 | return this; | ||
61 | } | ||
62 | |||
63 | @Override | ||
64 | public void init(ThreadContext context) { | ||
65 | super.init(context); | ||
66 | this.context = context; | ||
67 | } | ||
68 | |||
69 | @Override | ||
70 | public Double getFitness(ThreadContext context) { | ||
71 | return 0d; | ||
72 | } | ||
73 | |||
74 | @Override | ||
75 | public boolean isHardObjective() { | ||
76 | return true; | ||
77 | } | ||
78 | |||
79 | @Override | ||
80 | public boolean satisifiesHardObjective(Double fitness) { | ||
81 | return minDepth <= context.getDepth() && context.getDepth() <= maxDepth; | ||
82 | } | ||
83 | |||
84 | @Override | ||
85 | public IObjective createNew() { | ||
86 | return new DepthHardObjective(name, minDepth, maxDepth); | ||
87 | } | ||
88 | |||
89 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java new file mode 100644 index 00000000..7616b4a2 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java | |||
@@ -0,0 +1,116 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.List; | ||
13 | import java.util.Objects; | ||
14 | |||
15 | import org.eclipse.viatra.dse.api.DSEException; | ||
16 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
17 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint; | ||
18 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
19 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
20 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
21 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher; | ||
22 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
23 | |||
24 | /** | ||
25 | * This global constraint collects a list of VIATRA Query pattern and checks if any of them has a match on along a trajectory. | ||
26 | * If any of the patterns has a match then it is unsatisfied and the exploration should backtrack. | ||
27 | * | ||
28 | * @author Andras Szabolcs Nagy | ||
29 | * | ||
30 | */ | ||
31 | public class ModelQueriesGlobalConstraint implements IGlobalConstraint { | ||
32 | |||
33 | public static final String GLOBAL_CONSTRAINT = "GlobalConstraint"; | ||
34 | protected String name; | ||
35 | protected List<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> constraints; | ||
36 | protected List<ViatraQueryMatcher<? extends IPatternMatch>> matchers = new ArrayList<ViatraQueryMatcher<? extends IPatternMatch>>(); | ||
37 | protected ModelQueryType type = ModelQueryType.NO_MATCH; | ||
38 | |||
39 | public ModelQueriesGlobalConstraint(String name, | ||
40 | List<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> constraints) { | ||
41 | Objects.requireNonNull(name, "Name of the global constraint cannot be null."); | ||
42 | Objects.requireNonNull(constraints, "The list of constraints cannot be null."); | ||
43 | |||
44 | this.name = name; | ||
45 | this.constraints = constraints; | ||
46 | } | ||
47 | |||
48 | public ModelQueriesGlobalConstraint( | ||
49 | List<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> constraints) { | ||
50 | this(GLOBAL_CONSTRAINT, constraints); | ||
51 | } | ||
52 | |||
53 | public ModelQueriesGlobalConstraint(String name) { | ||
54 | this(name, new ArrayList<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>>()); | ||
55 | } | ||
56 | |||
57 | public ModelQueriesGlobalConstraint() { | ||
58 | this(GLOBAL_CONSTRAINT, | ||
59 | new ArrayList<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>>()); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * Adds a new VIATRA Query pattern. | ||
64 | * | ||
65 | * @param constraint | ||
66 | * A VIATRA Query pattern. | ||
67 | * @return The actual instance to enable builder pattern like usage. | ||
68 | */ | ||
69 | public ModelQueriesGlobalConstraint withConstraint( | ||
70 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> constraint) { | ||
71 | constraints.add(constraint); | ||
72 | return this; | ||
73 | } | ||
74 | |||
75 | public ModelQueriesGlobalConstraint withType(ModelQueryType type) { | ||
76 | this.type = type; | ||
77 | return this; | ||
78 | } | ||
79 | |||
80 | @Override | ||
81 | public String getName() { | ||
82 | return name; | ||
83 | } | ||
84 | |||
85 | @Override | ||
86 | public boolean checkGlobalConstraint(ThreadContext context) { | ||
87 | for (ViatraQueryMatcher<? extends IPatternMatch> matcher : matchers) { | ||
88 | if ((type.equals(ModelQueryType.NO_MATCH) && matcher.countMatches() > 0) | ||
89 | || (type.equals(ModelQueryType.MUST_HAVE_MATCH) && matcher.countMatches() == 0)) { | ||
90 | return false; | ||
91 | } | ||
92 | } | ||
93 | return true; | ||
94 | } | ||
95 | |||
96 | @Override | ||
97 | public void init(ThreadContext context) { | ||
98 | try { | ||
99 | ViatraQueryEngine queryEngine = context.getQueryEngine(); | ||
100 | |||
101 | for (IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> querySpecification : constraints) { | ||
102 | ViatraQueryMatcher<? extends IPatternMatch> matcher = querySpecification.getMatcher(queryEngine); | ||
103 | matchers.add(matcher); | ||
104 | } | ||
105 | |||
106 | } catch (ViatraQueryException e) { | ||
107 | throw new DSEException("Couldn't get the VIATRA Query matcher, see inner exception", e); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | @Override | ||
112 | public IGlobalConstraint createNew() { | ||
113 | return new ModelQueriesGlobalConstraint(name, constraints); | ||
114 | } | ||
115 | |||
116 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java new file mode 100644 index 00000000..76390352 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java | |||
@@ -0,0 +1,14 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, 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.objectives.impl; | ||
10 | |||
11 | public enum ModelQueryType { | ||
12 | MUST_HAVE_MATCH, | ||
13 | NO_MATCH | ||
14 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java new file mode 100644 index 00000000..27cf139c --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java | |||
@@ -0,0 +1,52 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
13 | |||
14 | /** | ||
15 | * This hard objective is never fulfilled. Use it if all states should be regarded as an invalid solution. | ||
16 | * | ||
17 | * @author Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public class NeverSatisfiedDummyHardObjective extends BaseObjective { | ||
21 | |||
22 | private static final String DEFAULT_NAME = "NeverSatisfiedDummyHardObjective"; | ||
23 | |||
24 | public NeverSatisfiedDummyHardObjective() { | ||
25 | super(DEFAULT_NAME); | ||
26 | } | ||
27 | |||
28 | public NeverSatisfiedDummyHardObjective(String name) { | ||
29 | super(name); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Double getFitness(ThreadContext context) { | ||
34 | return 0d; | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public boolean isHardObjective() { | ||
39 | return true; | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public boolean satisifiesHardObjective(Double fitness) { | ||
44 | return false; | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public IObjective createNew() { | ||
49 | return this; | ||
50 | } | ||
51 | |||
52 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java new file mode 100644 index 00000000..756d94ec --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java | |||
@@ -0,0 +1,59 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
12 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
13 | |||
14 | /** | ||
15 | * This hard objective is satisfied if there are no rule activations from the current state (returning 1 in this case). | ||
16 | * | ||
17 | * @author Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public class NoRuleActivationsHardObjective extends BaseObjective { | ||
21 | |||
22 | protected static final String DEFAULT_NAME = "NoMoreActivationHardObjective"; | ||
23 | private ThreadContext context; | ||
24 | |||
25 | public NoRuleActivationsHardObjective(String name) { | ||
26 | super(name); | ||
27 | } | ||
28 | |||
29 | public NoRuleActivationsHardObjective() { | ||
30 | this(DEFAULT_NAME); | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public Double getFitness(ThreadContext context) { | ||
35 | return 0d; | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public void init(ThreadContext context) { | ||
40 | super.init(context); | ||
41 | this.context = context; | ||
42 | } | ||
43 | |||
44 | @Override | ||
45 | public IObjective createNew() { | ||
46 | return new NoRuleActivationsHardObjective(name); | ||
47 | } | ||
48 | |||
49 | @Override | ||
50 | public boolean isHardObjective() { | ||
51 | return true; | ||
52 | } | ||
53 | |||
54 | @Override | ||
55 | public boolean satisifiesHardObjective(Double fitness) { | ||
56 | return context.getConflictSet().getNextActivations().isEmpty(); | ||
57 | } | ||
58 | |||
59 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java new file mode 100644 index 00000000..25ff45ae --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java | |||
@@ -0,0 +1,148 @@ | |||
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.objectives.impl; | ||
10 | |||
11 | import java.util.HashMap; | ||
12 | import java.util.List; | ||
13 | import java.util.Map; | ||
14 | import java.util.Map.Entry; | ||
15 | import java.util.Objects; | ||
16 | |||
17 | import org.eclipse.viatra.dse.base.DesignSpaceManager; | ||
18 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
19 | import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo; | ||
20 | import org.eclipse.viatra.dse.objectives.ActivationFitnessProcessor; | ||
21 | import org.eclipse.viatra.dse.objectives.Comparators; | ||
22 | import org.eclipse.viatra.dse.objectives.IObjective; | ||
23 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
24 | import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule; | ||
25 | |||
26 | /** | ||
27 | * This soft objective calculates a fitness value based on the length of the trajectory. Costs to the rules can be | ||
28 | * assigned. | ||
29 | * | ||
30 | * @author Andras Szabolcs Nagy | ||
31 | * | ||
32 | */ | ||
33 | public class TrajectoryCostSoftObjective extends BaseObjective { | ||
34 | |||
35 | public static final String DEFAULT_NAME = "TrajectoryCostObjective"; | ||
36 | protected Map<BatchTransformationRule<?, ?>, Double> fixCosts; | ||
37 | protected Map<BatchTransformationRule<?, ?>, ActivationFitnessProcessor> activationCostProcessors; | ||
38 | protected double trajectoryLengthWeight = 0.0; | ||
39 | protected boolean calculateTrajectoryLengthWeight; | ||
40 | |||
41 | public TrajectoryCostSoftObjective(String name) { | ||
42 | super(name); | ||
43 | comparator = Comparators.LOWER_IS_BETTER; | ||
44 | } | ||
45 | |||
46 | public TrajectoryCostSoftObjective() { | ||
47 | this(DEFAULT_NAME); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * Sets the cost of a rule. | ||
52 | * | ||
53 | * @param rule | ||
54 | * @param cost | ||
55 | * @return The actual instance to enable builder pattern like usage. | ||
56 | */ | ||
57 | public TrajectoryCostSoftObjective withRuleCost(BatchTransformationRule<?, ?> rule, double cost) { | ||
58 | Objects.requireNonNull(rule); | ||
59 | if (fixCosts == null) { | ||
60 | fixCosts = new HashMap<BatchTransformationRule<?, ?>, Double>(); | ||
61 | } | ||
62 | Preconditions.checkArgument(!fixCosts.containsKey(rule)); | ||
63 | fixCosts.put(rule, cost); | ||
64 | return this; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * Sets an activation processor for a rule. | ||
69 | * | ||
70 | * @param rule | ||
71 | * @param activationCostProcessor | ||
72 | * @return The actual instance to enable builder pattern like usage. | ||
73 | */ | ||
74 | public TrajectoryCostSoftObjective withActivationCost(BatchTransformationRule<?, ?> rule, | ||
75 | ActivationFitnessProcessor activationCostProcessor) { | ||
76 | Objects.requireNonNull(rule); | ||
77 | Objects.requireNonNull(activationCostProcessor); | ||
78 | if (activationCostProcessors == null) { | ||
79 | activationCostProcessors = new HashMap<BatchTransformationRule<?, ?>, ActivationFitnessProcessor>(); | ||
80 | } | ||
81 | Preconditions.checkArgument(!activationCostProcessors.containsKey(rule)); | ||
82 | activationCostProcessors.put(rule, activationCostProcessor); | ||
83 | return this; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * The length of the trajectory multiplied with given parameter will be added to the fitness value. | ||
88 | * | ||
89 | * @param trajectoryLengthWeight | ||
90 | * The weight of a transformation rule application. | ||
91 | * @return The actual instance to enable builder pattern like usage. | ||
92 | */ | ||
93 | public TrajectoryCostSoftObjective withTrajectoryLengthWeight(double trajectoryLengthWeight) { | ||
94 | this.trajectoryLengthWeight = trajectoryLengthWeight; | ||
95 | this.calculateTrajectoryLengthWeight = true; | ||
96 | return this; | ||
97 | } | ||
98 | |||
99 | @Override | ||
100 | public Double getFitness(ThreadContext context) { | ||
101 | |||
102 | DesignSpaceManager dsm = context.getDesignSpaceManager(); | ||
103 | TrajectoryInfo trajectoryInfo = dsm.getTrajectoryInfo(); | ||
104 | List<Object> trajectory = trajectoryInfo.getTrajectory(); | ||
105 | List<BatchTransformationRule<?, ?>> rules = trajectoryInfo.getRules(); | ||
106 | |||
107 | double result = 0; | ||
108 | |||
109 | for (int i = 0; i < trajectory.size(); i++) { | ||
110 | BatchTransformationRule<?, ?> rule = rules.get(i); | ||
111 | |||
112 | Double cost = fixCosts.get(rule); | ||
113 | if (cost != null) { | ||
114 | result += cost; | ||
115 | } | ||
116 | |||
117 | Map<String, Double> costs = trajectoryInfo.getMeasuredCosts().get(i); | ||
118 | if (costs != null) { | ||
119 | cost = costs.get(name); | ||
120 | if (cost != null) { | ||
121 | result += cost; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (calculateTrajectoryLengthWeight) { | ||
127 | result += trajectory.size() * trajectoryLengthWeight; | ||
128 | } | ||
129 | |||
130 | return result; | ||
131 | } | ||
132 | |||
133 | @Override | ||
134 | public void init(ThreadContext context) { | ||
135 | super.init(context); | ||
136 | DesignSpaceManager dsm = context.getDesignSpaceManager(); | ||
137 | if (activationCostProcessors != null) { | ||
138 | for (Entry<BatchTransformationRule<?, ?>, ActivationFitnessProcessor> entry : activationCostProcessors.entrySet()) { | ||
139 | dsm.registerActivationCostProcessor(name, entry.getKey(), entry.getValue()); | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | @Override | ||
145 | public IObjective createNew() { | ||
146 | return this; | ||
147 | } | ||
148 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java new file mode 100644 index 00000000..8d74e856 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java | |||
@@ -0,0 +1,40 @@ | |||
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.solutionstore; | ||
10 | |||
11 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
12 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | ||
13 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
14 | import org.eclipse.viatra.dse.solutionstore.SolutionStore.ISolutionSaver; | ||
15 | |||
16 | /** | ||
17 | * Contains callback methods which are called when a solution is found by the exploration {@link IStrategy}. | ||
18 | * | ||
19 | * @author Andras Szabolcs Nagy | ||
20 | * | ||
21 | */ | ||
22 | public interface ISolutionFoundHandler { | ||
23 | |||
24 | /** | ||
25 | * Called when a solution is saved by the {@link ISolutionSaver}. Later, this solution can be omitted from the final | ||
26 | * set of solutions. | ||
27 | * | ||
28 | * @param context | ||
29 | * @param trajectory | ||
30 | */ | ||
31 | void solutionFound(ThreadContext context, SolutionTrajectory trajectory); | ||
32 | |||
33 | /** | ||
34 | * Called when the exploration found a solution but it was not saved because of certain conditions. | ||
35 | * | ||
36 | * @param context | ||
37 | * @param trajectory | ||
38 | */ | ||
39 | void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory); | ||
40 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java new file mode 100644 index 00000000..36e6b5b7 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java | |||
@@ -0,0 +1,18 @@ | |||
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.solutionstore; | ||
10 | |||
11 | /** | ||
12 | * Provides file name when a model is searialzed. | ||
13 | * @author Andras Szabolcs Nagy | ||
14 | * | ||
15 | */ | ||
16 | public interface ISolutionNameProvider { | ||
17 | String getName(); | ||
18 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java new file mode 100644 index 00000000..43460015 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java | |||
@@ -0,0 +1,37 @@ | |||
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.solutionstore; | ||
10 | |||
11 | /** | ||
12 | * Provides file name with a String <code>[prefix][id].[extension]</code> pattern. | ||
13 | * @author Andras Szabolcs Nagy | ||
14 | * | ||
15 | */ | ||
16 | public class IdBasedSolutionNameProvider implements ISolutionNameProvider { | ||
17 | |||
18 | private int id = 1; | ||
19 | private String prefix; | ||
20 | private String extension; | ||
21 | |||
22 | public IdBasedSolutionNameProvider(String prefix, String extension) { | ||
23 | this.extension = extension; | ||
24 | this.prefix = prefix; | ||
25 | |||
26 | } | ||
27 | |||
28 | @Override | ||
29 | public String getName() { | ||
30 | StringBuilder sb = new StringBuilder(prefix); | ||
31 | sb.append(id++); | ||
32 | sb.append('.'); | ||
33 | sb.append(extension); | ||
34 | return sb.toString(); | ||
35 | } | ||
36 | |||
37 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java new file mode 100644 index 00000000..118f0c75 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java | |||
@@ -0,0 +1,28 @@ | |||
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.solutionstore; | ||
10 | |||
11 | import org.apache.log4j.Logger; | ||
12 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
13 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
14 | |||
15 | public class LogSolutionHandler implements ISolutionFoundHandler { | ||
16 | |||
17 | Logger logger = Logger.getLogger(LogSolutionHandler.class); | ||
18 | |||
19 | @Override | ||
20 | public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) { | ||
21 | logger.info("Solution registered: " + trajectory.toPrettyString()); | ||
22 | } | ||
23 | |||
24 | @Override | ||
25 | public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) { | ||
26 | logger.debug("Not good enough solution: " + trajectory.toPrettyString()); | ||
27 | } | ||
28 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java new file mode 100644 index 00000000..bbbe60de --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java | |||
@@ -0,0 +1,55 @@ | |||
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.solutionstore; | ||
10 | |||
11 | import java.util.HashSet; | ||
12 | |||
13 | import org.eclipse.emf.common.notify.Notifier; | ||
14 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
15 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
16 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
17 | |||
18 | public class ModelSaverSolutionFoundHandler implements ISolutionFoundHandler { | ||
19 | |||
20 | private HashSet<Object> savedSolutions = new HashSet<Object>(); | ||
21 | private ISolutionNameProvider solutionNameProvider; | ||
22 | |||
23 | public ModelSaverSolutionFoundHandler() { | ||
24 | solutionNameProvider = new IdBasedSolutionNameProvider("solution", "xmi"); | ||
25 | } | ||
26 | |||
27 | public ModelSaverSolutionFoundHandler(String extension) { | ||
28 | solutionNameProvider = new IdBasedSolutionNameProvider("solution", extension); | ||
29 | } | ||
30 | |||
31 | public ModelSaverSolutionFoundHandler(String prefix, String extension) { | ||
32 | solutionNameProvider = new IdBasedSolutionNameProvider(prefix, extension); | ||
33 | } | ||
34 | |||
35 | public ModelSaverSolutionFoundHandler(ISolutionNameProvider solutionNameProvider) { | ||
36 | this.solutionNameProvider = solutionNameProvider; | ||
37 | } | ||
38 | |||
39 | @Override | ||
40 | public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) { | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) { | ||
45 | Object stateCode = trajectory.getSolution().getStateCode(); | ||
46 | |||
47 | if (savedSolutions.contains(stateCode)) { | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | savedSolutions.add(stateCode); | ||
52 | Notifier clonedModel = EMFHelper.clone(context.getModel()); | ||
53 | EMFHelper.saveModel(clonedModel, solutionNameProvider.getName()); | ||
54 | } | ||
55 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java new file mode 100644 index 00000000..578ae277 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java | |||
@@ -0,0 +1,311 @@ | |||
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.solutionstore; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.List; | ||
15 | import java.util.Map; | ||
16 | import java.util.Map.Entry; | ||
17 | import java.util.concurrent.atomic.AtomicBoolean; | ||
18 | import java.util.concurrent.atomic.AtomicInteger; | ||
19 | |||
20 | import org.apache.log4j.Level; | ||
21 | import org.apache.log4j.Logger; | ||
22 | import org.eclipse.emf.common.notify.Notifier; | ||
23 | import org.eclipse.viatra.dse.api.DSEException; | ||
24 | import org.eclipse.viatra.dse.api.Solution; | ||
25 | import org.eclipse.viatra.dse.api.SolutionTrajectory; | ||
26 | import org.eclipse.viatra.dse.base.DesignSpaceManager; | ||
27 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
28 | import org.eclipse.viatra.dse.objectives.Fitness; | ||
29 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper; | ||
30 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
31 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
32 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
33 | |||
34 | /** | ||
35 | * | ||
36 | * @author Andras Szabolcs Nagy | ||
37 | * | ||
38 | */ | ||
39 | public class SolutionStore { | ||
40 | |||
41 | public interface ISolutionSaver { | ||
42 | void setSolutionsCollection(Map<Object, Solution> solutions); | ||
43 | boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory); | ||
44 | } | ||
45 | |||
46 | public interface IEnoughSolutions extends ISolutionFoundHandler { | ||
47 | boolean enoughSolutions(); | ||
48 | } | ||
49 | |||
50 | public static class ANumberOfEnoughSolutions implements IEnoughSolutions { | ||
51 | |||
52 | private final AtomicInteger foundSolutions; | ||
53 | private final AtomicBoolean foundEnoughSolutions; | ||
54 | |||
55 | public ANumberOfEnoughSolutions(int number) { | ||
56 | foundSolutions = new AtomicInteger(number); | ||
57 | foundEnoughSolutions = new AtomicBoolean(false); | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public boolean enoughSolutions() { | ||
62 | return foundEnoughSolutions.get(); | ||
63 | } | ||
64 | |||
65 | @Override | ||
66 | public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) { | ||
67 | int solutionsToFind = foundSolutions.decrementAndGet(); | ||
68 | if (solutionsToFind == 0) { | ||
69 | foundEnoughSolutions.set(true); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | @Override | ||
74 | public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) { | ||
75 | } | ||
76 | } | ||
77 | |||
78 | public static class SimpleSolutionSaver implements ISolutionSaver { | ||
79 | |||
80 | private Map<Object, Solution> solutions; | ||
81 | |||
82 | @Override | ||
83 | public void setSolutionsCollection(Map<Object, Solution> solutions) { | ||
84 | this.solutions = solutions; | ||
85 | } | ||
86 | |||
87 | @Override | ||
88 | public boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) { | ||
89 | Solution solution = solutions.get(id); | ||
90 | if (solution != null) { | ||
91 | if (solution.getTrajectories().contains(solutionTrajectory)) { | ||
92 | return false; | ||
93 | } else { | ||
94 | solution.addTrajectory(solutionTrajectory); | ||
95 | solutionTrajectory.setSolution(solution); | ||
96 | } | ||
97 | } else { | ||
98 | solution = new Solution(id, solutionTrajectory); | ||
99 | solutions.put(id, solution); | ||
100 | solutionTrajectory.setSolution(solution); | ||
101 | } | ||
102 | return true; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | public static class BestSolutionSaver implements ISolutionSaver { | ||
107 | |||
108 | private Map<Object, Solution> solutions; | ||
109 | private Map<SolutionTrajectory, Fitness> trajectories = new HashMap<>(); | ||
110 | |||
111 | @Override | ||
112 | public void setSolutionsCollection(Map<Object, Solution> solutions) { | ||
113 | this.solutions = solutions; | ||
114 | } | ||
115 | |||
116 | @Override | ||
117 | public boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) { | ||
118 | |||
119 | Fitness lastFitness = context.getLastFitness(); | ||
120 | ObjectiveComparatorHelper comparatorHelper = context.getObjectiveComparatorHelper(); | ||
121 | |||
122 | List<SolutionTrajectory> dominatedTrajectories = new ArrayList<>(); | ||
123 | |||
124 | for (Entry<SolutionTrajectory, Fitness> entry : trajectories.entrySet()) { | ||
125 | int isLastFitnessBetter = comparatorHelper.compare(lastFitness, entry.getValue()); | ||
126 | if (isLastFitnessBetter < 0) { | ||
127 | return false; | ||
128 | } | ||
129 | if (isLastFitnessBetter > 0) { | ||
130 | dominatedTrajectories.add(entry.getKey()); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | boolean solutionSaved = false; | ||
135 | |||
136 | Solution solution = solutions.get(id); | ||
137 | if (solution != null) { | ||
138 | if (!solution.getTrajectories().contains(solutionTrajectory)) { | ||
139 | solution.addTrajectory(solutionTrajectory); | ||
140 | solutionTrajectory.setSolution(solution); | ||
141 | solutionSaved = true; | ||
142 | trajectories.put(solutionTrajectory, lastFitness); | ||
143 | } | ||
144 | } else { | ||
145 | solution = new Solution(id, solutionTrajectory); | ||
146 | solutions.put(id, solution); | ||
147 | solutionTrajectory.setSolution(solution); | ||
148 | solutionSaved = true; | ||
149 | trajectories.put(solutionTrajectory, lastFitness); | ||
150 | } | ||
151 | |||
152 | for (SolutionTrajectory st : dominatedTrajectories) { | ||
153 | trajectories.remove(st); | ||
154 | Solution s = st.getSolution(); | ||
155 | if (!s.getTrajectories().remove(st)) { | ||
156 | throw new DSEException("Should not happen."); | ||
157 | } | ||
158 | if (s.getTrajectories().isEmpty()) { | ||
159 | Object stateCode = s.getStateCode(); | ||
160 | solutions.remove(stateCode); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | return solutionSaved; | ||
165 | } | ||
166 | |||
167 | } | ||
168 | |||
169 | protected boolean acceptOnlyGoalSolutions = true; | ||
170 | protected final Map<Object, Solution> solutions = new HashMap<Object, Solution>(); | ||
171 | protected ISolutionSaver solutionSaver = new SimpleSolutionSaver(); | ||
172 | protected List<ISolutionFoundHandler> solutionFoundHandlers = new ArrayList<ISolutionFoundHandler>(1); | ||
173 | |||
174 | protected final IEnoughSolutions enoughSolutions; | ||
175 | |||
176 | public SolutionStore() { | ||
177 | this(new IEnoughSolutions() { | ||
178 | @Override | ||
179 | public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) { | ||
180 | } | ||
181 | |||
182 | @Override | ||
183 | public boolean enoughSolutions() { | ||
184 | return false; | ||
185 | } | ||
186 | |||
187 | @Override | ||
188 | public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) { | ||
189 | } | ||
190 | }); | ||
191 | } | ||
192 | |||
193 | public SolutionStore(int numOfSolutionsToFind) { | ||
194 | this(new ANumberOfEnoughSolutions(numOfSolutionsToFind)); | ||
195 | } | ||
196 | |||
197 | public SolutionStore(IEnoughSolutions enoughSolutionsImpl) { | ||
198 | enoughSolutions = enoughSolutionsImpl; | ||
199 | } | ||
200 | |||
201 | public synchronized void newSolution(ThreadContext context) { | ||
202 | solutionSaver.setSolutionsCollection(solutions); | ||
203 | Fitness fitness = context.getLastFitness(); | ||
204 | DesignSpaceManager dsm = context.getDesignSpaceManager(); | ||
205 | Object id = dsm.getCurrentState(); | ||
206 | IStateCoderFactory stateCoderFactory = context.getGlobalContext().getStateCoderFactory(); | ||
207 | SolutionTrajectory solutionTrajectory = dsm.getTrajectoryInfo().createSolutionTrajectory(stateCoderFactory, context.getDesignSpaceManager()); | ||
208 | solutionTrajectory.setFitness(fitness); | ||
209 | |||
210 | if (acceptOnlyGoalSolutions && !fitness.isSatisifiesHardObjectives()) { | ||
211 | unsavedSolutionCallbacks(context, solutionTrajectory); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | boolean solutionSaved = solutionSaver.saveSolution(context, id, solutionTrajectory); | ||
216 | |||
217 | if (solutionSaved) { | ||
218 | enoughSolutions.solutionFound(context, solutionTrajectory); | ||
219 | |||
220 | savedSolutionCallbacks(context, solutionTrajectory); | ||
221 | |||
222 | if (enoughSolutions.enoughSolutions()) { | ||
223 | context.getGlobalContext().stopAllThreads(); | ||
224 | } | ||
225 | } else { | ||
226 | unsavedSolutionCallbacks(context, solutionTrajectory); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | private void unsavedSolutionCallbacks(ThreadContext context, SolutionTrajectory solutionTrajectory) { | ||
231 | for (ISolutionFoundHandler handler : solutionFoundHandlers) { | ||
232 | handler.solutionTriedToSave(context, solutionTrajectory); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | private void savedSolutionCallbacks(ThreadContext context, SolutionTrajectory solutionTrajectory) { | ||
237 | for (ISolutionFoundHandler handler : solutionFoundHandlers) { | ||
238 | handler.solutionFound(context, solutionTrajectory); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | public synchronized Collection<Solution> getSolutions() { | ||
243 | return solutions.values(); | ||
244 | } | ||
245 | |||
246 | public synchronized void registerSolutionFoundHandler(ISolutionFoundHandler handler) { | ||
247 | if (solutionFoundHandlers == null) { | ||
248 | solutionFoundHandlers = new ArrayList<ISolutionFoundHandler>(1); | ||
249 | } | ||
250 | solutionFoundHandlers.add(handler); | ||
251 | } | ||
252 | |||
253 | public SolutionStore logSolutionsWhenFound() { | ||
254 | registerSolutionFoundHandler(new LogSolutionHandler()); | ||
255 | Logger.getLogger(LogSolutionHandler.class).setLevel(Level.INFO); | ||
256 | return this; | ||
257 | } | ||
258 | |||
259 | public SolutionStore saveModelWhenFound() { | ||
260 | registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler()); | ||
261 | return this; | ||
262 | } | ||
263 | |||
264 | public SolutionStore saveModelWhenFound(String extension) { | ||
265 | registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(extension)); | ||
266 | return this; | ||
267 | } | ||
268 | |||
269 | public SolutionStore saveModelWhenFound(String prefix, String extension) { | ||
270 | registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(prefix, extension)); | ||
271 | return this; | ||
272 | } | ||
273 | |||
274 | public SolutionStore saveModelWhenFound(ISolutionNameProvider solutionNameProvider) { | ||
275 | registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(solutionNameProvider)); | ||
276 | return this; | ||
277 | } | ||
278 | |||
279 | public SolutionStore acceptGoalSolutionsOnly() { | ||
280 | acceptOnlyGoalSolutions = true; | ||
281 | return this; | ||
282 | } | ||
283 | |||
284 | public SolutionStore acceptAnySolutions() { | ||
285 | acceptOnlyGoalSolutions = false; | ||
286 | return this; | ||
287 | } | ||
288 | |||
289 | public SolutionStore withSolutionSaver(ISolutionSaver solutionSaver) { | ||
290 | this.solutionSaver = solutionSaver; | ||
291 | return this; | ||
292 | } | ||
293 | |||
294 | public SolutionStore storeBestSolutionsOnly() { | ||
295 | this.solutionSaver = new BestSolutionSaver(); | ||
296 | return this; | ||
297 | } | ||
298 | |||
299 | public void saveModels(Notifier model, ISolutionNameProvider solutionNameProvider) { | ||
300 | try { | ||
301 | for (Solution solution : solutions.values()) { | ||
302 | SolutionTrajectory trajectory = solution.getArbitraryTrajectory(); | ||
303 | trajectory.doTransformationUndoable(model); | ||
304 | EMFHelper.saveModel(model, solutionNameProvider.getName()); | ||
305 | trajectory.undoTransformation(); | ||
306 | } | ||
307 | } catch (ViatraQueryException e) { | ||
308 | Logger.getLogger(SolutionStore.class).error("Exception happened during model saving.", e); | ||
309 | } | ||
310 | } | ||
311 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java new file mode 100644 index 00000000..f163f1a5 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java | |||
@@ -0,0 +1,82 @@ | |||
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.statecode; | ||
10 | |||
11 | import org.eclipse.emf.common.notify.Notifier; | ||
12 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
13 | |||
14 | /** | ||
15 | * <p> | ||
16 | * To be able to efficiently explore a design space, a state that has been explored before through an other trajectory | ||
17 | * needs to be recognized and ignored accordingly. | ||
18 | * </p> | ||
19 | * | ||
20 | * <p> | ||
21 | * This is done by generating a pseudo-unique value (object) that is only depended on the relevant parts of the model's | ||
22 | * internal state, that is, the values of two states can only be equal if the states themselves can be considered equal. | ||
23 | * </p> | ||
24 | * | ||
25 | * <p> | ||
26 | * The processing engine however assumes, that any two states that share this pseudo-unique value has the same | ||
27 | * characteristics, meaning they have the same amount and type of outgoing transitions available, and firing the | ||
28 | * appropriate transitions from both states also result in states that share their pseudo-unique identifier. If this | ||
29 | * condition is not satisfied, the exploration process's result will be non-deterministic, and in consequence, solutions | ||
30 | * can be lost. | ||
31 | * </p> | ||
32 | * | ||
33 | * <p> | ||
34 | * In addition to providing pseudo-unique identifiers to model states, the state coder must provide pseud-unique | ||
35 | * identifiers to the outgoing transitions as well, but they only need to be unique on the scope of the particular | ||
36 | * state, not globally. Global addressing thus can be achieved by considering the pseudo-unique identifier of the state | ||
37 | * and the pseudo-unique identifier of the transition together if needed. | ||
38 | * </p> | ||
39 | * | ||
40 | * <p> | ||
41 | * Both identifiers can be arbitrary objects, and equality is checked by calling {@link Object#equals(Object)} on the | ||
42 | * two identifiers. | ||
43 | * </p> | ||
44 | * | ||
45 | * <p> | ||
46 | * For any particular implementation an {@link IStateCoderFactory} implementation must also be supplied that handles the | ||
47 | * creation of {@link IStateCoder} instances. | ||
48 | * </p> | ||
49 | * | ||
50 | * <p> | ||
51 | * Usually it is unnecessary to represent everything from the model in a state code, only the parts which are modified | ||
52 | * by the transformation rules. | ||
53 | * </p> | ||
54 | * | ||
55 | * @author Miklos Foldenyi, Andras Szabolcs Nagy | ||
56 | * | ||
57 | */ | ||
58 | public interface IStateCoder { | ||
59 | |||
60 | /** | ||
61 | * Initializes the state coder on the given model. | ||
62 | * | ||
63 | * @param notifier | ||
64 | */ | ||
65 | void init(Notifier notifier); | ||
66 | |||
67 | /** | ||
68 | * Returns a pseudo-unique identifier that describes the underlying model's current internal state. | ||
69 | * | ||
70 | * @return an arbitrary {@link Object} that can be used as the identifier. | ||
71 | */ | ||
72 | Object createStateCode(); | ||
73 | |||
74 | /** | ||
75 | * Returns a pseudo-unique identifier that describes the given {@link IPatternMatch} in the context of the | ||
76 | * underlying model's current internal state. | ||
77 | * | ||
78 | * @return an arbitrary {@link Object} that can be used as the identifier in the given state. | ||
79 | */ | ||
80 | Object createActivationCode(IPatternMatch match); | ||
81 | |||
82 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java new file mode 100644 index 00000000..cf8bdf8d --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java | |||
@@ -0,0 +1,29 @@ | |||
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.statecode; | ||
10 | |||
11 | /** | ||
12 | * Interface for a factory class that creates instances of {@link IStateCoder} objects. This is required because state | ||
13 | * coders have to be created on-demand if the design space exploration process decides that a new thread is to be | ||
14 | * spawned. Since each thread requires it's own working model instance and a state coder is linked to the underlying | ||
15 | * model, a new {@link IStateCoder} needs to be created per processing thread. | ||
16 | * | ||
17 | * @author Miklos Foldenyi, Andras Szabolcs Nagy | ||
18 | * | ||
19 | */ | ||
20 | public interface IStateCoderFactory { | ||
21 | |||
22 | /** | ||
23 | * Creates a new {@link IStateCoder} instance specific to this {@link IStateCoderFactory}. | ||
24 | * | ||
25 | * @return the new {@link IStateCoder} instance specific to this working model. | ||
26 | */ | ||
27 | IStateCoder createStateCoder(); | ||
28 | |||
29 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java new file mode 100644 index 00000000..afcba7b6 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java | |||
@@ -0,0 +1,45 @@ | |||
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.statecoding; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | |||
13 | import org.eclipse.emf.common.notify.Notifier; | ||
14 | import org.eclipse.emf.ecore.EClass; | ||
15 | import org.eclipse.emf.ecore.EObject; | ||
16 | |||
17 | /** | ||
18 | * Implementation of this interface is responsible to provide {@link EObject}s of a given {@link EClass} for | ||
19 | * {@link TheStateCoder} | ||
20 | * | ||
21 | * @author Andras Szabolcs Nagy | ||
22 | * | ||
23 | */ | ||
24 | public interface IObjectsProvider { | ||
25 | |||
26 | /** | ||
27 | * Initialize the {@link IObjectsProvider} on a given model and {@link StatecodingDependencyGraph}. | ||
28 | * | ||
29 | * @param notifier | ||
30 | * The root of the model. | ||
31 | * @param statecodingDependencyGraph | ||
32 | * The state coding dependency graph. | ||
33 | */ | ||
34 | void init(Notifier notifier, StatecodingDependencyGraph statecodingDependencyGraph); | ||
35 | |||
36 | /** | ||
37 | * Returns the instances of an {@link EClass} in a model. | ||
38 | * | ||
39 | * @param eClass | ||
40 | * The class of the objects. | ||
41 | * @return The collection of the instances. | ||
42 | */ | ||
43 | Collection<EObject> getEObjects(EClass eClass); | ||
44 | |||
45 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java new file mode 100644 index 00000000..931eb1a2 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java | |||
@@ -0,0 +1,25 @@ | |||
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.statecoding; | ||
10 | |||
11 | /** | ||
12 | * Interface for creating {@link IObjectsProvider} instances. | ||
13 | * | ||
14 | * @author Andras Szabolcs Nagy | ||
15 | */ | ||
16 | public interface IObjectsProviderFactory { | ||
17 | |||
18 | /** | ||
19 | * Creates an {@link IObjectsProvider} implementation. | ||
20 | * | ||
21 | * @return The newly created {@link IObjectsProvider}. | ||
22 | */ | ||
23 | IObjectsProvider createObjectsProvider(); | ||
24 | |||
25 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java new file mode 100644 index 00000000..e38d45d3 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java | |||
@@ -0,0 +1,60 @@ | |||
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.statecoding; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashSet; | ||
13 | import java.util.Set; | ||
14 | |||
15 | import org.apache.log4j.Logger; | ||
16 | import org.eclipse.emf.common.notify.Notifier; | ||
17 | import org.eclipse.emf.ecore.EClass; | ||
18 | import org.eclipse.emf.ecore.EObject; | ||
19 | import org.eclipse.viatra.dse.api.DSEException; | ||
20 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
21 | import org.eclipse.viatra.query.runtime.base.api.IndexingLevel; | ||
22 | import org.eclipse.viatra.query.runtime.base.api.NavigationHelper; | ||
23 | import org.eclipse.viatra.query.runtime.emf.EMFScope; | ||
24 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
25 | |||
26 | public class IncrementalObjectProvider implements IObjectsProvider { | ||
27 | |||
28 | private Logger logger = Logger.getLogger(getClass()); | ||
29 | private NavigationHelper baseIndex; | ||
30 | |||
31 | @Override | ||
32 | public void init(Notifier notifier, StatecodingDependencyGraph statecodingDependencyGraph) { | ||
33 | |||
34 | try { | ||
35 | EMFScope scope = new EMFScope(notifier); | ||
36 | ViatraQueryEngine queryEngine = ViatraQueryEngine.on(scope); | ||
37 | |||
38 | Set<EClass> classes = new HashSet<EClass>(); | ||
39 | // Set<EReference> references = new HashSet<EReference>(); | ||
40 | for (StatecodingNode node : statecodingDependencyGraph.getNodes()) { | ||
41 | classes.add(node.getClazz()); | ||
42 | // for (StatecodingDependency dependency : node.getStatecodingDependencies()) { | ||
43 | // // TODO inverse reference | ||
44 | // references.add(dependency.eReference); | ||
45 | // } | ||
46 | } | ||
47 | baseIndex = EMFScope.extractUnderlyingEMFIndex(queryEngine); | ||
48 | baseIndex.registerEClasses(classes, IndexingLevel.FULL); | ||
49 | } catch (ViatraQueryException e) { | ||
50 | logger.error("Failed to initialize VIATRA Query engine on the given notifier", e); | ||
51 | throw new DSEException("Failed to initialize VIATRA Query engine on the given notifier"); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public Collection<EObject> getEObjects(EClass eClass) { | ||
57 | return baseIndex.getAllInstances(eClass); | ||
58 | } | ||
59 | |||
60 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProviderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProviderFactory.java new file mode 100644 index 00000000..97011436 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProviderFactory.java | |||
@@ -0,0 +1,18 @@ | |||
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.statecoding; | ||
10 | |||
11 | public class IncrementalObjectProviderFactory implements IObjectsProviderFactory { | ||
12 | |||
13 | @Override | ||
14 | public IncrementalObjectProvider createObjectsProvider() { | ||
15 | return new IncrementalObjectProvider(); | ||
16 | } | ||
17 | |||
18 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependency.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependency.java new file mode 100644 index 00000000..67b1982d --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependency.java | |||
@@ -0,0 +1,33 @@ | |||
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.statecoding; | ||
10 | |||
11 | import org.eclipse.emf.ecore.EReference; | ||
12 | |||
13 | public class StatecodingDependency { | ||
14 | |||
15 | protected EReference eReference; | ||
16 | protected StatecodingNode node; | ||
17 | protected boolean isContained; | ||
18 | protected StatecodingDependencyType type; | ||
19 | |||
20 | public StatecodingDependency(EReference eReference, StatecodingNode node, boolean isContained, | ||
21 | StatecodingDependencyType type) { | ||
22 | super(); | ||
23 | this.eReference = eReference; | ||
24 | this.node = node; | ||
25 | this.isContained = isContained; | ||
26 | this.type = type; | ||
27 | } | ||
28 | |||
29 | public StatecodingDependency(EReference eReference, StatecodingNode node) { | ||
30 | this(eReference, node, false, StatecodingDependencyType.NORMAL); | ||
31 | } | ||
32 | |||
33 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyGraph.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyGraph.java new file mode 100644 index 00000000..6f7255a3 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyGraph.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.statecoding; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.List; | ||
13 | |||
14 | import org.eclipse.emf.ecore.EClass; | ||
15 | |||
16 | public class StatecodingDependencyGraph { | ||
17 | |||
18 | private List<StatecodingNode> nodes = new ArrayList<StatecodingNode>(); | ||
19 | |||
20 | public StatecodingNode createNode(EClass clazz) { | ||
21 | StatecodingNode node = new StatecodingNode(clazz); | ||
22 | node.setGraph(this); | ||
23 | addNode(node); | ||
24 | return node; | ||
25 | } | ||
26 | |||
27 | public void addNode(StatecodingNode node) { | ||
28 | nodes.add(node); | ||
29 | } | ||
30 | |||
31 | public StatecodingNode getNodeByClass(EClass eClass) { | ||
32 | for (StatecodingNode node : nodes) { | ||
33 | if (node.getClazz().equals(eClass)) { | ||
34 | return node; | ||
35 | } | ||
36 | } | ||
37 | return null; | ||
38 | } | ||
39 | |||
40 | public List<StatecodingNode> getNodes() { | ||
41 | return nodes; | ||
42 | } | ||
43 | |||
44 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyType.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyType.java new file mode 100644 index 00000000..bdd4677d --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingDependencyType.java | |||
@@ -0,0 +1,15 @@ | |||
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.statecoding; | ||
10 | |||
11 | public enum StatecodingDependencyType { | ||
12 | |||
13 | NORMAL, | ||
14 | INVERSE | ||
15 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNode.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNode.java new file mode 100644 index 00000000..91fc28cf --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNode.java | |||
@@ -0,0 +1,100 @@ | |||
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.statecoding; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Comparator; | ||
13 | import java.util.List; | ||
14 | import java.util.Set; | ||
15 | import java.util.TreeSet; | ||
16 | |||
17 | import org.eclipse.emf.ecore.EAttribute; | ||
18 | import org.eclipse.emf.ecore.EClass; | ||
19 | import org.eclipse.emf.ecore.EReference; | ||
20 | |||
21 | public class StatecodingNode { | ||
22 | |||
23 | private StatecodingDependencyGraph graph; | ||
24 | |||
25 | private final EClass clazz; | ||
26 | private Set<EAttribute> attributes = new TreeSet<EAttribute>(Comparator.comparing(EAttribute::getName)); | ||
27 | private List<StatecodingDependency> dependencies = new ArrayList<StatecodingDependency>(); | ||
28 | private boolean stateCodeIsId = false; | ||
29 | private StatecodingNodeType statecodingNodeType = StatecodingNodeType.CREATE_AND_DELETE; | ||
30 | |||
31 | public StatecodingNode(EClass clazz) { | ||
32 | this.clazz = clazz; | ||
33 | } | ||
34 | |||
35 | public StatecodingNode withAttribute(EAttribute attribute) { | ||
36 | attributes.add(attribute); | ||
37 | return this; | ||
38 | } | ||
39 | |||
40 | public StatecodingNode withType(StatecodingNodeType type) { | ||
41 | statecodingNodeType = type; | ||
42 | return this; | ||
43 | } | ||
44 | |||
45 | public StatecodingNode withUniqueness() { | ||
46 | stateCodeIsId = true; | ||
47 | return this; | ||
48 | } | ||
49 | |||
50 | public StatecodingNode withDependency(EReference reference, StatecodingNode node) { | ||
51 | dependencies.add(new StatecodingDependency(reference, node)); | ||
52 | return this; | ||
53 | } | ||
54 | |||
55 | public StatecodingNode withInverseDependency(EReference reference, StatecodingNode node) { | ||
56 | dependencies.add(new StatecodingDependency(reference, node, false, StatecodingDependencyType.INVERSE)); | ||
57 | return this; | ||
58 | } | ||
59 | |||
60 | public void addDependency(StatecodingDependency statecodingDependency) { | ||
61 | dependencies.add(statecodingDependency); | ||
62 | } | ||
63 | |||
64 | public EClass getClazz() { | ||
65 | return clazz; | ||
66 | } | ||
67 | |||
68 | public boolean isStateCodeIsId() { | ||
69 | return stateCodeIsId; | ||
70 | } | ||
71 | |||
72 | public void setStateCodeIsId(boolean stateCodeIsId) { | ||
73 | this.stateCodeIsId = stateCodeIsId; | ||
74 | } | ||
75 | |||
76 | public StatecodingNodeType getStatecodingNodeType() { | ||
77 | return statecodingNodeType; | ||
78 | } | ||
79 | |||
80 | public void setStatecodingNodeType(StatecodingNodeType statecodingNodeType) { | ||
81 | this.statecodingNodeType = statecodingNodeType; | ||
82 | } | ||
83 | |||
84 | public Set<EAttribute> getAttributes() { | ||
85 | return attributes; | ||
86 | } | ||
87 | |||
88 | public List<StatecodingDependency> getStatecodingDependencies() { | ||
89 | return dependencies; | ||
90 | } | ||
91 | |||
92 | public StatecodingDependencyGraph getGraph() { | ||
93 | return graph; | ||
94 | } | ||
95 | |||
96 | public void setGraph(StatecodingDependencyGraph graph) { | ||
97 | this.graph = graph; | ||
98 | } | ||
99 | |||
100 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNodeType.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNodeType.java new file mode 100644 index 00000000..c902a7a6 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/StatecodingNodeType.java | |||
@@ -0,0 +1,17 @@ | |||
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.statecoding; | ||
10 | |||
11 | public enum StatecodingNodeType { | ||
12 | |||
13 | FIXED, | ||
14 | ONLY_CREATE, | ||
15 | ONLY_DELETE, | ||
16 | CREATE_AND_DELETE | ||
17 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoder.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoder.java new file mode 100644 index 00000000..4601ff08 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoder.java | |||
@@ -0,0 +1,215 @@ | |||
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.statecoding; | ||
10 | |||
11 | import java.util.Arrays; | ||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | import java.util.Set; | ||
15 | |||
16 | import org.eclipse.emf.common.notify.Notifier; | ||
17 | import org.eclipse.emf.common.util.EList; | ||
18 | import org.eclipse.emf.ecore.EAttribute; | ||
19 | import org.eclipse.emf.ecore.EObject; | ||
20 | import org.eclipse.viatra.dse.api.DSEException; | ||
21 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
22 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
23 | |||
24 | public class TheStateCoder implements IStateCoder { | ||
25 | |||
26 | private StatecodingDependencyGraph sdg; | ||
27 | private IObjectsProvider objectProvider; | ||
28 | |||
29 | public TheStateCoder(StatecodingDependencyGraph sdg, IObjectsProvider objectProvider) { | ||
30 | this.sdg = sdg; | ||
31 | this.objectProvider = objectProvider; | ||
32 | } | ||
33 | |||
34 | @Override | ||
35 | public void init(Notifier notifier) { | ||
36 | // TODO checks | ||
37 | // TODO node sorting based on traversal - in factory | ||
38 | |||
39 | // this.notifier = notifier; | ||
40 | // try { | ||
41 | // EMFScope scope = new EMFScope(notifier); | ||
42 | // queryEngine = ViatraQueryEngine.on(scope); | ||
43 | // } catch (ViatraQueryException e1) { | ||
44 | // logger.error("Failed to initialize VIATRA Query engine on the given notifier", e1); | ||
45 | // throw new DSEException("Failed to initialize VIATRA Query engine on the given notifier"); | ||
46 | // } | ||
47 | |||
48 | objectProvider.init(notifier, sdg); | ||
49 | } | ||
50 | |||
51 | @Override | ||
52 | public String createStateCode() { | ||
53 | |||
54 | StringBuilder sb = new StringBuilder(); | ||
55 | |||
56 | // TODO sort | ||
57 | for (StatecodingNode node : sdg.getNodes()) { | ||
58 | sb.append(node.getClazz().getName()); | ||
59 | sb.append(':'); | ||
60 | sb.append(addStateCode(node)); | ||
61 | sb.append('|'); | ||
62 | } | ||
63 | sb.deleteCharAt(sb.length() - 1); | ||
64 | |||
65 | return sb.toString(); | ||
66 | |||
67 | } | ||
68 | |||
69 | @Override | ||
70 | public Object createActivationCode(IPatternMatch match) { | ||
71 | // TODO root object | ||
72 | // TODO parameterless? | ||
73 | |||
74 | int i = 0; | ||
75 | StringBuilder sb = new StringBuilder(); | ||
76 | Object object; | ||
77 | do { | ||
78 | object = match.get(i++); | ||
79 | if (object != null) { | ||
80 | if (object instanceof EObject) { | ||
81 | EObject eObject = (EObject) object; | ||
82 | sb.append(addStateCode(sdg.getNodeByClass(eObject.eClass()), eObject)); | ||
83 | } else { | ||
84 | // TODO toString or not to toString | ||
85 | } | ||
86 | } | ||
87 | } while (object != null); | ||
88 | |||
89 | return sb.toString(); | ||
90 | } | ||
91 | |||
92 | public String addStateCode(StatecodingNode node, EObject eObject) { | ||
93 | StringBuilder sb = new StringBuilder(); | ||
94 | |||
95 | Set<EAttribute> attributes = node.getAttributes(); | ||
96 | if (!attributes.isEmpty()) { | ||
97 | for (EAttribute eAttribute : attributes) { | ||
98 | // attributes are sorted | ||
99 | // TODO handle collection | ||
100 | sb.append(eObject.eGet(eAttribute)); | ||
101 | sb.append(';'); | ||
102 | } | ||
103 | sb.deleteCharAt(sb.length() - 1); | ||
104 | } | ||
105 | |||
106 | List<StatecodingDependency> dependencies = node.getStatecodingDependencies(); | ||
107 | int dependenciesSize = dependencies.size(); | ||
108 | if (dependenciesSize > 0) { | ||
109 | String[] codeParts = new String[dependenciesSize]; | ||
110 | int i = 0; | ||
111 | for (StatecodingDependency dependency : dependencies) { | ||
112 | String code = addStateCodeFromDependency(dependency, eObject); | ||
113 | codeParts[i++] = code; | ||
114 | } | ||
115 | Arrays.sort(codeParts); | ||
116 | |||
117 | sb.append("("); | ||
118 | sb.append(codeParts[0]); | ||
119 | for (i = 1; i < codeParts.length; i++) { | ||
120 | sb.append(';'); | ||
121 | sb.append(codeParts[i]); | ||
122 | } | ||
123 | sb.append(")"); | ||
124 | } | ||
125 | return sb.toString(); | ||
126 | } | ||
127 | |||
128 | public String addStateCode(StatecodingNode node) { | ||
129 | Collection<EObject> eObjects = objectProvider.getEObjects(node.getClazz()); | ||
130 | int size = eObjects.size(); | ||
131 | |||
132 | if (size > 0) { | ||
133 | String[] codeParts = new String[size]; | ||
134 | int i = 0; | ||
135 | for (EObject eObject : eObjects) { | ||
136 | String code = addStateCode(node, eObject); | ||
137 | codeParts[i++] = code; | ||
138 | } | ||
139 | Arrays.sort(codeParts); | ||
140 | |||
141 | StringBuilder sb = new StringBuilder(); | ||
142 | sb.append(codeParts[0]); | ||
143 | for (i = 1; i < codeParts.length; i++) { | ||
144 | sb.append(';'); | ||
145 | sb.append(codeParts[i]); | ||
146 | } | ||
147 | return sb.toString(); | ||
148 | } | ||
149 | |||
150 | return ""; | ||
151 | } | ||
152 | |||
153 | public String addStateCodeFromDependency(StatecodingDependency sd, EObject eObject) { | ||
154 | |||
155 | if (sd.type.equals(StatecodingDependencyType.NORMAL)) { | ||
156 | |||
157 | Object eReferred = eObject.eGet(sd.eReference); | ||
158 | if (eReferred == null) { | ||
159 | return ""; | ||
160 | } else if (eReferred instanceof EList<?>) { | ||
161 | EList<?> refferedList = (EList<?>) eReferred; | ||
162 | // TODO test | ||
163 | if (!refferedList.isEmpty()) { | ||
164 | |||
165 | String[] codeParts = new String[refferedList.size()]; | ||
166 | int i = 0; | ||
167 | for (Object referredEObject : refferedList) { | ||
168 | String code = addStateCode(sd.node, (EObject) referredEObject); | ||
169 | codeParts[i++] = code; | ||
170 | } | ||
171 | Arrays.sort(codeParts); | ||
172 | |||
173 | StringBuilder sb = new StringBuilder(); | ||
174 | sb.append('['); | ||
175 | sb.append(codeParts[0]); | ||
176 | for (i = 1; i < codeParts.length; i++) { | ||
177 | sb.append(';'); | ||
178 | sb.append(codeParts[i]); | ||
179 | } | ||
180 | sb.append(']'); | ||
181 | return sb.toString(); | ||
182 | |||
183 | } | ||
184 | } else if (eReferred instanceof EObject) { | ||
185 | return addStateCode(sd.node, (EObject) eReferred); | ||
186 | } else { | ||
187 | throw new DSEException("The EObject " + eObject.toString() + " does not have a feature " | ||
188 | + eReferred.toString() + "."); | ||
189 | } | ||
190 | |||
191 | } else { | ||
192 | for (EObject dependentEObject : objectProvider.getEObjects(sd.node.getClazz())) { | ||
193 | Object eReferred = dependentEObject.eGet(sd.eReference); | ||
194 | if (eReferred == null) { | ||
195 | continue; | ||
196 | } else if (eReferred instanceof EList<?>) { | ||
197 | // TODO this is slow, use VIATRA Query | ||
198 | for (Object referredEObject : ((EList<?>) eReferred)) { | ||
199 | if (referredEObject.equals(eObject)) { | ||
200 | return addStateCode(sd.node, (EObject) dependentEObject); | ||
201 | } | ||
202 | } | ||
203 | } else if (eReferred.equals(eObject)) { | ||
204 | // Probably never happens? | ||
205 | return addStateCode(sd.node, (EObject) dependentEObject); | ||
206 | } else { | ||
207 | throw new DSEException("The EObject " + eObject.toString() + " does not have a feature " | ||
208 | + eReferred.toString() + "."); | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | return ""; | ||
214 | } | ||
215 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoderFactory.java new file mode 100644 index 00000000..eeb6e48f --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/TheStateCoderFactory.java | |||
@@ -0,0 +1,40 @@ | |||
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.statecoding; | ||
10 | |||
11 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
12 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
13 | |||
14 | public class TheStateCoderFactory implements IStateCoderFactory { | ||
15 | |||
16 | private StatecodingDependencyGraph sdg; | ||
17 | private IObjectsProviderFactory objectProviderFactory; | ||
18 | |||
19 | public TheStateCoderFactory(StatecodingDependencyGraph sdg) { | ||
20 | this(sdg, new IncrementalObjectProviderFactory()); | ||
21 | } | ||
22 | |||
23 | public TheStateCoderFactory(StatecodingDependencyGraph sdg, IObjectsProviderFactory objectProviderFactory) { | ||
24 | this.sdg = sdg; | ||
25 | this.objectProviderFactory = objectProviderFactory; | ||
26 | |||
27 | // TODO cyclic dependency? - exception | ||
28 | |||
29 | // TODO make plan for traversal | ||
30 | |||
31 | // TODO If the type is FIXED and all dependency is FIXED then do not create state code for it (them) | ||
32 | // This is not true :( e.g. matchmaking - they are fixed, but the references must be encoded | ||
33 | } | ||
34 | |||
35 | @Override | ||
36 | public IStateCoder createStateCoder() { | ||
37 | return new TheStateCoder(sdg, objectProviderFactory.createObjectsProvider()); | ||
38 | } | ||
39 | |||
40 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoder.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoder.java new file mode 100644 index 00000000..0f0759ae --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoder.java | |||
@@ -0,0 +1,250 @@ | |||
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.statecoding.simple; | ||
10 | |||
11 | import java.util.Arrays; | ||
12 | import java.util.Collection; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.HashSet; | ||
15 | import java.util.List; | ||
16 | import java.util.Map; | ||
17 | import java.util.Set; | ||
18 | |||
19 | import org.eclipse.emf.common.notify.Notifier; | ||
20 | import org.eclipse.emf.ecore.EAttribute; | ||
21 | import org.eclipse.emf.ecore.EClass; | ||
22 | import org.eclipse.emf.ecore.EObject; | ||
23 | import org.eclipse.emf.ecore.EReference; | ||
24 | import org.eclipse.emf.ecore.EStructuralFeature; | ||
25 | import org.eclipse.emf.ecore.EStructuralFeature.Setting; | ||
26 | import org.eclipse.viatra.dse.api.DSEException; | ||
27 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
28 | import org.eclipse.viatra.dse.util.EMFHelper.MetaModelElements; | ||
29 | import org.eclipse.viatra.dse.util.ValueComparableEObjectStringMap; | ||
30 | import org.eclipse.viatra.query.runtime.api.IPatternMatch; | ||
31 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
32 | import org.eclipse.viatra.query.runtime.base.api.FeatureListener; | ||
33 | import org.eclipse.viatra.query.runtime.base.api.IndexingLevel; | ||
34 | import org.eclipse.viatra.query.runtime.base.api.InstanceListener; | ||
35 | import org.eclipse.viatra.query.runtime.base.api.NavigationHelper; | ||
36 | import org.eclipse.viatra.query.runtime.emf.EMFBaseIndexWrapper; | ||
37 | import org.eclipse.viatra.query.runtime.emf.EMFScope; | ||
38 | import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; | ||
39 | |||
40 | /** | ||
41 | * | ||
42 | * @author Andras Szabolcs Nagy | ||
43 | * | ||
44 | */ | ||
45 | public class SimpleStateCoder implements IStateCoder { | ||
46 | |||
47 | private Set<EClass> classes; | ||
48 | private Set<EStructuralFeature> features; | ||
49 | private NavigationHelper navigationHelper; | ||
50 | |||
51 | private Map<EClass, Map<EObject, String>> objectCodes; | ||
52 | private int maxDepth; | ||
53 | |||
54 | private Set<EObject> changedOrNewEObjects = new HashSet<EObject>(); | ||
55 | private Set<EObject> deletedClasses = new HashSet<EObject>(); | ||
56 | |||
57 | public SimpleStateCoder(MetaModelElements metaModelElements) { | ||
58 | this.maxDepth = 1; | ||
59 | |||
60 | classes = metaModelElements.classes; | ||
61 | features = new HashSet<EStructuralFeature>(metaModelElements.attributes); | ||
62 | features.addAll(metaModelElements.references); | ||
63 | } | ||
64 | |||
65 | @Override | ||
66 | public void init(Notifier notifier) { | ||
67 | try { | ||
68 | EMFScope scope = new EMFScope(notifier); | ||
69 | ViatraQueryEngine queryEngine = ViatraQueryEngine.on(scope); | ||
70 | EMFBaseIndexWrapper baseIndex = (EMFBaseIndexWrapper) queryEngine.getBaseIndex(); | ||
71 | navigationHelper = baseIndex.getNavigationHelper(); | ||
72 | navigationHelper.registerObservedTypes(classes, null, features, IndexingLevel.FULL); | ||
73 | } catch (ViatraQueryException e) { | ||
74 | throw new DSEException(e); | ||
75 | } | ||
76 | |||
77 | objectCodes = new HashMap<EClass, Map<EObject, String>>(); | ||
78 | for (EClass eClass : classes) { | ||
79 | Map<EObject, String> codes = new ValueComparableEObjectStringMap(); | ||
80 | |||
81 | objectCodes.put(eClass, codes); | ||
82 | |||
83 | for (EObject eObject : navigationHelper.getDirectInstances(eClass)) { | ||
84 | codes.put(eObject, createObjectCodeWithDepth(eObject, maxDepth)); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | navigationHelper.addFeatureListener(features, new FeatureListener() { | ||
89 | |||
90 | @Override | ||
91 | public void featureInserted(EObject host, EStructuralFeature feature, Object value) { | ||
92 | changedOrNewEObjects.add(host); | ||
93 | } | ||
94 | |||
95 | @Override | ||
96 | public void featureDeleted(EObject host, EStructuralFeature feature, Object value) { | ||
97 | changedOrNewEObjects.add(host); | ||
98 | if (value instanceof EObject) { | ||
99 | changedOrNewEObjects.add((EObject) value); | ||
100 | } | ||
101 | } | ||
102 | }); | ||
103 | |||
104 | navigationHelper.addInstanceListener(classes, new InstanceListener() { | ||
105 | |||
106 | @Override | ||
107 | public void instanceInserted(EClass clazz, EObject instance) { | ||
108 | changedOrNewEObjects.add(instance); | ||
109 | } | ||
110 | |||
111 | @Override | ||
112 | public void instanceDeleted(EClass clazz, EObject instance) { | ||
113 | deletedClasses.add(instance); | ||
114 | } | ||
115 | }); | ||
116 | } | ||
117 | |||
118 | private String createObjectCodeWithDepth(EObject eObject, int depth) { | ||
119 | |||
120 | StringBuilder sb = new StringBuilder(); | ||
121 | |||
122 | Collection<EAttribute> attributes = eObject.eClass().getEAllAttributes(); | ||
123 | for (EAttribute eAttribute : attributes) { | ||
124 | Object value = eObject.eGet(eAttribute); | ||
125 | sb.append(value); | ||
126 | sb.append(','); | ||
127 | } | ||
128 | if (!attributes.isEmpty()) { | ||
129 | sb.deleteCharAt(sb.length() - 1); | ||
130 | } | ||
131 | if (depth > 0) { | ||
132 | sb.append('-'); | ||
133 | Collection<EReference> eReferences = eObject.eClass().getEAllReferences(); | ||
134 | for (EReference eReference : eReferences) { | ||
135 | Object value = eObject.eGet(eReference); | ||
136 | if (value == null) { | ||
137 | sb.append("null,"); | ||
138 | } else if (value instanceof EObject) { | ||
139 | sb.append(createObjectCodeWithDepth((EObject) value, depth - 1)); | ||
140 | sb.append(','); | ||
141 | } else { | ||
142 | List<EObject> referencedEObjects = (List<EObject>) value; | ||
143 | if (!referencedEObjects.isEmpty()) { | ||
144 | |||
145 | String[] codes = new String[referencedEObjects.size()]; | ||
146 | int index = 0; | ||
147 | for (EObject referencedEObject : referencedEObjects) { | ||
148 | codes[index++] = createObjectCodeWithDepth(referencedEObject, depth - 1); | ||
149 | } | ||
150 | Arrays.sort(codes); | ||
151 | sb.append('('); | ||
152 | for (String code : codes) { | ||
153 | sb.append(code); | ||
154 | } | ||
155 | sb.append("),"); | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | sb.deleteCharAt(sb.length() - 1); | ||
160 | } | ||
161 | return sb.toString(); | ||
162 | } | ||
163 | |||
164 | @Override | ||
165 | public Object createStateCode() { | ||
166 | |||
167 | refreshObjectCodes(); | ||
168 | |||
169 | StringBuilder sb = new StringBuilder(); | ||
170 | |||
171 | for (EClass eClass : classes) { | ||
172 | |||
173 | Set<EObject> instances = navigationHelper.getDirectInstances(eClass); | ||
174 | |||
175 | if (!instances.isEmpty()) { | ||
176 | |||
177 | sb.append(eClass.getName()); | ||
178 | sb.append(':'); | ||
179 | |||
180 | String[] codesToSort = new String[instances.size()]; | ||
181 | int index = 0; | ||
182 | Map<EObject, String> codes = objectCodes.get(eClass); | ||
183 | for (EObject eObject : instances) { | ||
184 | codesToSort[index++] = codes.get(eObject); | ||
185 | } | ||
186 | Arrays.sort(codesToSort); | ||
187 | for (String string : codesToSort) { | ||
188 | sb.append(string); | ||
189 | sb.append(';'); | ||
190 | } | ||
191 | sb.deleteCharAt(sb.length() - 1); | ||
192 | sb.append('|'); | ||
193 | } | ||
194 | } | ||
195 | if (sb.length() != 0) { | ||
196 | sb.deleteCharAt(sb.length() - 1); | ||
197 | } | ||
198 | return sb.toString(); | ||
199 | } | ||
200 | |||
201 | private void refreshObjectCodes() { | ||
202 | for (EObject eObject : deletedClasses) { | ||
203 | EClass eClass = eObject.eClass(); | ||
204 | objectCodes.get(eClass).remove(eObject); | ||
205 | } | ||
206 | deletedClasses.clear(); | ||
207 | |||
208 | Set<EObject> objectsToRecode = new HashSet<EObject>(); | ||
209 | for (EObject eObject : changedOrNewEObjects) { | ||
210 | objectsToRecode.add(eObject); | ||
211 | for (Setting setting : navigationHelper.getInverseReferences(eObject)) { | ||
212 | objectsToRecode.add(setting.getEObject()); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | for (EObject eObject : objectsToRecode) { | ||
217 | EClass eClass = eObject.eClass(); | ||
218 | objectCodes.get(eClass).put(eObject, createObjectCodeWithDepth(eObject, maxDepth)); | ||
219 | } | ||
220 | changedOrNewEObjects.clear(); | ||
221 | } | ||
222 | |||
223 | @Override | ||
224 | public Object createActivationCode(IPatternMatch match) { | ||
225 | |||
226 | StringBuilder sb = new StringBuilder(); | ||
227 | String[] tokens = match.specification().getFullyQualifiedName().split("\\."); | ||
228 | sb.append(tokens[tokens.length - 1]); | ||
229 | sb.append(':'); | ||
230 | Object param; | ||
231 | for (int i = 0; (param = match.get(i)) != null; i++) { | ||
232 | EObject eObject = (EObject) param; | ||
233 | |||
234 | Collection<EAttribute> attributes = eObject.eClass().getEAllAttributes(); | ||
235 | for (EAttribute eAttribute : attributes) { | ||
236 | Object value = eObject.eGet(eAttribute); | ||
237 | sb.append(value); | ||
238 | sb.append(','); | ||
239 | } | ||
240 | if (!attributes.isEmpty()) { | ||
241 | sb.deleteCharAt(sb.length() - 1); | ||
242 | } | ||
243 | |||
244 | sb.append('|'); | ||
245 | } | ||
246 | sb.deleteCharAt(sb.length() - 1); | ||
247 | return sb.toString().intern(); | ||
248 | } | ||
249 | |||
250 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoderFactory.java new file mode 100644 index 00000000..d776e8a8 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/simple/SimpleStateCoderFactory.java | |||
@@ -0,0 +1,38 @@ | |||
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.statecoding.simple; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.HashSet; | ||
13 | |||
14 | import org.eclipse.emf.ecore.EPackage; | ||
15 | import org.eclipse.viatra.dse.statecode.IStateCoder; | ||
16 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory; | ||
17 | import org.eclipse.viatra.dse.util.EMFHelper; | ||
18 | import org.eclipse.viatra.dse.util.EMFHelper.MetaModelElements; | ||
19 | |||
20 | /** | ||
21 | * | ||
22 | * @author Andras Szabolcs Nagy | ||
23 | * | ||
24 | */ | ||
25 | public class SimpleStateCoderFactory implements IStateCoderFactory { | ||
26 | |||
27 | private MetaModelElements metaModelElements; | ||
28 | |||
29 | public SimpleStateCoderFactory(Collection<EPackage> metaModelPackages) { | ||
30 | metaModelElements = EMFHelper.getAllMetaModelElements(new HashSet<EPackage>(metaModelPackages)); | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public IStateCoder createStateCoder() { | ||
35 | return new SimpleStateCoder(metaModelElements); | ||
36 | } | ||
37 | |||
38 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java new file mode 100644 index 00000000..14b3acfb --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java | |||
@@ -0,0 +1,424 @@ | |||
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.util; | ||
10 | |||
11 | import java.io.IOException; | ||
12 | import java.util.Collections; | ||
13 | import java.util.Comparator; | ||
14 | import java.util.HashMap; | ||
15 | import java.util.HashSet; | ||
16 | import java.util.List; | ||
17 | import java.util.Map; | ||
18 | import java.util.Objects; | ||
19 | import java.util.Set; | ||
20 | import java.util.TreeSet; | ||
21 | |||
22 | import org.apache.log4j.Logger; | ||
23 | import org.eclipse.emf.common.command.BasicCommandStack; | ||
24 | import org.eclipse.emf.common.notify.Notifier; | ||
25 | import org.eclipse.emf.common.util.EList; | ||
26 | import org.eclipse.emf.common.util.URI; | ||
27 | import org.eclipse.emf.ecore.EAttribute; | ||
28 | import org.eclipse.emf.ecore.EClass; | ||
29 | import org.eclipse.emf.ecore.EClassifier; | ||
30 | import org.eclipse.emf.ecore.ENamedElement; | ||
31 | import org.eclipse.emf.ecore.EObject; | ||
32 | import org.eclipse.emf.ecore.EPackage; | ||
33 | import org.eclipse.emf.ecore.EReference; | ||
34 | import org.eclipse.emf.ecore.resource.Resource; | ||
35 | import org.eclipse.emf.ecore.resource.ResourceSet; | ||
36 | import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; | ||
37 | import org.eclipse.emf.ecore.util.EcoreUtil.Copier; | ||
38 | import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; | ||
39 | import org.eclipse.emf.edit.command.AddCommand; | ||
40 | import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; | ||
41 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
42 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
43 | |||
44 | /** | ||
45 | * This class contains static helper methods. | ||
46 | * @author Andras Szabolcs Nagy | ||
47 | */ | ||
48 | public final class EMFHelper { | ||
49 | |||
50 | private static final Logger logger = Logger.getLogger(EMFHelper.class); | ||
51 | |||
52 | private EMFHelper() { | ||
53 | } | ||
54 | |||
55 | public static class EmfHelperException extends RuntimeException { | ||
56 | private static final long serialVersionUID = 7635796550669616626L; | ||
57 | |||
58 | public EmfHelperException(String string) { | ||
59 | super(string); | ||
60 | } | ||
61 | public EmfHelperException(String string, Throwable e) { | ||
62 | super(string, e); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Gets the {@link EditingDomain} of either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
68 | * @param notifier The {@link Notifier}. | ||
69 | * @return The EditingDomain. | ||
70 | */ | ||
71 | public static EditingDomain getEditingDomain(Notifier notifier) { | ||
72 | Objects.requireNonNull(notifier); | ||
73 | if (notifier instanceof EObject) { | ||
74 | EObject eObject = (EObject) notifier; | ||
75 | return AdapterFactoryEditingDomain.getEditingDomainFor(eObject); | ||
76 | } else if (notifier instanceof Resource) { | ||
77 | Resource resource = (Resource) notifier; | ||
78 | EList<EObject> contents = resource.getContents(); | ||
79 | if (contents.isEmpty()) { | ||
80 | return null; | ||
81 | } | ||
82 | return AdapterFactoryEditingDomain.getEditingDomainFor(contents.get(0)); | ||
83 | } else if (notifier instanceof ResourceSet) { | ||
84 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
85 | if (resourceSet.getResources().isEmpty()) { | ||
86 | return null; | ||
87 | } | ||
88 | return getEditingDomain(resourceSet.getResources().get(0)); | ||
89 | } | ||
90 | |||
91 | return null; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Creates (or gets if already exists) an {@link EditingDomain} over the given {@link Notifier}, | ||
96 | * either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
97 | * @param notifier The {@link Notifier}. | ||
98 | * @return The EditingDomain. | ||
99 | */ | ||
100 | public static EditingDomain createEditingDomain(Notifier notifier) { | ||
101 | |||
102 | EditingDomain domain = getEditingDomain(notifier); | ||
103 | if (domain != null) { | ||
104 | return domain; | ||
105 | } | ||
106 | |||
107 | registerExtensionForXmiSerializer("dummyext"); | ||
108 | |||
109 | if (notifier instanceof EObject) { | ||
110 | EObject eObject = (EObject) notifier; | ||
111 | |||
112 | domain = new AdapterFactoryEditingDomain(null, new BasicCommandStack()); | ||
113 | Resource resource = domain.getResourceSet().createResource(URI.createFileURI("dummy.dummyext")); | ||
114 | domain.getCommandStack().execute(new AddCommand(domain, resource.getContents(), eObject)); | ||
115 | |||
116 | return domain; | ||
117 | |||
118 | } else if (notifier instanceof Resource) { | ||
119 | Resource resource = (Resource) notifier; | ||
120 | |||
121 | ResourceSet resourceSet = resource.getResourceSet(); | ||
122 | if (resourceSet != null) { | ||
123 | return new AdapterFactoryEditingDomain(null, new BasicCommandStack(), resourceSet); | ||
124 | } else { | ||
125 | domain = new AdapterFactoryEditingDomain(null, new BasicCommandStack(), (ResourceSet) null); | ||
126 | resourceSet = domain.getResourceSet(); | ||
127 | domain.getCommandStack().execute(new AddCommand(domain, resourceSet.getResources(), resource)); | ||
128 | return domain; | ||
129 | } | ||
130 | |||
131 | } else if (notifier instanceof ResourceSet) { | ||
132 | return new AdapterFactoryEditingDomain(null, new BasicCommandStack(), (ResourceSet) notifier); | ||
133 | } else { | ||
134 | throw new EmfHelperException("Not supported argument type."); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Saves the EMF model (EObject or Resource) into the given file. An {@link XMIResourceFactoryImpl} will be | ||
140 | * registered if not already. | ||
141 | * | ||
142 | * Doesn't throw exception but logs an error if the save was unsuccessful. | ||
143 | * | ||
144 | * @param model Can be an {@link EObject} or a {@link Resource}. | ||
145 | * @param fileName | ||
146 | */ | ||
147 | public static void saveModel(Notifier model, String fileName) { | ||
148 | |||
149 | Objects.requireNonNull(model); | ||
150 | Preconditions.checkArgument(fileName != null && !fileName.isEmpty(), "File name is null or empty."); | ||
151 | |||
152 | int extensionIndex = fileName.lastIndexOf('.'); | ||
153 | |||
154 | Preconditions.checkState(extensionIndex > -1 && extensionIndex != fileName.length() - 1, "Bad file extension."); | ||
155 | |||
156 | String ext = fileName.substring(extensionIndex + 1); | ||
157 | |||
158 | registerExtensionForXmiSerializer(ext); | ||
159 | |||
160 | URI uri = URI.createFileURI(fileName); | ||
161 | Resource resource; | ||
162 | |||
163 | if (model instanceof ResourceSet) { | ||
164 | throw new EmfHelperException("Unsupported type: ResourceSet"); | ||
165 | } else if (model instanceof Resource) { | ||
166 | resource = (Resource) model; | ||
167 | } else if (model instanceof EObject) { | ||
168 | EObject root = (EObject) model; | ||
169 | ResourceSet resSet = new ResourceSetImpl(); | ||
170 | resource = resSet.createResource(uri); | ||
171 | resource.getContents().add(root); | ||
172 | } else { | ||
173 | throw new EmfHelperException("Unkown type: " + model.getClass()); | ||
174 | } | ||
175 | |||
176 | resource.setURI(uri); | ||
177 | saveResource(resource); | ||
178 | } | ||
179 | |||
180 | private static void saveResource(Resource resource) { | ||
181 | try { | ||
182 | resource.save(Collections.emptyMap()); | ||
183 | } catch (IOException e) { | ||
184 | logger.error(e); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Loads a model as a {@link Resource}. In headless mode, don't forget to call XYZPackage.eINSTANCE. | ||
190 | */ | ||
191 | public static Resource loadModel(String fileName) throws IOException { | ||
192 | Preconditions.checkArgument(fileName != null && !fileName.isEmpty(), "File name is null or empty."); | ||
193 | int extensionIndex = fileName.lastIndexOf('.'); | ||
194 | Preconditions.checkState(extensionIndex > -1 && extensionIndex != fileName.length() - 1, "Bad file extension."); | ||
195 | |||
196 | String ext = fileName.substring(extensionIndex + 1); | ||
197 | registerExtensionForXmiSerializer(ext); | ||
198 | |||
199 | ResourceSetImpl rSet = new ResourceSetImpl(); | ||
200 | URI fileUri = URI.createFileURI(fileName); | ||
201 | Resource resource = rSet.createResource(fileUri); | ||
202 | |||
203 | resource.load(null); | ||
204 | return resource; | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * Retrieves the root EObject from a Resource or ResourceSet. | ||
209 | * <ul> | ||
210 | * <li>Returns null if there is no content.</li> | ||
211 | * <li>Returns the notifier itself if it is an EObject.</li> | ||
212 | * <li>Logs a warn if there are multiple roots.</li> | ||
213 | * </ul> | ||
214 | * | ||
215 | * @param notifier | ||
216 | * @return The root EObject or null. | ||
217 | */ | ||
218 | public static EObject getRootEObject(Notifier notifier) { | ||
219 | if (notifier instanceof EObject) { | ||
220 | return (EObject) notifier; | ||
221 | } else if (notifier instanceof Resource) { | ||
222 | Resource resource = (Resource) notifier; | ||
223 | List<EObject> contents = resource.getContents(); | ||
224 | if (contents.size() > 1) { | ||
225 | logger.warn("Resource has more than one root."); | ||
226 | } | ||
227 | if (contents.isEmpty()) { | ||
228 | return null; | ||
229 | } else { | ||
230 | return contents.get(0); | ||
231 | } | ||
232 | } else if (notifier instanceof ResourceSet) { | ||
233 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
234 | List<Resource> resources = resourceSet.getResources(); | ||
235 | if (resources.size() > 1) { | ||
236 | logger.warn("ResourceSet has more than one resources."); | ||
237 | } | ||
238 | if (resources.isEmpty()) { | ||
239 | return null; | ||
240 | } else { | ||
241 | return getRootEObject(resources.get(0)); | ||
242 | } | ||
243 | } else { | ||
244 | throw new EmfHelperException("Unkown type: " + notifier.getClass()); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Registers an {@link XMIResourceFactoryImpl} for the given extension. | ||
250 | * @param ext The extension as a String. | ||
251 | */ | ||
252 | public static void registerExtensionForXmiSerializer(String ext) { | ||
253 | Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; | ||
254 | Map<String, Object> m = reg.getExtensionToFactoryMap(); | ||
255 | m.computeIfAbsent(ext, e -> new XMIResourceFactoryImpl()); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * Clones the given model. Either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
260 | * @param notifier The root container of the model. | ||
261 | * @return The cloned model. | ||
262 | */ | ||
263 | public static Notifier clone(Notifier notifier) { | ||
264 | Copier copier = new Copier(); | ||
265 | Notifier clonedModel = clone(notifier, copier, null); | ||
266 | copier.copyReferences(); | ||
267 | return clonedModel; | ||
268 | } | ||
269 | |||
270 | private static Notifier clone(Notifier notifier, Copier copier, ResourceSet resourceSetToCloneTo) { | ||
271 | Objects.requireNonNull(copier); | ||
272 | |||
273 | if (notifier instanceof EObject) { | ||
274 | EObject eObject = (EObject) notifier; | ||
275 | return copier.copy(eObject); | ||
276 | } else if (notifier instanceof Resource) { | ||
277 | Resource resource = (Resource) notifier; | ||
278 | ResourceSet rSetTemp = resourceSetToCloneTo; | ||
279 | if (resourceSetToCloneTo == null) { | ||
280 | rSetTemp = new ResourceSetImpl(); | ||
281 | } | ||
282 | Resource clonedResource = rSetTemp.createResource(URI.createFileURI("dummy.dummyext")); | ||
283 | |||
284 | for (EObject eObject : resource.getContents()) { | ||
285 | EObject clonedEObject = copier.copy(eObject); | ||
286 | clonedResource.getContents().add(clonedEObject); | ||
287 | } | ||
288 | |||
289 | return clonedResource; | ||
290 | } else if (notifier instanceof ResourceSet) { | ||
291 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
292 | ResourceSetImpl clonedResourceSet = new ResourceSetImpl(); | ||
293 | |||
294 | for (Resource resource : resourceSet.getResources()) { | ||
295 | clone(resource, copier, clonedResourceSet); | ||
296 | } | ||
297 | |||
298 | return clonedResourceSet; | ||
299 | } else { | ||
300 | throw new EmfHelperException("Not supported argument type."); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | public static class ENamedElementComparator implements Comparator<ENamedElement> { | ||
305 | @Override | ||
306 | public int compare(ENamedElement eClass1, ENamedElement eClass2) { | ||
307 | return eClass1.getName().compareTo(eClass2.getName()); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * This class is used to store | ||
313 | * <ul> | ||
314 | * <li>{@link EClass}es,</li> | ||
315 | * <li>{@link EAttribute}s,</li> | ||
316 | * <li>{@link EReference}s,</li> | ||
317 | * <li>EAttributes by EClasses,</li> | ||
318 | * <li>EReferences by EClasses</li> | ||
319 | * </ul> | ||
320 | * for a given set of {@link EPackage}s. | ||
321 | * | ||
322 | */ | ||
323 | public static class MetaModelElements { | ||
324 | public Set<EPackage> metaModelPackages; | ||
325 | public Set<EClass> classes; | ||
326 | public Set<EAttribute> attributes; | ||
327 | public Set<EReference> references; | ||
328 | public Map<EClass, Set<EAttribute>> attributesOfClass; | ||
329 | public Map<EClass, Set<EReference>> referencesOfClass; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * Traverses the full metamodel on the given {@link EPackage}s and returns all the classes, attributes and | ||
334 | * references it contains. | ||
335 | * | ||
336 | * @param metaModelPackages | ||
337 | * The set of {@link EPackage}s. | ||
338 | * @return A {@link MetaModelElements} instance containing the metamodel elements. | ||
339 | */ | ||
340 | public static MetaModelElements getAllMetaModelElements(Set<EPackage> metaModelPackages) { | ||
341 | return getMetaModelElements(metaModelPackages, true, true, true); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#classes}. | ||
346 | * | ||
347 | * @param metaModelPackages | ||
348 | * The set of {@link EPackage}s. | ||
349 | * @return AA {@link MetaModelElements} instance. | ||
350 | */ | ||
351 | public static MetaModelElements getClasses(Set<EPackage> metaModelPackages) { | ||
352 | return getMetaModelElements(metaModelPackages, true, false, false); | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#references} and | ||
357 | * {@link MetaModelElements#referencesOfClass}. | ||
358 | * | ||
359 | * @param metaModelPackages | ||
360 | * The set of {@link EPackage}s. | ||
361 | * @return AA {@link MetaModelElements} instance. | ||
362 | */ | ||
363 | public static MetaModelElements getReferences(Set<EPackage> metaModelPackages) { | ||
364 | return getMetaModelElements(metaModelPackages, false, true, false); | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#attributes} and | ||
369 | * {@link MetaModelElements#attributesOfClass}. | ||
370 | * | ||
371 | * @param metaModelPackages | ||
372 | * The set of {@link EPackage}s. | ||
373 | * @return AA {@link MetaModelElements} instance. | ||
374 | */ | ||
375 | public static MetaModelElements getAttrbiutes(Set<EPackage> metaModelPackages) { | ||
376 | return getMetaModelElements(metaModelPackages, false, false, true); | ||
377 | } | ||
378 | |||
379 | private static MetaModelElements getMetaModelElements(Set<EPackage> metaModelPackages, boolean getClasses, | ||
380 | boolean getReferences, boolean getAttrbiutes) { | ||
381 | |||
382 | Comparator<ENamedElement> comparator = new ENamedElementComparator(); | ||
383 | |||
384 | MetaModelElements result = new MetaModelElements(); | ||
385 | result.metaModelPackages = metaModelPackages; | ||
386 | if (getClasses) { | ||
387 | result.classes = new TreeSet<EClass>(comparator); | ||
388 | } | ||
389 | if (getReferences) { | ||
390 | result.references = new HashSet<EReference>(); | ||
391 | result.referencesOfClass = new HashMap<EClass, Set<EReference>>(); | ||
392 | } | ||
393 | if (getAttrbiutes) { | ||
394 | result.attributes = new HashSet<EAttribute>(); | ||
395 | result.attributesOfClass = new HashMap<EClass, Set<EAttribute>>(); | ||
396 | } | ||
397 | for (EPackage ePackage : metaModelPackages) { | ||
398 | for (EClassifier eClassifier : ePackage.getEClassifiers()) { | ||
399 | if (eClassifier instanceof EClass) { | ||
400 | EClass eClass = ((EClass) eClassifier); | ||
401 | if (getClasses) { | ||
402 | result.classes.add(eClass); | ||
403 | } | ||
404 | if (getReferences) { | ||
405 | result.referencesOfClass.put(eClass, new TreeSet<EReference>(comparator)); | ||
406 | for (EReference eReference : eClass.getEAllReferences()) { | ||
407 | result.references.add(eReference); | ||
408 | result.referencesOfClass.get(eClass).add(eReference); | ||
409 | } | ||
410 | } | ||
411 | if (getAttrbiutes) { | ||
412 | result.attributesOfClass.put(eClass, new TreeSet<EAttribute>(comparator)); | ||
413 | for (EAttribute eAttribute : eClass.getEAllAttributes()) { | ||
414 | result.attributes.add(eAttribute); | ||
415 | result.attributesOfClass.get(eClass).add(eAttribute); | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | return result; | ||
422 | } | ||
423 | |||
424 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/Hasher.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/Hasher.java new file mode 100644 index 00000000..0c5d7eba --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/Hasher.java | |||
@@ -0,0 +1,86 @@ | |||
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.util; | ||
10 | |||
11 | import java.math.BigInteger; | ||
12 | import java.security.MessageDigest; | ||
13 | import java.security.NoSuchAlgorithmException; | ||
14 | |||
15 | import org.eclipse.viatra.dse.api.DSEException; | ||
16 | |||
17 | /** | ||
18 | * Utility class that encapsulates a {@link MessageDigest} instance to aid calculating hash values more easily, and to | ||
19 | * reuse a {@link MessageDigest} instance. | ||
20 | * | ||
21 | */ | ||
22 | public final class Hasher { | ||
23 | private MessageDigest md; | ||
24 | |||
25 | private static final int HEX = 16; | ||
26 | |||
27 | private Hasher(MessageDigest md) { | ||
28 | this.md = md; | ||
29 | } | ||
30 | |||
31 | /** | ||
32 | * Calculates and returns a hash value. | ||
33 | * | ||
34 | * @param data | ||
35 | * the data to be hashed in a {@link String}. | ||
36 | * @return the hash value in some {@link String} representation. | ||
37 | */ | ||
38 | public String hash(String data) { | ||
39 | md.update(data.getBytes(), 0, data.length()); | ||
40 | return new String(md.digest()); | ||
41 | } | ||
42 | |||
43 | @SuppressWarnings("unused") | ||
44 | private String alternateHashBest(String data) { | ||
45 | md.update(data.getBytes(), 0, data.length()); | ||
46 | return new String(md.digest()); | ||
47 | } | ||
48 | |||
49 | @SuppressWarnings("unused") | ||
50 | private String alternateHashSecondBest(String data) { | ||
51 | md.update(data.getBytes(), 0, data.length()); | ||
52 | return new BigInteger(1, md.digest()).toString(HEX); | ||
53 | } | ||
54 | |||
55 | @SuppressWarnings("unused") | ||
56 | private String alternateHashThirdBest(String data) { | ||
57 | md.update(data.getBytes(), 0, data.length()); | ||
58 | byte[] array = md.digest(); | ||
59 | StringBuilder sb = new StringBuilder(); | ||
60 | for (int i = 0; i < array.length; i++) { | ||
61 | sb.append(Integer.toHexString((int) array[i])); | ||
62 | } | ||
63 | return sb.toString(); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Returns a {@link Hasher} with an internal {@link MessageDigest} that is based on the protocol named | ||
68 | * {@code protocoll}. | ||
69 | * | ||
70 | * @param protocoll | ||
71 | * the name of the hash algorythm. | ||
72 | * @return the initialized {@link Hasher} | ||
73 | * | ||
74 | * @throws DSEException | ||
75 | * on initialization failure. | ||
76 | */ | ||
77 | public static Hasher getHasher(String protocoll) { | ||
78 | try { | ||
79 | return new Hasher(MessageDigest.getInstance(protocoll)); | ||
80 | } catch (NoSuchAlgorithmException e) { | ||
81 | throw new DSEException(e); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | public static final String SHA1_PROTOCOLL = "SHA-1"; | ||
86 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/ValueComparableEObjectStringMap.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/ValueComparableEObjectStringMap.java new file mode 100644 index 00000000..49af05d1 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/ValueComparableEObjectStringMap.java | |||
@@ -0,0 +1,63 @@ | |||
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.util; | ||
10 | |||
11 | import java.util.Comparator; | ||
12 | import java.util.HashMap; | ||
13 | import java.util.Map; | ||
14 | import java.util.TreeMap; | ||
15 | |||
16 | import org.eclipse.emf.ecore.EObject; | ||
17 | |||
18 | import com.google.common.base.Functions; | ||
19 | import com.google.common.collect.Ordering; | ||
20 | |||
21 | /** | ||
22 | * | ||
23 | * This custom {@link TreeMap} implementation enables to store {@link EObject}-{@link String} pairs sorted by values | ||
24 | * (strings). It works as expected if the map is modified in any way, hence the map will still be sorted by values on | ||
25 | * the new set of entries. | ||
26 | * | ||
27 | * It is allowed to have two entries with the same EObject key (and also with same values). | ||
28 | * | ||
29 | * The short coming of the class is that EObjects are compared to each other by their | ||
30 | * {@link System#identityHashCode(Object)}, which may lead to unexpected errors. | ||
31 | * | ||
32 | * @author Andras Szabolcs Nagy | ||
33 | * | ||
34 | */ | ||
35 | public class ValueComparableEObjectStringMap extends TreeMap<EObject, String> { | ||
36 | |||
37 | private static final class EObjectComparator implements Comparator<EObject> { | ||
38 | @Override | ||
39 | public int compare(EObject o1, EObject o2) { | ||
40 | return Integer.valueOf(System.identityHashCode(o1)).compareTo(Integer.valueOf(System.identityHashCode(o2))); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | private final Map<EObject, String> innerMap; | ||
45 | |||
46 | public ValueComparableEObjectStringMap() { | ||
47 | this(new HashMap<EObject, String>()); | ||
48 | } | ||
49 | |||
50 | private ValueComparableEObjectStringMap(Map<EObject, String> innerMap) { | ||
51 | super(Ordering.natural().onResultOf(Functions.forMap(innerMap)).compound(new EObjectComparator())); | ||
52 | this.innerMap = innerMap; | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public String put(EObject keyEObject, String stringValue) { | ||
57 | if (innerMap.containsKey(keyEObject)) { | ||
58 | remove(keyEObject); | ||
59 | } | ||
60 | innerMap.put(keyEObject, stringValue); | ||
61 | return super.put(keyEObject, stringValue); | ||
62 | } | ||
63 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/DesignSpaceVisualizerOptions.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/DesignSpaceVisualizerOptions.java new file mode 100644 index 00000000..bb8000d5 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/DesignSpaceVisualizerOptions.java | |||
@@ -0,0 +1,56 @@ | |||
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.visualizer; | ||
10 | |||
11 | public class DesignSpaceVisualizerOptions { | ||
12 | |||
13 | public boolean showExplorationTrace = true; | ||
14 | public boolean showStateCodes = true; | ||
15 | public boolean showTransitionCodes = true; | ||
16 | |||
17 | public DesignSpaceVisualizerOptions withOutExploraionTrace() { | ||
18 | showExplorationTrace = false; | ||
19 | return this; | ||
20 | } | ||
21 | |||
22 | public DesignSpaceVisualizerOptions withOutstateCodes() { | ||
23 | showStateCodes = false; | ||
24 | return this; | ||
25 | } | ||
26 | |||
27 | public DesignSpaceVisualizerOptions withOutTransitionCodes() { | ||
28 | showTransitionCodes = false; | ||
29 | return this; | ||
30 | } | ||
31 | |||
32 | public boolean isShowExplorationTrace() { | ||
33 | return showExplorationTrace; | ||
34 | } | ||
35 | |||
36 | public void setShowExplorationTrace(boolean showExplorationTrace) { | ||
37 | this.showExplorationTrace = showExplorationTrace; | ||
38 | } | ||
39 | |||
40 | public boolean isShowStateCodes() { | ||
41 | return showStateCodes; | ||
42 | } | ||
43 | |||
44 | public void setShowStateCodes(boolean showStateCodes) { | ||
45 | this.showStateCodes = showStateCodes; | ||
46 | } | ||
47 | |||
48 | public boolean isShowTransitionCodes() { | ||
49 | return showTransitionCodes; | ||
50 | } | ||
51 | |||
52 | public void setShowTransitionCodes(boolean showTransitionCodes) { | ||
53 | this.showTransitionCodes = showTransitionCodes; | ||
54 | } | ||
55 | |||
56 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IDesignSpaceVisualizer.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IDesignSpaceVisualizer.java new file mode 100644 index 00000000..da598b91 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IDesignSpaceVisualizer.java | |||
@@ -0,0 +1,39 @@ | |||
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.visualizer; | ||
10 | |||
11 | import org.eclipse.viatra.dse.api.DesignSpaceExplorer; | ||
12 | import org.eclipse.viatra.dse.base.ThreadContext; | ||
13 | |||
14 | /** | ||
15 | * | ||
16 | * An implementation of this interface is notified about the traversal of the design space from every traversing thread, | ||
17 | * if registered to the {@link DesignSpaceExplorer}. Its purpose is to able to visualize the design space (a directed | ||
18 | * graph with IDs of the nodes and transitions) and to able to visualize the order of the exploration (the trace of a | ||
19 | * thread). | ||
20 | * | ||
21 | * @author Andras Szabolcs Nagy | ||
22 | * | ||
23 | */ | ||
24 | public interface IDesignSpaceVisualizer extends IExploreEventHandler { | ||
25 | |||
26 | /** | ||
27 | * Initializes the instance with a starting thread's context. Can be called multiple times and concurrently. | ||
28 | * | ||
29 | * @see DesignSpaceVisualizerOptions | ||
30 | * @param context | ||
31 | */ | ||
32 | void init(ThreadContext context); | ||
33 | |||
34 | /** | ||
35 | * Saves the captured data. | ||
36 | */ | ||
37 | void save(); | ||
38 | |||
39 | } | ||
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IExploreEventHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IExploreEventHandler.java new file mode 100644 index 00000000..9f902f31 --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/visualizer/IExploreEventHandler.java | |||
@@ -0,0 +1,40 @@ | |||
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.visualizer; | ||
10 | |||
11 | import org.eclipse.viatra.dse.base.DesignSpaceManager; | ||
12 | |||
13 | /** | ||
14 | * An implementation of this interface is notified about every move in the design space (firing a rule activation or | ||
15 | * undoing it) of a single thread, if registered to the corresponding {@link DesignSpaceManager}. Its methods are called | ||
16 | * synchronously, therefore the implementation can have an impact on the performance. Also note, if the same instance is | ||
17 | * registered to multiple threads ({@link DesignSpaceManager}), it has to be thread safe. | ||
18 | * | ||
19 | * @author Andras Szabolcs Nagy | ||
20 | * | ||
21 | */ | ||
22 | public interface IExploreEventHandler { | ||
23 | |||
24 | /** | ||
25 | * Called by the {@link DesignSpaceManager}, after a rule activation (transition) is fired. Multiple calls with the | ||
26 | * same transition can occur. | ||
27 | * | ||
28 | * @param transition The fired transition. | ||
29 | */ | ||
30 | void transitionFired(Object transition); | ||
31 | |||
32 | /** | ||
33 | * Called by the {@link DesignSpaceManager}, after undoing the previously fired rule activation (transition). | ||
34 | * Multiple calls with the same transition can occur. | ||
35 | * | ||
36 | * @param transition The undone transition. | ||
37 | */ | ||
38 | void undo(Object transition); | ||
39 | |||
40 | } | ||