aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-dse
diff options
context:
space:
mode:
authorLibravatar nagilooh <ficsorattila96@gmail.com>2023-08-02 14:07:35 +0200
committerLibravatar nagilooh <ficsorattila96@gmail.com>2023-08-02 14:07:35 +0200
commitc93d455d2459c2fbe0cfce7693d592986f65d44c (patch)
treecd29acd462c7934ed26ba1a7370b721033841e63 /subprojects/store-dse
parentMerge remote-tracking branch 'origin/main' into design-space-exploration (diff)
downloadrefinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.tar.gz
refinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.tar.zst
refinery-c93d455d2459c2fbe0cfce7693d592986f65d44c.zip
Move DSE to new subproject
Diffstat (limited to 'subprojects/store-dse')
-rw-r--r--subprojects/store-dse/build.gradle.kts16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java9
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java61
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java43
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java6
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java8
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java9
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java283
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java62
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java57
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java84
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java51
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java131
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java25
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java21
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java100
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java58
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java190
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java108
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java274
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java117
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java487
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java403
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java57
24 files changed, 2660 insertions, 0 deletions
diff --git a/subprojects/store-dse/build.gradle.kts b/subprojects/store-dse/build.gradle.kts
new file mode 100644
index 00000000..bb1dee7d
--- /dev/null
+++ b/subprojects/store-dse/build.gradle.kts
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 api(project(":refinery-store-query"))
13 api(project(":refinery-store-query-viatra"))
14 api(project(":refinery-store-reasoning"))
15 api(project(":refinery-visualization"))
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java
new file mode 100644
index 00000000..2af22963
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.dse;
2
3import org.eclipse.collections.api.block.procedure.Procedure;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.tuple.Tuple;
6
7public interface ActionFactory {
8 Procedure<Tuple> prepare(Model model);
9}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java
new file mode 100644
index 00000000..729a6fc9
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java
@@ -0,0 +1,61 @@
1package tools.refinery.store.dse;
2
3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.map.Version;
5import tools.refinery.store.dse.internal.Activation;
6import tools.refinery.store.dse.internal.DesignSpaceExplorationBuilderImpl;
7import tools.refinery.store.dse.objectives.Fitness;
8import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.tuple.Tuple1;
11
12import java.util.Collection;
13import java.util.List;
14import java.util.Random;
15
16public interface DesignSpaceExplorationAdapter extends ModelAdapter {
17 @Override
18 DesignSpaceExplorationStoreAdapter getStoreAdapter();
19
20 static DesignSpaceExplorationBuilder builder() {
21 return new DesignSpaceExplorationBuilderImpl();
22 }
23
24 Collection<Version> explore();
25
26 public int getModelSize();
27
28 public Tuple1 createObject();
29
30 public Tuple deleteObject(Tuple tuple);
31
32 public boolean checkGlobalConstraints();
33
34 public boolean backtrack();
35
36 public Fitness calculateFitness();
37
38 public void newSolution();
39
40 public int getDepth();
41
42 public Collection<Activation> getUntraversedActivations();
43
44 public boolean fireActivation(Activation activation);
45
46 public void fireRandomActivation();
47
48 public boolean isCurrentInTrajectory();
49
50 public List<Version> getTrajectory();
51
52 public boolean isCurrentStateAlreadyTraversed();
53
54 public ObjectiveComparatorHelper getObjectiveComparatorHelper();
55
56 public void restoreTrajectory(List<Version> trajectory);
57
58 public void setRandom(Random random);
59
60 public void setRandom(long seed);
61}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java
new file mode 100644
index 00000000..8ca0037d
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java
@@ -0,0 +1,43 @@
1package tools.refinery.store.dse;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.query.dnf.RelationalQuery;
5import tools.refinery.store.dse.internal.TransformationRule;
6import tools.refinery.store.dse.objectives.Objective;
7
8import java.util.Collection;
9import java.util.List;
10
11public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder {
12 default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) {
13 return transformations(List.of(transformationRules));
14 }
15
16 default DesignSpaceExplorationBuilder transformations(Collection<? extends TransformationRule> transformationRules) {
17 transformationRules.forEach(this::transformation);
18 return this;
19 }
20
21 default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) {
22 return globalConstraints(List.of(globalConstraints));
23 }
24
25 default DesignSpaceExplorationBuilder globalConstraints(Collection<RelationalQuery> globalConstraints) {
26 globalConstraints.forEach(this::globalConstraint);
27 return this;
28 }
29
30 default DesignSpaceExplorationBuilder objectives(Objective... objectives) {
31 return objectives(List.of(objectives));
32 }
33
34 default DesignSpaceExplorationBuilder objectives(Collection<? extends Objective> objectives) {
35 objectives.forEach(this::objective);
36 return this;
37 }
38
39 DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule);
40 DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint);
41 DesignSpaceExplorationBuilder objective(Objective objective);
42 DesignSpaceExplorationBuilder strategy(Strategy strategy);
43}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java
new file mode 100644
index 00000000..5964cd82
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java
@@ -0,0 +1,6 @@
1package tools.refinery.store.dse;
2
3import tools.refinery.store.adapter.ModelStoreAdapter;
4
5public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter {
6}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java
new file mode 100644
index 00000000..cef43386
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java
@@ -0,0 +1,8 @@
1package tools.refinery.store.dse;
2
3public interface Strategy {
4
5 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter);
6
7 public void explore();
8}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java
new file mode 100644
index 00000000..f1de00e6
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.dse.internal;
2
3import tools.refinery.store.tuple.Tuple;
4
5public record Activation(TransformationRule transformationRule, Tuple activation) {
6 public boolean fire() {
7 return transformationRule.fireActivation(activation);
8 }
9}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java
new file mode 100644
index 00000000..5fb54da9
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java
@@ -0,0 +1,283 @@
1package tools.refinery.store.dse.internal;
2
3import tools.refinery.store.map.Version;
4import tools.refinery.store.model.Interpretation;
5import tools.refinery.store.model.Model;
6import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.dnf.RelationalQuery;
8import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
9import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter;
10import tools.refinery.store.dse.Strategy;
11import tools.refinery.store.dse.objectives.Fitness;
12import tools.refinery.store.dse.objectives.Objective;
13import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
14import tools.refinery.store.query.resultset.ResultSet;
15import tools.refinery.store.representation.Symbol;
16import tools.refinery.store.tuple.Tuple;
17import tools.refinery.store.tuple.Tuple1;
18import tools.refinery.visualization.ModelVisualizerAdapter;
19
20import java.util.*;
21
22public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter {
23 static final Symbol<Integer> NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0);
24 private final Model model;
25 private final ModelQueryAdapter queryEngine;
26 private final DesignSpaceExplorationStoreAdapterImpl storeAdapter;
27 private final LinkedHashSet<TransformationRule> transformationRules;
28 private final LinkedHashSet<RelationalQuery> globalConstraints;
29 private final List<Objective> objectives;
30 private final LinkedHashSet<ResultSet<Boolean>> globalConstraintResultSets = new LinkedHashSet<>();
31 private final Interpretation<Integer> sizeInterpretation;
32 private final Strategy strategy;
33
34 private ObjectiveComparatorHelper objectiveComparatorHelper;
35 private List<Version> trajectory = new LinkedList<>();
36 private Fitness lastFitness;
37 private final LinkedHashSet<Version> solutions = new LinkedHashSet<>();
38 private Map<Version, LinkedHashSet<Activation>> statesAndUntraversedActivations;
39 private Map<Version, LinkedHashSet<Activation>> statesAndTraversedActivations;
40 private Random random = new Random();
41 private boolean isNewState = false;
42 private final boolean isVisualizationEnabled;
43 private final ModelVisualizerAdapter modelVisualizerAdapter;
44
45 public List<Version> getTrajectory() {
46 return new LinkedList<>(trajectory);
47 }
48
49 public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) {
50 this.model = model;
51 this.storeAdapter = storeAdapter;
52 this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL);
53 queryEngine = model.getAdapter(ModelQueryAdapter.class);
54
55 globalConstraints = storeAdapter.getGlobalConstraints();
56 for (var constraint : globalConstraints) {
57 globalConstraintResultSets.add(queryEngine.getResultSet(constraint));
58 }
59
60 transformationRules = storeAdapter.getTransformationSpecifications();
61 for (var rule : transformationRules) {
62 rule.prepare(model, queryEngine);
63 }
64
65 objectives = storeAdapter.getObjectives();
66 statesAndUntraversedActivations = new HashMap<>();
67 statesAndTraversedActivations = new HashMap<>();
68 strategy = storeAdapter.getStrategy();
69 modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null);
70 isVisualizationEnabled = modelVisualizerAdapter != null;
71
72 }
73
74 @Override
75 public Model getModel() {
76 return model;
77 }
78
79 @Override
80 public DesignSpaceExplorationStoreAdapter getStoreAdapter() {
81 return storeAdapter;
82 }
83
84 @Override
85 public LinkedHashSet<Version> explore() {
86 var state = model.commit();
87 trajectory.add(state);
88 statesAndUntraversedActivations.put(state, getAllActivations());
89 statesAndTraversedActivations.put(state, new LinkedHashSet<>());
90 strategy.initStrategy(this);
91 strategy.explore();
92 return solutions;
93 }
94
95 @Override
96 public int getModelSize() {
97 return sizeInterpretation.get(Tuple.of());
98 }
99
100 @Override
101 public Tuple1 createObject() {
102 var newNodeId = getModelSize();
103 sizeInterpretation.put(Tuple.of(), newNodeId + 1);
104 return Tuple.of(newNodeId);
105 }
106
107 @Override
108 public Tuple deleteObject(Tuple tuple) {
109 if (tuple.getSize() != 1) {
110 throw new IllegalArgumentException("Tuple size must be 1");
111 }
112// TODO: implement more efficient deletion
113// if (tuple.get(0) == getModelSize() - 1) {
114// sizeInterpretation.put(Tuple.of(), getModelSize() - 1);
115// }
116 return tuple;
117 }
118
119 @Override
120 public boolean checkGlobalConstraints() {
121 for (var resultSet : globalConstraintResultSets) {
122 if (resultSet.size() > 0) {
123 return false;
124 }
125 }
126 return true;
127 }
128
129 @Override
130 public boolean backtrack() {
131 if (trajectory.size() < 2) {
132 return false;
133 }
134 if (isVisualizationEnabled) {
135 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1),
136 trajectory.get(trajectory.size() - 2), "backtrack");
137 }
138 model.restore(trajectory.get(trajectory.size() - 2));
139 trajectory.remove(trajectory.size() - 1);
140 return true;
141 }
142
143 @Override
144 public void restoreTrajectory(List<Version> trajectory) {
145 model.restore(trajectory.get(trajectory.size() - 1));
146// if (isVisualizationEnabled) {
147// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1),
148// trajectory.get(trajectory.size() - 1), "restore");
149// }
150 this.trajectory = trajectory;
151
152 }
153
154 @Override
155 public void setRandom(Random random) {
156 this.random = random;
157 }
158
159 @Override
160 public void setRandom(long seed) {
161 this.random = new Random(seed);
162 }
163
164 @Override
165 public Fitness calculateFitness() {
166 Fitness result = new Fitness();
167 boolean satisfiesHardObjectives = true;
168 for (Objective objective : objectives) {
169 var fitness = objective.getFitness(this);
170 result.put(objective.getName(), fitness);
171 if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) {
172 satisfiesHardObjectives = false;
173 }
174 }
175 result.setSatisfiesHardObjectives(satisfiesHardObjectives);
176
177 lastFitness = result;
178
179 return result;
180 }
181
182 @Override
183 public void newSolution() {
184 var state = model.getState();
185 solutions.add(state);
186 if (isVisualizationEnabled) {
187 modelVisualizerAdapter.addSolution(state);
188 }
189 }
190
191 @Override
192 public int getDepth() {
193 return trajectory.size() - 1;
194 }
195
196 public LinkedHashSet<Activation> getUntraversedActivations() {
197// return statesAndUntraversedActivations.get(model.getState());
198 LinkedHashSet<Activation> untraversedActivations = new LinkedHashSet<>();
199 for (Activation activation : getAllActivations()) {
200 if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) {
201 untraversedActivations.add(activation);
202 }
203 }
204
205 return untraversedActivations;
206 }
207
208 @Override
209 public boolean fireActivation(Activation activation) {
210 if (activation == null) {
211 return false;
212 }
213 var previousState = model.getState();
214 if (!statesAndUntraversedActivations.get(previousState).contains(activation)) {
215// TODO: throw exception?
216 return false;
217 }
218 if (!activation.fire()) {
219 return false;
220 }
221 statesAndUntraversedActivations.get(previousState).remove(activation);
222 statesAndTraversedActivations.get(previousState).add(activation);
223 var newState = model.commit();
224 trajectory.add(newState);
225 isNewState = !statesAndUntraversedActivations.containsKey(newState);
226 statesAndUntraversedActivations.put(newState, getAllActivations());
227 statesAndTraversedActivations.put(newState, new LinkedHashSet<>());
228 if (isVisualizationEnabled) {
229 if (isNewState) {
230 modelVisualizerAdapter.addState(newState);
231 }
232 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2),
233 trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(),
234 activation.activation());
235 }
236 return true;
237 }
238
239 @Override
240 public void fireRandomActivation() {
241 var activations = getUntraversedActivations();
242 if (activations.isEmpty()) {
243// TODO: throw exception
244 return;
245 }
246 int index = random.nextInt(activations.size());
247 var iterator = activations.iterator();
248 while (index-- > 0) {
249 iterator.next();
250 }
251 var activationId = iterator.next();
252 fireActivation(activationId);
253 }
254
255 @Override
256 public boolean isCurrentInTrajectory() {
257 return trajectory.contains(model.getState());
258 }
259
260 public LinkedHashSet<Activation> getAllActivations() {
261 LinkedHashSet<Activation> result = new LinkedHashSet<>();
262 for (var rule : transformationRules) {
263 result.addAll(rule.getAllActivations());
264 }
265 return result;
266 }
267
268 public boolean isCurrentStateAlreadyTraversed() {
269// TODO: check isomorphism?
270 return !isNewState;
271 }
272
273 public Fitness getLastFitness() {
274 return lastFitness;
275 }
276
277 public ObjectiveComparatorHelper getObjectiveComparatorHelper() {
278 if (objectiveComparatorHelper == null) {
279 objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives);
280 }
281 return objectiveComparatorHelper;
282 }
283}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java
new file mode 100644
index 00000000..03508adc
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java
@@ -0,0 +1,62 @@
1package tools.refinery.store.dse.internal;
2
3import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.model.ModelStoreBuilder;
6import tools.refinery.store.query.dnf.RelationalQuery;
7import tools.refinery.store.dse.DesignSpaceExplorationBuilder;
8import tools.refinery.store.dse.Strategy;
9import tools.refinery.store.dse.objectives.Objective;
10
11import java.util.LinkedHashSet;
12import java.util.LinkedList;
13import java.util.List;
14
15public class DesignSpaceExplorationBuilderImpl
16 extends AbstractModelAdapterBuilder<DesignSpaceExplorationStoreAdapterImpl>
17 implements DesignSpaceExplorationBuilder {
18 private final LinkedHashSet<TransformationRule> transformationSpecifications = new LinkedHashSet<>();
19 private final LinkedHashSet<RelationalQuery> globalConstraints = new LinkedHashSet<>();
20 private final List<Objective> objectives = new LinkedList<>();
21 private Strategy strategy;
22
23 @Override
24 protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) {
25 return new DesignSpaceExplorationStoreAdapterImpl(store, transformationSpecifications, globalConstraints,
26 objectives, strategy);
27 }
28
29 @Override
30 public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) {
31 checkNotConfigured();
32 transformationSpecifications.add(transformationRule);
33 return this;
34 }
35
36 @Override
37 public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) {
38 checkNotConfigured();
39 globalConstraints.add(globalConstraint);
40 return this;
41 }
42
43 @Override
44 public DesignSpaceExplorationBuilder objective(Objective objective) {
45 checkNotConfigured();
46 objectives.add(objective);
47 return this;
48 }
49
50 @Override
51 public DesignSpaceExplorationBuilder strategy(Strategy strategy) {
52 checkNotConfigured();
53 this.strategy = strategy;
54 return this;
55 }
56
57 @Override
58 protected void doConfigure(ModelStoreBuilder storeBuilder) {
59 storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL);
60 super.doConfigure(storeBuilder);
61 }
62}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java
new file mode 100644
index 00000000..b06462ce
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java
@@ -0,0 +1,57 @@
1package tools.refinery.store.dse.internal;
2
3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.dnf.RelationalQuery;
7import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter;
8import tools.refinery.store.dse.Strategy;
9import tools.refinery.store.dse.objectives.Objective;
10
11import java.util.LinkedHashSet;
12import java.util.List;
13
14public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter {
15 private final ModelStore store;
16 private final LinkedHashSet<TransformationRule> transformationSpecifications;
17 private final LinkedHashSet<RelationalQuery> globalConstraints;
18 private final List<Objective> objectives;
19 private final Strategy strategy;
20
21 public DesignSpaceExplorationStoreAdapterImpl(ModelStore store,
22 LinkedHashSet<TransformationRule> transformationSpecifications,
23 LinkedHashSet<RelationalQuery> globalConstraints,
24 List<Objective> objectives, Strategy strategy) {
25 this.store = store;
26 this.transformationSpecifications = transformationSpecifications;
27 this.globalConstraints = globalConstraints;
28 this.objectives = objectives;
29 this.strategy = strategy;
30 }
31
32 @Override
33 public ModelStore getStore() {
34 return store;
35 }
36
37 @Override
38 public ModelAdapter createModelAdapter(Model model) {
39 return new DesignSpaceExplorationAdapterImpl(model, this);
40 }
41
42 public LinkedHashSet<TransformationRule> getTransformationSpecifications() {
43 return transformationSpecifications;
44 }
45
46 public LinkedHashSet<RelationalQuery> getGlobalConstraints() {
47 return globalConstraints;
48 }
49
50 public List<Objective> getObjectives() {
51 return objectives;
52 }
53
54 public Strategy getStrategy() {
55 return strategy;
56 }
57}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java
new file mode 100644
index 00000000..ed2e77f1
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java
@@ -0,0 +1,84 @@
1package tools.refinery.store.dse.internal;
2
3import org.eclipse.collections.api.block.procedure.Procedure;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.RelationalQuery;
7import tools.refinery.store.dse.ActionFactory;
8import tools.refinery.store.query.resultset.OrderedResultSet;
9import tools.refinery.store.query.resultset.ResultSet;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.LinkedHashSet;
13import java.util.Random;
14
15public class TransformationRule {
16
17 private final String name;
18 private final RelationalQuery precondition;
19 private final ActionFactory actionFactory;
20 private Procedure<Tuple> action;
21 private OrderedResultSet<Boolean> activations;
22 private Random random;
23 private ModelQueryAdapter queryEngine;
24
25 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) {
26 this(name, precondition, actionFactory, new Random());
27 }
28
29 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) {
30 this(name, precondition, actionFactory, new Random(seed));
31 }
32
33 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) {
34 this.name = name;
35 this.precondition = precondition;
36 this.actionFactory = actionFactory;
37 this.random = random;
38 }
39 public boolean prepare(Model model, ModelQueryAdapter queryEngine) {
40 action = actionFactory.prepare(model);
41 this.queryEngine = queryEngine;
42 activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition));
43 return true;
44 }
45
46 public boolean fireActivation(Tuple activation) {
47 action.accept(activation);
48 queryEngine.flushChanges();
49 return true;
50 }
51
52 public boolean fireRandomActivation() {
53 return getRandomActivation().fire();
54 }
55
56 public String getName() {
57 return name;
58 }
59
60 public RelationalQuery getPrecondition() {
61 return precondition;
62 }
63
64 public ResultSet<Boolean> getAllActivationsAsSets() {
65 return activations;
66 }
67
68 public LinkedHashSet<Activation> getAllActivations() {
69 var result = new LinkedHashSet<Activation>();
70 var cursor = activations.getAll();
71 while (cursor.move()) {
72 result.add(new Activation(this, cursor.getKey()));
73 }
74 return result;
75 }
76
77 public Activation getRandomActivation() {
78 return new Activation(this, activations.getKey(random.nextInt(activations.size())));
79 }
80
81 public Activation getActivation(int index) {
82 return new Activation(this, activations.getKey(index));
83 }
84}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java
new file mode 100644
index 00000000..82695704
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.dse.objectives;
10
11import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
12
13/**
14 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
15 *
16 * @author Andras Szabolcs Nagy
17 *
18 */
19public class AlwaysSatisfiedDummyHardObjective extends BaseObjective {
20
21 private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
22
23 public AlwaysSatisfiedDummyHardObjective() {
24 super(DEFAULT_NAME);
25 }
26
27 public AlwaysSatisfiedDummyHardObjective(String name) {
28 super(name);
29 }
30
31 @Override
32 public Double getFitness(DesignSpaceExplorationAdapter context) {
33 return 0d;
34 }
35
36 @Override
37 public boolean isHardObjective() {
38 return true;
39 }
40
41 @Override
42 public boolean satisfiesHardObjective(Double fitness) {
43 return true;
44 }
45
46 @Override
47 public Objective createNew() {
48 return this;
49 }
50
51}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java
new file mode 100644
index 00000000..24e3280d
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java
@@ -0,0 +1,131 @@
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 *******************************************************************************/
9package tools.refinery.store.dse.objectives;
10
11import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
12
13import java.util.Comparator;
14import java.util.Objects;
15
16/**
17 * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name,
18 * comparator, level and fitness hard constraint.
19 *
20 * @author Andras Szabolcs Nagy
21 *
22 */
23public abstract class BaseObjective implements Objective {
24
25 protected final String name;
26 protected Comparator<Double> comparator = Comparators.HIGHER_IS_BETTER;
27
28 protected double fitnessConstraint;
29 protected boolean isThereFitnessConstraint = false;
30 protected Comparator<Double> fitnessConstraintComparator;
31
32 public BaseObjective(String name) {
33 Objects.requireNonNull(name, "Name of the objective cannot be null.");
34 this.name = name;
35 }
36
37 @Override
38 public String getName() {
39 return name;
40 }
41
42 @Override
43 public void setComparator(Comparator<Double> comparator) {
44 this.comparator = comparator;
45 }
46
47 @Override
48 public Comparator<Double> getComparator() {
49 return comparator;
50 }
51
52 public BaseObjective withComparator(Comparator<Double> comparator) {
53 setComparator(comparator);
54 return this;
55 }
56
57 /**
58 * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
59 * current state as a solution.
60 *
61 * @param fitnessConstraint
62 * Solutions should be better than this value.
63 * @param fitnessConstraintComparator
64 * {@link Comparator} to determine if the current state is better than the given value.
65 * @return The actual instance to enable builder pattern like usage.
66 */
67 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint,
68 Comparator<Double> fitnessConstraintComparator) {
69 this.fitnessConstraint = fitnessConstraint;
70 this.fitnessConstraintComparator = fitnessConstraintComparator;
71 this.isThereFitnessConstraint = true;
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. The provided comparator will be used.
78 *
79 * @param fitnessConstraint
80 * Solutions should be better than this value.
81 * @return The actual instance to enable builder pattern like usage.
82 */
83 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) {
84 return withHardConstraintOnFitness(fitnessConstraint, null);
85 }
86
87 @Override
88 public void init(DesignSpaceExplorationAdapter context) {
89 if (fitnessConstraintComparator == null) {
90 fitnessConstraintComparator = comparator;
91 }
92 }
93
94 @Override
95 public boolean isHardObjective() {
96 return isThereFitnessConstraint;
97 }
98
99 @Override
100 public boolean satisfiesHardObjective(Double fitness) {
101 if (isThereFitnessConstraint) {
102 int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint);
103 if (compare < 0) {
104 return false;
105 }
106 }
107 return true;
108 }
109
110 @Override
111 public int hashCode() {
112 return name.hashCode();
113 }
114
115 @Override
116 public boolean equals(Object obj) {
117 if (this == obj) {
118 return true;
119 }
120 if (obj instanceof BaseObjective baseObjective) {
121 return name.equals(baseObjective.getName());
122 }
123 return false;
124 }
125
126 @Override
127 public String toString() {
128 return name;
129 }
130
131}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java
new file mode 100644
index 00000000..e64e04e8
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java
@@ -0,0 +1,25 @@
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 *******************************************************************************/
9package tools.refinery.store.dse.objectives;
10
11import java.util.Comparator;
12
13public class Comparators {
14
15 private Comparators() { /*Utility class constructor*/ }
16
17 public static final Comparator<Double> HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2);
18
19 public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1);
20
21 private static final Double ZERO = (double) 0;
22
23 public static final Comparator<Double> DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2));
24
25}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java
new file mode 100644
index 00000000..16caed85
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java
@@ -0,0 +1,21 @@
1package tools.refinery.store.dse.objectives;
2
3import java.util.HashMap;
4
5public class Fitness extends HashMap<String, Double> {
6
7 private boolean satisfiesHardObjectives;
8
9 public boolean isSatisfiesHardObjectives() {
10 return satisfiesHardObjectives;
11 }
12
13 public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) {
14 this.satisfiesHardObjectives = satisfiesHardObjectives;
15 }
16
17 @Override
18 public String toString() {
19 return super.toString() + " hardObjectives=" + satisfiesHardObjectives;
20 }
21}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java
new file mode 100644
index 00000000..4e14c9a3
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java
@@ -0,0 +1,100 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.dse.objectives;
10
11import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
12
13import java.util.Comparator;
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 */
30public interface Objective {
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 DesignSpaceExplorationAdapter}
60 * @return The objective value in double.
61 */
62 Double getFitness(DesignSpaceExplorationAdapter context);
63
64 /**
65 * Initializes the objective. It is called exactly once for every thread starts.
66 *
67 * @param context
68 * The {@link DesignSpaceExplorationAdapter}.
69 */
70 void init(DesignSpaceExplorationAdapter context);
71
72 /**
73 * Returns an instance of the {@link Objective}. 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 Objective createNew();
79
80 /**
81 * Returns true if the objective is a hard objective. In such a case the method
82 * {@link Objective#satisfiesHardObjective(Double)} is called.
83 *
84 * @return True if the objective is a hard objective.
85 * @see Objective#satisfiesHardObjective(Double)
86 * @see Objective
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 Objective
97 */
98 boolean satisfiesHardObjective(Double fitness);
99
100}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java
new file mode 100644
index 00000000..3184b8c4
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java
@@ -0,0 +1,58 @@
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 *******************************************************************************/
9package tools.refinery.store.dse.objectives;
10
11import java.util.List;
12
13/**
14 * This class is responsible to compare and sort fitness values.
15 *
16 * @author András Szabolcs Nagy
17 */
18public class ObjectiveComparatorHelper {
19
20 private final List<Objective> objectives;
21
22 public ObjectiveComparatorHelper(List<Objective> objectives) {
23 this.objectives = objectives;
24 }
25
26 /**
27 * Compares two fitnesses based on dominance. Returns -1 if the second parameter {@code o2} is a better
28 * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates
29 * {@code o2}) and returns 0 if they are non-dominating each other.
30 */
31 public int compare(Fitness o1, Fitness o2) {
32
33 boolean o1HasBetterFitness = false;
34 boolean o2HasBetterFitness = false;
35
36 for (Objective objective : objectives) {
37 String objectiveName = objective.getName();
38 int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName));
39
40 if (sgn < 0) {
41 o2HasBetterFitness = true;
42 }
43 if (sgn > 0) {
44 o1HasBetterFitness = true;
45 }
46 if (o1HasBetterFitness && o2HasBetterFitness) {
47 break;
48 }
49 }
50 if (o2HasBetterFitness) {
51 } else if (o1HasBetterFitness) {
52 return 1;
53 }
54
55 return 0;
56
57 }
58}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java
new file mode 100644
index 00000000..05cc5bac
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java
@@ -0,0 +1,190 @@
1package tools.refinery.store.dse.strategy;
2
3import tools.refinery.store.map.Version;
4import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
5import tools.refinery.store.dse.Strategy;
6import tools.refinery.store.dse.internal.Activation;
7import tools.refinery.store.dse.objectives.Fitness;
8import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
9
10import java.util.Collection;
11import java.util.Iterator;
12import java.util.List;
13import java.util.PriorityQueue;
14
15public class BestFirstStrategy implements Strategy {
16
17 private DesignSpaceExplorationAdapter dseAdapter;
18
19 private int maxDepth;
20 private boolean backTrackIfSolution = true;
21 private boolean onlyBetterFirst = false;
22
23 private PriorityQueue<TrajectoryWithFitness> trajectoriesToExplore;
24
25 private static class TrajectoryWithFitness {
26
27 public List<Version> trajectory;
28 public Fitness fitness;
29
30 public TrajectoryWithFitness(List<Version> trajectory, Fitness fitness) {
31 super();
32 this.trajectory = trajectory;
33 this.fitness = fitness;
34 }
35
36 @Override
37 public String toString() {
38 return trajectory.toString() + fitness.toString();
39 }
40
41 }
42
43 public BestFirstStrategy() {
44 this(-1);
45 }
46
47 public BestFirstStrategy(int maxDepth) {
48 if (maxDepth < 0) {
49 this.maxDepth = Integer.MAX_VALUE;
50 } else {
51 this.maxDepth = maxDepth;
52 }
53 }
54
55 public BestFirstStrategy continueIfHardObjectivesFulfilled() {
56 backTrackIfSolution = false;
57 return this;
58 }
59
60 public BestFirstStrategy goOnOnlyIfFitnessIsBetter() {
61 onlyBetterFirst = true;
62 return this;
63 }
64
65 @Override
66 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
67 this.dseAdapter = designSpaceExplorationAdapter;
68 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
69
70 trajectoriesToExplore = new PriorityQueue<TrajectoryWithFitness>(11,
71 (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness));
72 }
73
74 @Override
75 public void explore() {
76 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
77
78 boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
79 if (!globalConstraintsAreSatisfied) {
80 // "Global constraint is not satisfied in the first state. Terminate.");
81 return;
82 }
83
84 final Fitness firstFitness = dseAdapter.calculateFitness();
85 if (firstFitness.isSatisfiesHardObjectives()) {
86 dseAdapter.newSolution();
87 // "First state is a solution. Terminate.");
88 if (backTrackIfSolution) {
89 return;
90 }
91 }
92
93 if (maxDepth == 0) {
94 return;
95 }
96
97 final List<Version> firstTrajectory = dseAdapter.getTrajectory();
98 TrajectoryWithFitness currentTrajectoryWithFitness = new TrajectoryWithFitness(firstTrajectory, firstFitness);
99 trajectoriesToExplore.add(currentTrajectoryWithFitness);
100
101 mainLoop: while (true) {
102
103 if (currentTrajectoryWithFitness == null) {
104 if (trajectoriesToExplore.isEmpty()) {
105 // "State space is fully traversed.");
106 return;
107 } else {
108 currentTrajectoryWithFitness = trajectoriesToExplore.element();
109// if (logger.isDebugEnabled()) {
110// "New trajectory is chosen: " + currentTrajectoryWithFitness);
111// }
112 dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory);
113 }
114 }
115
116 Collection<Activation> activations = dseAdapter.getUntraversedActivations();
117 Iterator<Activation> iterator = activations.iterator();
118
119
120
121 while (iterator.hasNext()) {
122 final Activation nextActivation = iterator.next();
123 if (!iterator.hasNext()) {
124 // "Last untraversed activation of the state.");
125 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
126 }
127
128// if (logger.isDebugEnabled()) {
129// "Executing new activation: " + nextActivation);
130// }
131 dseAdapter.fireActivation(nextActivation);
132 if (dseAdapter.isCurrentStateAlreadyTraversed()) {
133 // "The new state is already visited.");
134 dseAdapter.backtrack();
135 } else if (!dseAdapter.checkGlobalConstraints()) {
136 // "Global constraint is not satisfied.");
137 dseAdapter.backtrack();
138 } else {
139 final Fitness nextFitness = dseAdapter.calculateFitness();
140 if (nextFitness.isSatisfiesHardObjectives()) {
141 dseAdapter.newSolution();
142 // "Found a solution.");
143 if (backTrackIfSolution) {
144 dseAdapter.backtrack();
145 continue;
146 }
147 }
148 if (dseAdapter.getDepth() >= maxDepth) {
149 // "Reached max depth.");
150 dseAdapter.backtrack();
151 continue;
152 }
153
154 TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness(
155 dseAdapter.getTrajectory(), nextFitness);
156 trajectoriesToExplore.add(nextTrajectoryWithFitness);
157
158 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness,
159 nextTrajectoryWithFitness.fitness);
160 if (compare < 0) {
161 // "Better fitness, moving on: " + nextFitness);
162 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
163 continue mainLoop;
164 } else if (compare == 0) {
165 if (onlyBetterFirst) {
166 // "Equally good fitness, backtrack: " + nextFitness);
167 dseAdapter.backtrack();
168 continue;
169 } else {
170 // "Equally good fitness, moving on: " + nextFitness);
171 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
172 continue mainLoop;
173 }
174 } else {
175 // "Worse fitness.");
176 currentTrajectoryWithFitness = null;
177 continue mainLoop;
178 }
179 }
180 }
181
182 // "State is fully traversed.");
183 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
184 currentTrajectoryWithFitness = null;
185
186 }
187 // "Interrupted.");
188
189 }
190}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java
new file mode 100644
index 00000000..42985013
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java
@@ -0,0 +1,108 @@
1package tools.refinery.store.dse.strategy;
2
3import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
4import tools.refinery.store.dse.Strategy;
5import tools.refinery.store.dse.internal.Activation;
6import tools.refinery.store.dse.objectives.Fitness;
7
8import java.util.Collection;
9
10public class DepthFirstStrategy implements Strategy {
11
12 private DesignSpaceExplorationAdapter dseAdapter;
13
14 private int maxDepth;
15 private boolean backTrackIfSolution = true;
16
17 public DepthFirstStrategy() {
18 this(-1);
19 }
20
21 public DepthFirstStrategy(int maxDepth) {
22 if (maxDepth < 0) {
23 this.maxDepth = Integer.MAX_VALUE;
24 } else {
25 this.maxDepth = maxDepth;
26 }
27 }
28
29 public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
30 backTrackIfSolution = false;
31 return this;
32 }
33
34 @Override
35 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
36 this.dseAdapter = designSpaceExplorationAdapter;
37 }
38
39 @Override
40 public void explore() {
41 mainloop: while (true) {
42 var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
43 if (!globalConstraintsAreSatisfied) {
44 var isSuccessfulUndo = dseAdapter.backtrack();
45 if (!isSuccessfulUndo) {
46// "Global constraint is not satisfied and cannot backtrack."
47 break;
48 }
49 else {
50// "Global constraint is not satisfied, backtrack."
51 continue;
52 }
53 }
54
55 Fitness fitness = dseAdapter.calculateFitness();
56 if (fitness.isSatisfiesHardObjectives()) {
57 dseAdapter.newSolution();
58 if (backTrackIfSolution) {
59 var isSuccessfulUndo = dseAdapter.backtrack();
60 if (!isSuccessfulUndo) {
61// "Found a solution but cannot backtrack."
62 break;
63 } else {
64// "Found a solution, backtrack."
65 continue;
66 }
67 }
68 }
69
70 var depth = dseAdapter.getDepth();
71 if (dseAdapter.getDepth() >= maxDepth) {
72 var isSuccessfulUndo = dseAdapter.backtrack();
73 if (!isSuccessfulUndo) {
74// "Reached max depth but cannot backtrack."
75 break;
76 }
77 }
78
79 Collection<Activation> activations;
80 do {
81 activations = dseAdapter.getUntraversedActivations();
82 if (activations.isEmpty()) {
83 if (!dseAdapter.backtrack()) {
84 // "No more transitions from current state and cannot backtrack."
85 break mainloop;
86 }
87 else {
88 // "No more transitions from current state, backtrack."
89 continue;
90 }
91 }
92 } while (activations.isEmpty());
93
94 dseAdapter.fireRandomActivation();
95// if (dseAdapter.isCurrentInTrajectory()) {
96// if (!dseAdapter.backtrack()) {
97//// TODO: throw exception
98//// "The new state is present in the trajectory but cannot backtrack. Should never happen!"
99// break;
100// }
101// else {
102//// "The new state is already visited in the trajectory, backtrack."
103// continue;
104// }
105// }
106 }
107 }
108}
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java
new file mode 100644
index 00000000..e7cc60d6
--- /dev/null
+++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java
@@ -0,0 +1,274 @@
1package tools.refinery.store.dse;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Query;
7import tools.refinery.store.query.dnf.RelationalQuery;
8import tools.refinery.store.dse.internal.TransformationRule;
9import tools.refinery.store.dse.strategy.BestFirstStrategy;
10import tools.refinery.store.dse.strategy.DepthFirstStrategy;
11import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
12import tools.refinery.store.query.view.AnySymbolView;
13import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.tuple.Tuple;
16import tools.refinery.visualization.ModelVisualizerAdapter;
17import tools.refinery.visualization.internal.FileFormat;
18
19import java.util.List;
20
21import static tools.refinery.store.query.literal.Literals.not;
22
23public class CRAExamplesTest {
24 private static final Symbol<String> name = Symbol.of("Name", 1, String.class);
25
26// private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
27 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
28// private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
29 private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1);
30 private static final Symbol<Boolean> method = Symbol.of("Method", 1);
31
32// private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
33 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
34 private static final Symbol<Boolean> dataDependency = Symbol.of("DataDependency", 2);
35 private static final Symbol<Boolean> functionalDependency = Symbol.of("FunctionalDependency", 2);
36
37 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
38 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
39
40// private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
41 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
42// private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
43 private static final AnySymbolView attributeView = new KeyOnlyView<>(attribute);
44 private static final AnySymbolView methodView = new KeyOnlyView<>(method);
45// private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
46 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
47 private static final AnySymbolView dataDependencyView = new KeyOnlyView<>(dataDependency);
48 private static final AnySymbolView functionalDependencyView = new KeyOnlyView<>(functionalDependency);
49 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
50 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
51
52 /*Example Transformation rules*/
53 private static final RelationalQuery feature = Query.of("Feature",
54 (builder, f) -> builder.clause(
55 attributeView.call(f))
56 .clause(
57 methodView.call(f))
58 );
59
60 private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper",
61 (builder, c, f) -> builder.clause(
62 classElementView.call(c),
63// classesView.call(model, c),
64 encapsulatesView.call(c, f)
65 ));
66
67 private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition",
68 (builder, f, c1) -> builder.clause((c2) -> List.of(
69// classModelView.call(model),
70 feature.call(f),
71 classElementView.call(c1),
72// featuresView.call(model, f),
73 not(assignFeaturePreconditionHelper.call(c2, f)),
74 not(encapsulatesView.call(c1, f))
75 )));
76
77 private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
78 (builder, c) -> builder.clause((f) -> List.of(
79// classModelView.call(model),
80 classElementView.call(c),
81// featuresView.call(model, f),
82 not(encapsulatesView.call(c, f))
83 )));
84
85 private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper",
86 (builder, f, c) -> builder.clause(
87 classElementView.call(c),
88// classesView.call(model, c),
89 encapsulatesView.call(c, f)
90 ));
91
92 private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition",
93 (builder, f) -> builder.clause((c) -> List.of(
94// classModelView.call(model),
95 feature.call(f),
96 not(createClassPreconditionHelper.call(f, c))
97 )));
98
99 private static final RelationalQuery moveFeaturePrecondition = Query.of("MoveFeature",
100 (builder, c1, c2, f) -> builder.clause(
101// classModelView.call(model),
102 classElementView.call(c1),
103 classElementView.call(c2),
104 c1.notEquivalent(c2),
105 feature.call(f),
106// classesView.call(model, c1),
107// classesView.call(model, c2),
108// featuresView.call(model, f),
109 encapsulatesView.call(c1, f)
110 ));
111
112 private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature",
113 assignFeaturePrecondition,
114 (model) -> {
115// var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy);
116 var encapsulatesInterpretation = model.getInterpretation(encapsulates);
117 return ((Tuple activation) -> {
118 var feature = activation.get(0);
119 var classElement = activation.get(1);
120
121// isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true);
122 encapsulatesInterpretation.put(Tuple.of(classElement, feature), true);
123 });
124 });
125
126 private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass",
127 deleteEmptyClassPrecondition,
128 (model) -> {
129// var classesInterpretation = model.getInterpretation(classes);
130 var classElementInterpretation = model.getInterpretation(classElement);
131 return ((Tuple activation) -> {
132 // TODO: can we move dseAdapter outside?
133 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
134// var modelElement = activation.get(0);
135 var classElement = activation.get(0);
136
137// classesInterpretation.put(Tuple.of(modelElement, classElement), false);
138 classElementInterpretation.put(Tuple.of(classElement), false);
139 dseAdapter.deleteObject(Tuple.of(classElement));
140 });
141 });
142
143 private static final TransformationRule createClassRule = new TransformationRule("CreateClass",
144 createClassPrecondition,
145 (model) -> {
146 var classElementInterpretation = model.getInterpretation(classElement);
147// var classesInterpretation = model.getInterpretation(classes);
148 var encapsulatesInterpretation = model.getInterpretation(encapsulates);
149 return ((Tuple activation) -> {
150 // TODO: can we move dseAdapter outside?
151 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
152// var modelElement = activation.get(0);
153 var feature = activation.get(0);
154
155 var newClassElement = dseAdapter.createObject();
156 var newClassElementId = newClassElement.get(0);
157 classElementInterpretation.put(newClassElement, true);
158// classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
159 encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true);
160 });
161 });
162
163 private static final TransformationRule moveFeatureRule = new TransformationRule("MoveFeature",
164 moveFeaturePrecondition,
165 (model) -> {
166 var encapsulatesInterpretation = model.getInterpretation(encapsulates);
167 return ((Tuple activation) -> {
168 var classElement1 = activation.get(0);
169 var classElement2 = activation.get(1);
170 var feature = activation.get(2);
171
172 encapsulatesInterpretation.put(Tuple.of(classElement1, feature), false);
173 encapsulatesInterpretation.put(Tuple.of(classElement2, feature), true);
174 });
175 });
176
177 @Test
178 void craTest() {
179 var store = ModelStore.builder()
180 .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency,
181 functionalDependency, name)
182 .with(ViatraModelQueryAdapter.builder()
183 .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition,
184 deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition,
185 moveFeaturePrecondition))
186 .with(ModelVisualizerAdapter.builder())
187 .with(DesignSpaceExplorationAdapter.builder()
188 .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule)
189// .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled()
190 .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled()
191// .goOnOnlyIfFitnessIsBetter()
192 ))
193 .build();
194
195 var model = store.createEmptyModel();
196 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
197// dseAdapter.setRandom(1);
198 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
199
200// var modelInterpretation = model.getInterpretation(classModel);
201 var nameInterpretation = model.getInterpretation(name);
202 var methodInterpretation = model.getInterpretation(method);
203 var attributeInterpretation = model.getInterpretation(attribute);
204 var dataDependencyInterpretation = model.getInterpretation(dataDependency);
205 var functionalDependencyInterpretation = model.getInterpretation(functionalDependency);
206
207// var modelElement = dseAdapter.createObject();
208 var method1 = dseAdapter.createObject();
209 var method1Id = method1.get(0);
210 var method2 = dseAdapter.createObject();
211 var method2Id = method2.get(0);
212 var method3 = dseAdapter.createObject();
213 var method3Id = method3.get(0);
214 var method4 = dseAdapter.createObject();
215 var method4Id = method4.get(0);
216 var attribute1 = dseAdapter.createObject();
217 var attribute1Id = attribute1.get(0);
218 var attribute2 = dseAdapter.createObject();
219 var attribute2Id = attribute2.get(0);
220 var attribute3 = dseAdapter.createObject();
221 var attribute3Id = attribute3.get(0);
222 var attribute4 = dseAdapter.createObject();
223 var attribute4Id = attribute4.get(0);
224 var attribute5 = dseAdapter.createObject();
225 var attribute5Id = attribute5.get(0);
226
227 nameInterpretation.put(method1, "M1");
228 nameInterpretation.put(method2, "M2");
229 nameInterpretation.put(method3, "M3");
230 nameInterpretation.put(method4, "M4");
231 nameInterpretation.put(attribute1, "A1");
232 nameInterpretation.put(attribute2, "A2");
233 nameInterpretation.put(attribute3, "A3");
234 nameInterpretation.put(attribute4, "A4");
235 nameInterpretation.put(attribute5, "A5");
236
237
238
239// modelInterpretation.put(modelElement, true);
240 methodInterpretation.put(method1, true);
241 methodInterpretation.put(method2, true);
242 methodInterpretation.put(method3, true);
243 methodInterpretation.put(method4, true);
244 attributeInterpretation.put(attribute1, true);
245 attributeInterpretation.put(attribute2, true);
246 attributeInterpretation.put(attribute3, true);
247 attributeInterpretation.put(attribute4, true);
248 attributeInterpretation.put(attribute5, true);
249
250 dataDependencyInterpretation.put(Tuple.of(method1Id, attribute1Id), true);
251 dataDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true);
252 dataDependencyInterpretation.put(Tuple.of(method2Id, attribute2Id), true);
253 dataDependencyInterpretation.put(Tuple.of(method3Id, attribute3Id), true);
254 dataDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true);
255 dataDependencyInterpretation.put(Tuple.of(method4Id, attribute3Id), true);
256 dataDependencyInterpretation.put(Tuple.of(method4Id, attribute5Id), true);
257
258 functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true);
259 functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute4Id), true);
260 functionalDependencyInterpretation.put(Tuple.of(method2Id, attribute1Id), true);
261 functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute1Id), true);
262 functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true);
263 functionalDependencyInterpretation.put(Tuple.of(method4Id, attribute2Id), true);
264
265 queryEngine.flushChanges();
266
267 var states = dseAdapter.explore();
268 System.out.println("states size: " + states.size());
269 System.out.println("states: " + states);
270 var visualizer = model.getAdapter(ModelVisualizerAdapter.class);
271 visualizer.renderDesignSpace("test_output", FileFormat.SVG);
272 }
273
274}
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java
new file mode 100644
index 00000000..911c0661
--- /dev/null
+++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java
@@ -0,0 +1,117 @@
1package tools.refinery.store.dse;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Query;
7import tools.refinery.store.dse.internal.TransformationRule;
8import tools.refinery.store.dse.strategy.BestFirstStrategy;
9import tools.refinery.store.dse.strategy.DepthFirstStrategy;
10import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
11import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.query.view.KeyOnlyView;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15import tools.refinery.visualization.ModelVisualizerAdapter;
16import tools.refinery.visualization.internal.FileFormat;
17
18public class DebugTest {
19 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
20 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
21 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
22
23 private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
24 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
25
26 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
27 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
28
29 private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
30 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
31 private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
32 private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
33 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
34 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
35 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
36
37
38 @Test
39 void BFSTest() {
40 var createClassPrecondition = Query.of("CreateClassPrecondition",
41 (builder, model) -> builder.clause(
42 classModelView.call(model)
43 ));
44
45 var createClassRule = new TransformationRule("CreateClass",
46 createClassPrecondition,
47 (model) -> {
48 var classesInterpretation = model.getInterpretation(classes);
49 var classElementInterpretation = model.getInterpretation(classElement);
50 return ((Tuple activation) -> {
51 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
52 var modelElement = activation.get(0);
53
54 var newClassElement = dseAdapter.createObject();
55 var newClassElementId = newClassElement.get(0);
56
57 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
58 classElementInterpretation.put(Tuple.of(newClassElementId), true);
59 });
60 });
61
62 var createFeaturePrecondition = Query.of("CreateFeaturePrecondition",
63 (builder, model) -> builder.clause(
64 classModelView.call(model)
65 ));
66
67 var createFeatureRule = new TransformationRule("CreateFeature",
68 createFeaturePrecondition,
69 (model) -> {
70 var featuresInterpretation = model.getInterpretation(features);
71 var featureInterpretation = model.getInterpretation(feature);
72 return ((Tuple activation) -> {
73 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
74 var modelElement = activation.get(0);
75
76 var newClassElement = dseAdapter.createObject();
77 var newClassElementId = newClassElement.get(0);
78
79 featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
80 featureInterpretation.put(Tuple.of(newClassElementId), true);
81 });
82 });
83
84 var store = ModelStore.builder()
85 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
86 .with(ViatraModelQueryAdapter.builder()
87 .queries(createClassPrecondition, createFeaturePrecondition))
88 .with(ModelVisualizerAdapter.builder())
89 .with(DesignSpaceExplorationAdapter.builder()
90 .transformations(createClassRule, createFeatureRule)
91 .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled()
92// .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled()
93// .goOnOnlyIfFitnessIsBetter()
94 ))
95 .build();
96
97 var model = store.createEmptyModel();
98 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
99// dseAdapter.setRandom(1);
100 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
101
102 var modelElementInterpretation = model.getInterpretation(classModel);
103 var classElementInterpretation = model.getInterpretation(classElement);
104 var modelElement = dseAdapter.createObject();
105 modelElementInterpretation.put(modelElement, true);
106 classElementInterpretation.put(modelElement, true);
107 queryEngine.flushChanges();
108
109
110 var states = dseAdapter.explore();
111 var visualizer = model.getAdapter(ModelVisualizerAdapter.class);
112 visualizer.renderDesignSpace("test_output", FileFormat.SVG);
113 System.out.println("states size: " + states.size());
114 System.out.println("states: " + states);
115
116 }
117}
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java
new file mode 100644
index 00000000..c454f4ec
--- /dev/null
+++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java
@@ -0,0 +1,487 @@
1package tools.refinery.store.dse;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Query;
7import tools.refinery.store.dse.internal.TransformationRule;
8import tools.refinery.store.dse.strategy.BestFirstStrategy;
9import tools.refinery.store.dse.strategy.DepthFirstStrategy;
10import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
11import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.query.view.KeyOnlyView;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15import tools.refinery.visualization.ModelVisualizerAdapter;
16
17import static org.junit.jupiter.api.Assertions.assertEquals;
18
19public class DesignSpaceExplorationTest {
20// private static final Symbol<Boolean> namedElement = Symbol.of("NamedElement", 1);
21// private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1);
22// private static final Symbol<Boolean> method = Symbol.of("Method", 1);
23// private static final Symbol<Boolean> dataDependency = Symbol.of("DataDependency", 2);
24// private static final Symbol<Boolean> functionalDependency = Symbol.of("FunctionalDependency", 2);
25
26 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
27 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
28 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
29
30 private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
31 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
32
33 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
34 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
35
36 private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
37 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
38 private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
39 private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
40 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
41 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
42 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
43
44 @Test
45 void createObjectTest() {
46 var store = ModelStore.builder()
47 .with(ViatraModelQueryAdapter.builder())
48 .with(DesignSpaceExplorationAdapter.builder())
49 .build();
50
51 var model = store.createEmptyModel();
52 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
53
54 assertEquals(0, dseAdapter.getModelSize());
55
56 var newModel = dseAdapter.createObject();
57 var newModelId = newModel.get(0);
58 var newClass1 = dseAdapter.createObject();
59 var newClass1Id = newClass1.get(0);
60 var newClass2 = dseAdapter.createObject();
61 var newClass2Id = newClass2.get(0);
62 var newField = dseAdapter.createObject();
63 var newFieldId = newField.get(0);
64
65 assertEquals(0, newModelId);
66 assertEquals(1, newClass1Id);
67 assertEquals(2, newClass2Id);
68 assertEquals(3, newFieldId);
69 assertEquals(4, dseAdapter.getModelSize());
70 }
71
72 @Test
73 void deleteMiddleObjectTest() {
74 var store = ModelStore.builder()
75 .with(ViatraModelQueryAdapter.builder())
76 .with(DesignSpaceExplorationAdapter.builder())
77 .build();
78
79 var model = store.createEmptyModel();
80 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
81
82 assertEquals(0, dseAdapter.getModelSize());
83
84 var newObject0 = dseAdapter.createObject();
85 var newObject0Id = newObject0.get(0);
86 var newObject1 = dseAdapter.createObject();
87 var newObject1Id = newObject1.get(0);
88 var newObject2 = dseAdapter.createObject();
89 var newObject2Id = newObject2.get(0);
90 var newObject3 = dseAdapter.createObject();
91 var newObject3Id = newObject3.get(0);
92
93 assertEquals(0, newObject0Id);
94 assertEquals(1, newObject1Id);
95 assertEquals(2, newObject2Id);
96 assertEquals(3, newObject3Id);
97 assertEquals(4, dseAdapter.getModelSize());
98
99 dseAdapter.deleteObject(newObject1);
100 assertEquals(4, dseAdapter.getModelSize());
101
102 var newObject4 = dseAdapter.createObject();
103 var newObject4Id = newObject4.get(0);
104 assertEquals(4, newObject4Id);
105 assertEquals(5, dseAdapter.getModelSize());
106
107 dseAdapter.deleteObject(newObject4);
108 assertEquals(5, dseAdapter.getModelSize());
109 }
110
111 @Test
112 void DFSTrivialTest() {
113 var store = ModelStore.builder()
114 .symbols(classModel)
115 .with(ViatraModelQueryAdapter.builder())
116 .with(ModelVisualizerAdapter.builder())
117 .with(DesignSpaceExplorationAdapter.builder()
118 .strategy(new DepthFirstStrategy(0)))
119 .build();
120
121 var model = store.createEmptyModel();
122 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
123
124 var states = dseAdapter.explore();
125 assertEquals(1, states.size());
126 assertEquals(0, states.iterator().next());
127 }
128
129 @Test
130 void DFSOneRuleTest() {
131 var createClassPrecondition = Query.of("CreateClassPrecondition",
132 (builder, model) -> builder.clause(
133 classModelView.call(model)
134 ));
135
136 var createClassRule = new TransformationRule("CreateClass",
137 createClassPrecondition,
138 (model) -> {
139 var classesInterpretation = model.getInterpretation(classes);
140 var classElementInterpretation = model.getInterpretation(classElement);
141 return ((Tuple activation) -> {
142 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
143 var modelElement = activation.get(0);
144
145 var newClassElement = dseAdapter.createObject();
146 var newClassElementId = newClassElement.get(0);
147
148 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
149 classElementInterpretation.put(Tuple.of(newClassElementId), true);
150 });
151 });
152
153 var store = ModelStore.builder()
154 .symbols(classModel, classElement, classes)
155 .with(ViatraModelQueryAdapter.builder()
156 .queries(createClassPrecondition))
157 .with(ModelVisualizerAdapter.builder())
158 .with(DesignSpaceExplorationAdapter.builder()
159 .transformations(createClassRule)
160 .strategy(new DepthFirstStrategy(4)
161 ))
162 .build();
163
164 var model = store.createEmptyModel();
165 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
166 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
167
168 var modelElementInterpretation = model.getInterpretation(classModel);
169 modelElementInterpretation.put(dseAdapter.createObject(), true);
170 queryEngine.flushChanges();
171
172 var states = dseAdapter.explore();
173 assertEquals(1, states.size());
174 assertEquals(0, states.iterator().next());
175 }
176
177 @Test
178 void DFSContinueTest() {
179 var createClassPrecondition = Query.of("CreateClassPrecondition",
180 (builder, model) -> builder.clause(
181 classModelView.call(model)
182 ));
183
184 var createClassRule = new TransformationRule("CreateClass",
185 createClassPrecondition,
186 (model) -> {
187 var classesInterpretation = model.getInterpretation(classes);
188 var classElementInterpretation = model.getInterpretation(classElement);
189 return ((Tuple activation) -> {
190 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
191 var modelElement = activation.get(0);
192
193 var newClassElement = dseAdapter.createObject();
194 var newClassElementId = newClassElement.get(0);
195
196 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
197 classElementInterpretation.put(Tuple.of(newClassElementId), true);
198 });
199 });
200
201 var store = ModelStore.builder()
202 .symbols(classModel, classElement, classes)
203 .with(ViatraModelQueryAdapter.builder()
204 .queries(createClassPrecondition))
205 .with(ModelVisualizerAdapter.builder())
206 .with(DesignSpaceExplorationAdapter.builder()
207 .transformations(createClassRule)
208 .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled()
209 ))
210 .build();
211
212 var model = store.createEmptyModel();
213 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
214 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
215
216 var modelElementInterpretation = model.getInterpretation(classModel);
217 modelElementInterpretation.put(dseAdapter.createObject(), true);
218 queryEngine.flushChanges();
219
220 var states = dseAdapter.explore();
221 var iterator = states.iterator();
222 assertEquals(5, states.size());
223 assertEquals(0, iterator.next());
224 assertEquals(1, iterator.next());
225 assertEquals(2, iterator.next());
226 assertEquals(3, iterator.next());
227 assertEquals(4, iterator.next());
228 }
229
230 @Test
231 void DFSCompletenessTest() {
232 var createClassPrecondition = Query.of("CreateClassPrecondition",
233 (builder, model) -> builder.clause(
234 classModelView.call(model)
235 ));
236
237 var createClassRule = new TransformationRule("CreateClass",
238 createClassPrecondition,
239 (model) -> {
240 var classesInterpretation = model.getInterpretation(classes);
241 var classElementInterpretation = model.getInterpretation(classElement);
242 return ((Tuple activation) -> {
243 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
244 var modelElement = activation.get(0);
245
246 var newClassElement = dseAdapter.createObject();
247 var newClassElementId = newClassElement.get(0);
248
249 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
250 classElementInterpretation.put(Tuple.of(newClassElementId), true);
251 });
252 });
253
254 var createFeaturePrecondition = Query.of("CreateFeaturePrecondition",
255 (builder, model) -> builder.clause(
256 classModelView.call(model)
257 ));
258
259 var createFeatureRule = new TransformationRule("CreateFeature",
260 createFeaturePrecondition,
261 (model) -> {
262 var featuresInterpretation = model.getInterpretation(features);
263 var featureInterpretation = model.getInterpretation(feature);
264 return ((Tuple activation) -> {
265 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
266 var modelElement = activation.get(0);
267
268 var newClassElement = dseAdapter.createObject();
269 var newClassElementId = newClassElement.get(0);
270
271 featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
272 featureInterpretation.put(Tuple.of(newClassElementId), true);
273 });
274 });
275
276 var store = ModelStore.builder()
277 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
278 .with(ViatraModelQueryAdapter.builder()
279 .queries(createClassPrecondition, createFeaturePrecondition))
280 .with(ModelVisualizerAdapter.builder())
281 .with(DesignSpaceExplorationAdapter.builder()
282 .transformations(createClassRule, createFeatureRule)
283 .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled()
284 ))
285 .build();
286
287 var model = store.createEmptyModel();
288 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
289 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
290
291 var modelElementInterpretation = model.getInterpretation(classModel);
292 modelElementInterpretation.put(dseAdapter.createObject(), true);
293 queryEngine.flushChanges();
294
295 var states = dseAdapter.explore();
296 assertEquals(2047, states.size());
297 }
298
299 @Test
300 void BFSTrivialTest() {
301 var store = ModelStore.builder()
302 .symbols(classModel)
303 .with(ViatraModelQueryAdapter.builder())
304 .with(ModelVisualizerAdapter.builder())
305 .with(DesignSpaceExplorationAdapter.builder()
306 .strategy(new BestFirstStrategy(0)))
307 .build();
308
309 var model = store.createEmptyModel();
310 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
311
312 var states = dseAdapter.explore();
313 assertEquals(1, states.size());
314 assertEquals(0, states.iterator().next());
315 }
316
317 @Test
318 void BFSOneRuleTest() {
319 var createClassPrecondition = Query.of("CreateClassPrecondition",
320 (builder, model) -> builder.clause(
321 classModelView.call(model)
322 ));
323
324 var createClassRule = new TransformationRule("CreateClass",
325 createClassPrecondition,
326 (model) -> {
327 var classesInterpretation = model.getInterpretation(classes);
328 var classElementInterpretation = model.getInterpretation(classElement);
329 return ((Tuple activation) -> {
330 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
331 var modelElement = activation.get(0);
332
333 var newClassElement = dseAdapter.createObject();
334 var newClassElementId = newClassElement.get(0);
335
336 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
337 classElementInterpretation.put(Tuple.of(newClassElementId), true);
338 });
339 });
340
341 var store = ModelStore.builder()
342 .symbols(classModel, classElement, classes)
343 .with(ViatraModelQueryAdapter.builder()
344 .queries(createClassPrecondition))
345 .with(ModelVisualizerAdapter.builder())
346 .with(DesignSpaceExplorationAdapter.builder()
347 .transformations(createClassRule)
348 .strategy(new BestFirstStrategy(4)
349 ))
350 .build();
351
352 var model = store.createEmptyModel();
353 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
354 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
355
356 var modelElementInterpretation = model.getInterpretation(classModel);
357 modelElementInterpretation.put(dseAdapter.createObject(), true);
358 queryEngine.flushChanges();
359
360 var states = dseAdapter.explore();
361 assertEquals(1, states.size());
362 assertEquals(0, states.iterator().next());
363 }
364
365 @Test
366 void BFSContinueTest() {
367 var createClassPrecondition = Query.of("CreateClassPrecondition",
368 (builder, model) -> builder.clause(
369 classModelView.call(model)
370 ));
371
372 var createClassRule = new TransformationRule("CreateClass",
373 createClassPrecondition,
374 (model) -> {
375 var classesInterpretation = model.getInterpretation(classes);
376 var classElementInterpretation = model.getInterpretation(classElement);
377 return ((Tuple activation) -> {
378 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
379 var modelElement = activation.get(0);
380
381 var newClassElement = dseAdapter.createObject();
382 var newClassElementId = newClassElement.get(0);
383
384 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
385 classElementInterpretation.put(Tuple.of(newClassElementId), true);
386 });
387 });
388
389 var store = ModelStore.builder()
390 .symbols(classModel, classElement, classes)
391 .with(ViatraModelQueryAdapter.builder()
392 .queries(createClassPrecondition))
393 .with(ModelVisualizerAdapter.builder())
394 .with(DesignSpaceExplorationAdapter.builder()
395 .transformations(createClassRule)
396 .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled()
397 ))
398 .build();
399
400 var model = store.createEmptyModel();
401 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
402 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
403
404 var modelElementInterpretation = model.getInterpretation(classModel);
405 modelElementInterpretation.put(dseAdapter.createObject(), true);
406 queryEngine.flushChanges();
407
408 var states = dseAdapter.explore();
409 var iterator = states.iterator();
410 assertEquals(5, states.size());
411 assertEquals(0, iterator.next());
412 assertEquals(1, iterator.next());
413 assertEquals(2, iterator.next());
414 assertEquals(3, iterator.next());
415 assertEquals(4, iterator.next());
416 }
417
418 @Test
419 void BFSCompletenessTest() {
420 var createClassPrecondition = Query.of("CreateClassPrecondition",
421 (builder, model) -> builder.clause(
422 classModelView.call(model)
423 ));
424
425 var createClassRule = new TransformationRule("CreateClass",
426 createClassPrecondition,
427 (model) -> {
428 var classesInterpretation = model.getInterpretation(classes);
429 var classElementInterpretation = model.getInterpretation(classElement);
430 return ((Tuple activation) -> {
431 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
432 var modelElement = activation.get(0);
433
434 var newClassElement = dseAdapter.createObject();
435 var newClassElementId = newClassElement.get(0);
436
437 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
438 classElementInterpretation.put(Tuple.of(newClassElementId), true);
439 });
440 });
441
442 var createFeaturePrecondition = Query.of("CreateFeaturePrecondition",
443 (builder, model) -> builder.clause(
444 classModelView.call(model)
445 ));
446
447 var createFeatureRule = new TransformationRule("CreateFeature",
448 createFeaturePrecondition,
449 (model) -> {
450 var featuresInterpretation = model.getInterpretation(features);
451 var featureInterpretation = model.getInterpretation(feature);
452 return ((Tuple activation) -> {
453 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
454 var modelElement = activation.get(0);
455
456 var newClassElement = dseAdapter.createObject();
457 var newClassElementId = newClassElement.get(0);
458
459 featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
460 featureInterpretation.put(Tuple.of(newClassElementId), true);
461 });
462 });
463
464 var store = ModelStore.builder()
465 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
466 .with(ViatraModelQueryAdapter.builder()
467 .queries(createClassPrecondition, createFeaturePrecondition))
468 .with(ModelVisualizerAdapter.builder())
469 .with(DesignSpaceExplorationAdapter.builder()
470 .transformations(createClassRule, createFeatureRule)
471 .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled()
472 ))
473 .build();
474
475 var model = store.createEmptyModel();
476 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
477 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
478
479 var modelElementInterpretation = model.getInterpretation(classModel);
480 modelElementInterpretation.put(dseAdapter.createObject(), true);
481 queryEngine.flushChanges();
482
483 var states = dseAdapter.explore();
484 assertEquals(2047, states.size());
485 }
486
487}
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java
new file mode 100644
index 00000000..a32d392b
--- /dev/null
+++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java
@@ -0,0 +1,403 @@
1package tools.refinery.store.dse;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Query;
7import tools.refinery.store.dse.internal.TransformationRule;
8import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
9import tools.refinery.store.query.view.AnySymbolView;
10import tools.refinery.store.query.view.KeyOnlyView;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.List;
15import java.util.Map;
16
17import static org.junit.jupiter.api.Assertions.assertEquals;
18import static tools.refinery.store.query.literal.Literals.not;
19import static tools.refinery.store.dse.tests.QueryAssertions.assertResults;
20
21public class TransformationRuleTest {
22
23 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
24 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
25 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
26
27 private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
28 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
29
30 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
31 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
32
33 private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
34 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
35 private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
36 private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
37 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
38 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
39 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
40
41 @Test
42 void activationsTest() {
43 var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper",
44 (builder, model, c, f) -> builder.clause(
45 classElementView.call(c),
46 classesView.call(model, c),
47 encapsulatesView.call(c, f)
48 ));
49
50 var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f)
51 -> builder.clause((model, c1) -> List.of(
52 classModelView.call(model),
53 featureView.call(f),
54 classElementView.call(c2),
55 featuresView.call(model, f),
56 classesView.call(model, c1),
57 not(assignFeaturePreconditionHelper.call(model, c2, f)),
58 not(encapsulatesView.call(c2, f))
59 )));
60
61 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
62 (builder, model, c) -> builder.clause((f) -> List.of(
63 classModelView.call(model),
64 classElementView.call(c),
65 featuresView.call(model, f),
66 not(encapsulatesView.call(c, f))
67 )));
68
69 TransformationRule assignFeatureRule = new TransformationRule("AssignFeature",
70 assignFeaturePrecondition,
71 (model) -> {
72 var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy);
73 return ((Tuple activation) -> {
74 var feature = activation.get(0);
75 var classElement = activation.get(1);
76
77 isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true);
78 });
79 });
80
81 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass",
82 deleteEmptyClassPrecondition,
83 (model) -> {
84 var classesInterpretation = model.getInterpretation(classes);
85 var classElementInterpretation = model.getInterpretation(classElement);
86 return ((Tuple activation) -> {
87 var modelElement = activation.get(0);
88 var classElement = activation.get(1);
89
90 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
91 classElementInterpretation.put(Tuple.of(classElement), false);
92 });
93 });
94
95
96 var store = ModelStore.builder()
97 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
98 .with(ViatraModelQueryAdapter.builder()
99 .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper,
100 deleteEmptyClassPrecondition))
101 .with(DesignSpaceExplorationAdapter.builder())
102 .build();
103
104 var model = store.createEmptyModel();
105 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
106 assignFeatureRule.prepare(model, queryEngine);
107 deleteEmptyClassRule.prepare(model, queryEngine);
108
109 var classModelInterpretation = model.getInterpretation(classModel);
110 var classElementInterpretation = model.getInterpretation(classElement);
111 var featureInterpretation = model.getInterpretation(feature);
112 var featuresInterpretation = model.getInterpretation(features);
113 var classesInterpretation = model.getInterpretation(classes);
114
115 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
116 var newModel = dseAdapter.createObject();
117 var newModelId = newModel.get(0);
118 var newClass1 = dseAdapter.createObject();
119 var newClass1Id = newClass1.get(0);
120 var newClass2 = dseAdapter.createObject();
121 var newClass2Id = newClass2.get(0);
122 var newField = dseAdapter.createObject();
123 var newFieldId = newField.get(0);
124
125 classModelInterpretation.put(newModel, true);
126 classElementInterpretation.put(newClass1, true);
127 classElementInterpretation.put(newClass2, true);
128 featureInterpretation.put(newField, true);
129 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
130 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
131 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
132
133 queryEngine.flushChanges();
134
135 var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets();
136 var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets();
137
138 assertResults(Map.of(
139 Tuple.of(newClass1Id, newFieldId), true,
140 Tuple.of(newClass2Id, newFieldId), true
141 ), assignFeatureRuleActivations);
142
143 assertResults(Map.of(
144 Tuple.of(newModelId, newClass1Id), true,
145 Tuple.of(newModelId, newClass2Id), true
146 ), deleteEmptyClassRuleActivations);
147 }
148
149 @Test
150 void randomActivationTest() {
151 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
152 (builder, model, c) -> builder.clause((f) -> List.of(
153 classModelView.call(model),
154 classElementView.call(c),
155 featuresView.call(model, f),
156 not(encapsulatesView.call(c, f))
157 )));
158
159 TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0",
160 deleteEmptyClassPrecondition,
161 (model) -> {
162 var classesInterpretation = model.getInterpretation(classes);
163 var classElementInterpretation = model.getInterpretation(classElement);
164 return ((Tuple activation) -> {
165 var modelElement = activation.get(0);
166 var classElement = activation.get(1);
167
168 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
169 classElementInterpretation.put(Tuple.of(classElement), false);
170 });
171 },
172 0L);
173
174 TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1",
175 deleteEmptyClassPrecondition,
176 (model) -> {
177 var classesInterpretation = model.getInterpretation(classes);
178 var classElementInterpretation = model.getInterpretation(classElement);
179 return ((Tuple activation) -> {
180 var modelElement = activation.get(0);
181 var classElement = activation.get(1);
182
183 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
184 classElementInterpretation.put(Tuple.of(classElement), false);
185 });
186 },
187 78634L);
188
189 var store = ModelStore.builder()
190 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
191 .with(ViatraModelQueryAdapter.builder()
192 .queries(deleteEmptyClassPrecondition))
193 .with(DesignSpaceExplorationAdapter.builder())
194 .build();
195
196 var model = store.createEmptyModel();
197 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
198 deleteEmptyClassRule0.prepare(model, queryEngine);
199 deleteEmptyClassRule1.prepare(model, queryEngine);
200
201 var classModelInterpretation = model.getInterpretation(classModel);
202 var classElementInterpretation = model.getInterpretation(classElement);
203 var featureInterpretation = model.getInterpretation(feature);
204 var featuresInterpretation = model.getInterpretation(features);
205 var classesInterpretation = model.getInterpretation(classes);
206
207 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
208 var newModel = dseAdapter.createObject();
209 var newModelId = newModel.get(0);
210 var newClass1 = dseAdapter.createObject();
211 var newClass1Id = newClass1.get(0);
212 var newClass2 = dseAdapter.createObject();
213 var newClass2Id = newClass2.get(0);
214 var newField = dseAdapter.createObject();
215 var newFieldId = newField.get(0);
216
217 classModelInterpretation.put(newModel, true);
218 classElementInterpretation.put(newClass1, true);
219 classElementInterpretation.put(newClass2, true);
220 featureInterpretation.put(newField, true);
221 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
222 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
223 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
224
225 queryEngine.flushChanges();
226
227
228 var activation0 = deleteEmptyClassRule0.getRandomActivation().activation();
229 var activation1 = deleteEmptyClassRule1.getRandomActivation().activation();
230
231 assertResults(Map.of(
232 Tuple.of(newModelId, newClass1Id), true,
233 Tuple.of(newModelId, newClass2Id), true
234 ), deleteEmptyClassRule0.getAllActivationsAsSets());
235
236 assertResults(Map.of(
237 Tuple.of(newModelId, newClass1Id), true,
238 Tuple.of(newModelId, newClass2Id), true
239 ), deleteEmptyClassRule1.getAllActivationsAsSets());
240
241 assertEquals(Tuple.of(newModelId, newClass2Id), activation0);
242 assertEquals(Tuple.of(newModelId, newClass1Id), activation1);
243
244 }
245
246 @Test
247 void fireTest() {
248 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
249 (builder, model, c) -> builder.clause((f) -> List.of(
250 classModelView.call(model),
251 classElementView.call(c),
252 featuresView.call(model, f),
253 not(encapsulatesView.call(c, f))
254 )));
255
256 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass",
257 deleteEmptyClassPrecondition,
258 (model) -> {
259 var classesInterpretation = model.getInterpretation(classes);
260 var classElementInterpretation = model.getInterpretation(classElement);
261 return ((Tuple activation) -> {
262 var modelElement = activation.get(0);
263 var classElement = activation.get(1);
264
265 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
266 classElementInterpretation.put(Tuple.of(classElement), false);
267 });
268 });
269
270 var store = ModelStore.builder()
271 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
272 .with(ViatraModelQueryAdapter.builder()
273 .queries(deleteEmptyClassPrecondition))
274 .with(DesignSpaceExplorationAdapter.builder())
275 .build();
276
277 var model = store.createEmptyModel();
278 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
279 deleteEmptyClassRule.prepare(model, queryEngine);
280
281 var classModelInterpretation = model.getInterpretation(classModel);
282 var classElementInterpretation = model.getInterpretation(classElement);
283 var featureInterpretation = model.getInterpretation(feature);
284 var featuresInterpretation = model.getInterpretation(features);
285 var classesInterpretation = model.getInterpretation(classes);
286
287 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
288 var newModel = dseAdapter.createObject();
289 var newModelId = newModel.get(0);
290 var newClass1 = dseAdapter.createObject();
291 var newClass1Id = newClass1.get(0);
292 var newClass2 = dseAdapter.createObject();
293 var newClass2Id = newClass2.get(0);
294 var newField = dseAdapter.createObject();
295 var newFieldId = newField.get(0);
296
297 classModelInterpretation.put(newModel, true);
298 classElementInterpretation.put(newClass1, true);
299 classElementInterpretation.put(newClass2, true);
300 featureInterpretation.put(newField, true);
301 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
302 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
303 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
304
305 queryEngine.flushChanges();
306
307 assertResults(Map.of(
308 Tuple.of(newModelId, newClass1Id), true,
309 Tuple.of(newModelId, newClass2Id), true
310 ), deleteEmptyClassRule.getAllActivationsAsSets());
311
312
313 deleteEmptyClassRule.fireActivation(Tuple.of(0, 1));
314
315 assertResults(Map.of(
316 Tuple.of(newModelId, newClass1Id), false,
317 Tuple.of(newModelId, newClass2Id), true
318 ), deleteEmptyClassRule.getAllActivationsAsSets());
319 }
320
321 @Test
322 void randomFireTest() {
323 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
324 (builder, model, c) -> builder.clause((f) -> List.of(
325 classModelView.call(model),
326 classElementView.call(c),
327 featuresView.call(model, f),
328 not(encapsulatesView.call(c, f))
329 )));
330
331 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0",
332 deleteEmptyClassPrecondition,
333 (model) -> {
334 var classesInterpretation = model.getInterpretation(classes);
335 var classElementInterpretation = model.getInterpretation(classElement);
336 return ((Tuple activation) -> {
337 var modelElement = activation.get(0);
338 var classElement = activation.get(1);
339
340 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
341 classElementInterpretation.put(Tuple.of(classElement), false);
342 });
343 },
344 0L);
345
346 var store = ModelStore.builder()
347 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
348 .with(ViatraModelQueryAdapter.builder()
349 .queries(deleteEmptyClassPrecondition))
350 .with(DesignSpaceExplorationAdapter.builder())
351 .build();
352
353 var model = store.createEmptyModel();
354 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
355 deleteEmptyClassRule.prepare(model, queryEngine);
356
357 var classModelInterpretation = model.getInterpretation(classModel);
358 var classElementInterpretation = model.getInterpretation(classElement);
359 var featureInterpretation = model.getInterpretation(feature);
360 var featuresInterpretation = model.getInterpretation(features);
361 var classesInterpretation = model.getInterpretation(classes);
362
363 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
364 var newModel = dseAdapter.createObject();
365 var newModelId = newModel.get(0);
366 var newClass1 = dseAdapter.createObject();
367 var newClass1Id = newClass1.get(0);
368 var newClass2 = dseAdapter.createObject();
369 var newClass2Id = newClass2.get(0);
370 var newField = dseAdapter.createObject();
371 var newFieldId = newField.get(0);
372
373 classModelInterpretation.put(newModel, true);
374 classElementInterpretation.put(newClass1, true);
375 classElementInterpretation.put(newClass2, true);
376 featureInterpretation.put(newField, true);
377 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
378 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
379 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
380
381 queryEngine.flushChanges();
382
383 assertResults(Map.of(
384 Tuple.of(newModelId, newClass1Id), true,
385 Tuple.of(newModelId, newClass2Id), true
386 ), deleteEmptyClassRule.getAllActivationsAsSets());
387
388 deleteEmptyClassRule.fireRandomActivation();
389
390 assertResults(Map.of(
391 Tuple.of(newModelId, newClass1Id), true,
392 Tuple.of(newModelId, newClass2Id), false
393 ), deleteEmptyClassRule.getAllActivationsAsSets());
394
395 deleteEmptyClassRule.fireRandomActivation();
396
397 assertResults(Map.of(
398 Tuple.of(newModelId, newClass1Id), false,
399 Tuple.of(newModelId, newClass2Id), false
400 ), deleteEmptyClassRule.getAllActivationsAsSets());
401
402 }
403}
diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java
new file mode 100644
index 00000000..be514eaf
--- /dev/null
+++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java
@@ -0,0 +1,57 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.tests;
7
8import org.junit.jupiter.api.function.Executable;
9import tools.refinery.store.query.resultset.ResultSet;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.*;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.is;
16import static org.hamcrest.Matchers.nullValue;
17import static org.junit.jupiter.api.Assertions.assertAll;
18
19public final class QueryAssertions {
20 private QueryAssertions() {
21 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
22 }
23
24 public static <T> void assertNullableResults(Map<Tuple, Optional<T>> expected, ResultSet<T> resultSet) {
25 var nullableValuesMap = new LinkedHashMap<Tuple, T>(expected.size());
26 for (var entry : expected.entrySet()) {
27 nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null));
28 }
29 assertResults(nullableValuesMap, resultSet);
30 }
31
32 public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) {
33 var defaultValue = resultSet.getQuery().defaultValue();
34 var filteredExpected = new LinkedHashMap<Tuple, T>();
35 var executables = new ArrayList<Executable>();
36 for (var entry : expected.entrySet()) {
37 var key = entry.getKey();
38 var value = entry.getValue();
39 if (!Objects.equals(value, defaultValue)) {
40 filteredExpected.put(key, value);
41 }
42 executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value)));
43 }
44 executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size())));
45
46 var actual = new LinkedHashMap<Tuple, T>();
47 var cursor = resultSet.getAll();
48 while (cursor.move()) {
49 var key = cursor.getKey();
50 var previous = actual.put(key, cursor.getValue());
51 assertThat("duplicate value for key " + key, previous, nullValue());
52 }
53 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected)));
54
55 assertAll(executables);
56 }
57}