aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java10
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java18
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java4
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java116
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java27
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java56
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java2
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java2
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java1
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java110
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java129
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java21
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java21
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java179
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java33
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java22
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java5
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java12
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java33
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java125
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java38
23 files changed, 673 insertions, 323 deletions
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
index 8963a496..5aed5298 100644
--- 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
@@ -38,7 +38,9 @@ public interface DesignSpaceExplorationAdapter extends ModelAdapter {
38 38
39 public boolean backtrack(); 39 public boolean backtrack();
40 40
41 public Fitness calculateFitness(); 41 public boolean backtrack(String reason);
42
43 public Fitness getFitness();
42 44
43 public void newSolution(); 45 public void newSolution();
44 46
@@ -48,9 +50,7 @@ public interface DesignSpaceExplorationAdapter extends ModelAdapter {
48 50
49 public boolean fireActivation(Activation activation); 51 public boolean fireActivation(Activation activation);
50 52
51 public void fireRandomActivation(); 53 public boolean fireRandomActivation();
52
53 public boolean isCurrentInTrajectory();
54 54
55 public List<Version> getTrajectory(); 55 public List<Version> getTrajectory();
56 56
@@ -63,4 +63,6 @@ public interface DesignSpaceExplorationAdapter extends ModelAdapter {
63 public void setRandom(Random random); 63 public void setRandom(Random random);
64 64
65 public void setRandom(long seed); 65 public void setRandom(long seed);
66
67 public List<Version> getSolutions();
66} 68}
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
index 186bfebb..0252748d 100644
--- 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
@@ -6,6 +6,24 @@
6package tools.refinery.store.dse; 6package tools.refinery.store.dse;
7 7
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.dse.internal.TransformationRule;
10import tools.refinery.store.dse.objectives.Objective;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.dnf.RelationalQuery;
13
14import java.util.List;
15import java.util.Set;
9 16
10public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { 17public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter {
18
19 @Override
20 DesignSpaceExplorationAdapter createModelAdapter(Model model);
21
22 Set<TransformationRule> getTransformationSpecifications();
23
24 Set<RelationalQuery> getGlobalConstraints();
25
26 List<Objective> getObjectives();
27
28 Strategy getStrategy();
11} 29}
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
index e240f478..c60a4410 100644
--- 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
@@ -7,7 +7,7 @@ package tools.refinery.store.dse;
7 7
8public interface Strategy { 8public interface Strategy {
9 9
10 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter); 10 void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter);
11 11
12 public void explore(); 12 void explore();
13} 13}
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
index b32e9696..220f0b2d 100644
--- 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
@@ -33,27 +33,24 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
33 private final Model model; 33 private final Model model;
34 private final ModelQueryAdapter queryEngine; 34 private final ModelQueryAdapter queryEngine;
35 private final DesignSpaceExplorationStoreAdapterImpl storeAdapter; 35 private final DesignSpaceExplorationStoreAdapterImpl storeAdapter;
36 private final LinkedHashSet<TransformationRule> transformationRules; 36 private final Set<TransformationRule> transformationRules;
37 private final LinkedHashSet<RelationalQuery> globalConstraints; 37 private final Set<RelationalQuery> globalConstraints;
38 private final List<Objective> objectives; 38 private final List<Objective> objectives;
39 private final LinkedHashSet<ResultSet<Boolean>> globalConstraintResultSets = new LinkedHashSet<>(); 39 private final LinkedHashSet<ResultSet<Boolean>> globalConstraintResultSets = new LinkedHashSet<>();
40 private final Interpretation<Integer> sizeInterpretation; 40 private final Interpretation<Integer> sizeInterpretation;
41 private final Strategy strategy; 41 private final Strategy strategy;
42 42
43 private ObjectiveComparatorHelper objectiveComparatorHelper; 43 private ObjectiveComparatorHelper objectiveComparatorHelper;
44 private List<Version> trajectory = new LinkedList<>(); 44 private List<Version> trajectory = new ArrayList<>();
45 private Fitness lastFitness; 45 private Map<Version, Version> parents = new HashMap<>();
46 private final LinkedHashSet<Version> solutions = new LinkedHashSet<>(); 46 private final List<Version> solutions = new ArrayList<>();
47 private Map<Version, LinkedHashSet<Activation>> statesAndUntraversedActivations; 47 private Map<Version, List<Activation>> statesAndTraversedActivations;
48 private Map<Version, LinkedHashSet<Activation>> statesAndTraversedActivations;
49 private Random random = new Random(); 48 private Random random = new Random();
50 private boolean isNewState = false; 49 private boolean isNewState = false;
51 private final boolean isVisualizationEnabled; 50 private final boolean isVisualizationEnabled;
52 private final ModelVisualizerAdapter modelVisualizerAdapter; 51 private final ModelVisualizerAdapter modelVisualizerAdapter;
53 52
54 public List<Version> getTrajectory() { 53 private final Map<Version, Fitness> fitnessCache = new HashMap<>();
55 return new LinkedList<>(trajectory);
56 }
57 54
58 public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) { 55 public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) {
59 this.model = model; 56 this.model = model;
@@ -72,14 +69,18 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
72 } 69 }
73 70
74 objectives = storeAdapter.getObjectives(); 71 objectives = storeAdapter.getObjectives();
75 statesAndUntraversedActivations = new HashMap<>();
76 statesAndTraversedActivations = new HashMap<>(); 72 statesAndTraversedActivations = new HashMap<>();
77 strategy = storeAdapter.getStrategy(); 73 strategy = storeAdapter.getStrategy();
74 strategy.initialize(this);
78 modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null); 75 modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null);
79 isVisualizationEnabled = modelVisualizerAdapter != null; 76 isVisualizationEnabled = modelVisualizerAdapter != null;
80 77
81 } 78 }
82 79
80 public List<Version> getTrajectory() {
81 return new ArrayList<>(trajectory);
82 }
83
83 @Override 84 @Override
84 public Model getModel() { 85 public Model getModel() {
85 return model; 86 return model;
@@ -91,13 +92,13 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
91 } 92 }
92 93
93 @Override 94 @Override
94 public LinkedHashSet<Version> explore() { 95 public List<Version> explore() {
95 var state = model.commit(); 96 var state = model.commit();
96 trajectory.add(state); 97 trajectory.add(state);
97 statesAndUntraversedActivations.put(state, getAllActivations());
98 statesAndTraversedActivations.put(state, new LinkedHashSet<>());
99 strategy.initStrategy(this);
100 strategy.explore(); 98 strategy.explore();
99 if (isVisualizationEnabled) {
100 modelVisualizerAdapter.visualize();
101 }
101 return solutions; 102 return solutions;
102 } 103 }
103 104
@@ -137,14 +138,22 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
137 138
138 @Override 139 @Override
139 public boolean backtrack() { 140 public boolean backtrack() {
141 return backtrack("");
142 }
143 @Override
144 public boolean backtrack(String reason) {
140 if (trajectory.size() < 2) { 145 if (trajectory.size() < 2) {
141 return false; 146 return false;
142 } 147 }
148 var currentState = model.getState();
149 if (!parents.containsKey(currentState)) {
150 return false;
151 }
143 if (isVisualizationEnabled) { 152 if (isVisualizationEnabled) {
144 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1), 153 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1),
145 trajectory.get(trajectory.size() - 2), "backtrack"); 154 trajectory.get(trajectory.size() - 2), "backtrack(" + reason + ")");
146 } 155 }
147 model.restore(trajectory.get(trajectory.size() - 2)); 156 model.restore(parents.get(model.getState()));
148 trajectory.remove(trajectory.size() - 1); 157 trajectory.remove(trajectory.size() - 1);
149 return true; 158 return true;
150 } 159 }
@@ -156,7 +165,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
156// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1), 165// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1),
157// trajectory.get(trajectory.size() - 1), "restore"); 166// trajectory.get(trajectory.size() - 1), "restore");
158// } 167// }
159 this.trajectory = trajectory; 168 this.trajectory = new ArrayList<>(trajectory);
160 169
161 } 170 }
162 171
@@ -171,7 +180,16 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
171 } 180 }
172 181
173 @Override 182 @Override
174 public Fitness calculateFitness() { 183 public List<Version> getSolutions() {
184 return solutions;
185 }
186
187 @Override
188 public Fitness getFitness() {
189 return fitnessCache.computeIfAbsent(model.getState(), s -> calculateFitness());
190 }
191
192 private Fitness calculateFitness() {
175 Fitness result = new Fitness(); 193 Fitness result = new Fitness();
176 boolean satisfiesHardObjectives = true; 194 boolean satisfiesHardObjectives = true;
177 for (Objective objective : objectives) { 195 for (Objective objective : objectives) {
@@ -183,8 +201,6 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
183 } 201 }
184 result.setSatisfiesHardObjectives(satisfiesHardObjectives); 202 result.setSatisfiesHardObjectives(satisfiesHardObjectives);
185 203
186 lastFitness = result;
187
188 return result; 204 return result;
189 } 205 }
190 206
@@ -203,15 +219,19 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
203 } 219 }
204 220
205 public LinkedHashSet<Activation> getUntraversedActivations() { 221 public LinkedHashSet<Activation> getUntraversedActivations() {
206// return statesAndUntraversedActivations.get(model.getState()); 222 var traversedActivations = statesAndTraversedActivations.get(model.getState());
207 LinkedHashSet<Activation> untraversedActivations = new LinkedHashSet<>(); 223 if (traversedActivations == null) {
208 for (Activation activation : getAllActivations()) { 224 return new LinkedHashSet<>(getAllActivations());
209 if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) { 225 }
210 untraversedActivations.add(activation); 226 else {
227 LinkedHashSet<Activation> untraversedActivations = new LinkedHashSet<>();
228 for (Activation activation : getAllActivations()) {
229 if (!traversedActivations.contains(activation)) {
230 untraversedActivations.add(activation);
231 }
211 } 232 }
233 return untraversedActivations;
212 } 234 }
213
214 return untraversedActivations;
215 } 235 }
216 236
217 @Override 237 @Override
@@ -220,37 +240,29 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
220 return false; 240 return false;
221 } 241 }
222 var previousState = model.getState(); 242 var previousState = model.getState();
223 if (!statesAndUntraversedActivations.get(previousState).contains(activation)) {
224// TODO: throw exception?
225 return false;
226 }
227 if (!activation.fire()) { 243 if (!activation.fire()) {
228 return false; 244 return false;
229 } 245 }
230 statesAndUntraversedActivations.get(previousState).remove(activation); 246 statesAndTraversedActivations.computeIfAbsent(previousState, s -> new ArrayList<>()).add(activation);
231 statesAndTraversedActivations.get(previousState).add(activation);
232 var newState = model.commit(); 247 var newState = model.commit();
233 trajectory.add(newState); 248 trajectory.add(newState);
234 isNewState = !statesAndUntraversedActivations.containsKey(newState); 249 parents.put(newState, previousState);
235 statesAndUntraversedActivations.put(newState, getAllActivations()); 250 isNewState = !statesAndTraversedActivations.containsKey(newState);
236 statesAndTraversedActivations.put(newState, new LinkedHashSet<>());
237 if (isVisualizationEnabled) { 251 if (isVisualizationEnabled) {
238 if (isNewState) { 252 if (isNewState) {
239 modelVisualizerAdapter.addState(newState); 253 modelVisualizerAdapter.addState(newState, getFitness().values());
240 } 254 }
241 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2), 255 modelVisualizerAdapter.addTransition(previousState, newState, activation.transformationRule().getName(),
242 trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(),
243 activation.activation()); 256 activation.activation());
244 } 257 }
245 return true; 258 return true;
246 } 259 }
247 260
248 @Override 261 @Override
249 public void fireRandomActivation() { 262 public boolean fireRandomActivation() {
250 var activations = getUntraversedActivations(); 263 var activations = getUntraversedActivations();
251 if (activations.isEmpty()) { 264 if (activations.isEmpty()) {
252// TODO: throw exception 265 return false;
253 return;
254 } 266 }
255 int index = random.nextInt(activations.size()); 267 int index = random.nextInt(activations.size());
256 var iterator = activations.iterator(); 268 var iterator = activations.iterator();
@@ -258,31 +270,21 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
258 iterator.next(); 270 iterator.next();
259 } 271 }
260 var activationId = iterator.next(); 272 var activationId = iterator.next();
261 fireActivation(activationId); 273 return fireActivation(activationId);
262 } 274 }
263 275
264 @Override 276 public List<Activation> getAllActivations() {
265 public boolean isCurrentInTrajectory() { 277 List<Activation> result = new LinkedList<>();
266 return trajectory.contains(model.getState());
267 }
268
269 public LinkedHashSet<Activation> getAllActivations() {
270 LinkedHashSet<Activation> result = new LinkedHashSet<>();
271 for (var rule : transformationRules) { 278 for (var rule : transformationRules) {
272 result.addAll(rule.getAllActivations()); 279 result.addAll(rule.getAllActivationsAsList());
273 } 280 }
274 return result; 281 return result;
275 } 282 }
276 283
277 public boolean isCurrentStateAlreadyTraversed() { 284 public boolean isCurrentStateAlreadyTraversed() {
278// TODO: check isomorphism?
279 return !isNewState; 285 return !isNewState;
280 } 286 }
281 287
282 public Fitness getLastFitness() {
283 return lastFitness;
284 }
285
286 public ObjectiveComparatorHelper getObjectiveComparatorHelper() { 288 public ObjectiveComparatorHelper getObjectiveComparatorHelper() {
287 if (objectiveComparatorHelper == null) { 289 if (objectiveComparatorHelper == null) {
288 objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives); 290 objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives);
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
index 09925ae7..fea39886 100644
--- 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
@@ -5,27 +5,26 @@
5 */ 5 */
6package tools.refinery.store.dse.internal; 6package tools.refinery.store.dse.internal;
7 7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.query.dnf.RelationalQuery;
12import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; 8import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter;
13import tools.refinery.store.dse.Strategy; 9import tools.refinery.store.dse.Strategy;
14import tools.refinery.store.dse.objectives.Objective; 10import tools.refinery.store.dse.objectives.Objective;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.ModelStore;
13import tools.refinery.store.query.dnf.RelationalQuery;
15 14
16import java.util.LinkedHashSet;
17import java.util.List; 15import java.util.List;
16import java.util.Set;
18 17
19public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { 18public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter {
20 private final ModelStore store; 19 private final ModelStore store;
21 private final LinkedHashSet<TransformationRule> transformationSpecifications; 20 private final Set<TransformationRule> transformationSpecifications;
22 private final LinkedHashSet<RelationalQuery> globalConstraints; 21 private final Set<RelationalQuery> globalConstraints;
23 private final List<Objective> objectives; 22 private final List<Objective> objectives;
24 private final Strategy strategy; 23 private final Strategy strategy;
25 24
26 public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, 25 public DesignSpaceExplorationStoreAdapterImpl(ModelStore store,
27 LinkedHashSet<TransformationRule> transformationSpecifications, 26 Set<TransformationRule> transformationSpecifications,
28 LinkedHashSet<RelationalQuery> globalConstraints, 27 Set<RelationalQuery> globalConstraints,
29 List<Objective> objectives, Strategy strategy) { 28 List<Objective> objectives, Strategy strategy) {
30 this.store = store; 29 this.store = store;
31 this.transformationSpecifications = transformationSpecifications; 30 this.transformationSpecifications = transformationSpecifications;
@@ -40,22 +39,26 @@ public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplor
40 } 39 }
41 40
42 @Override 41 @Override
43 public ModelAdapter createModelAdapter(Model model) { 42 public DesignSpaceExplorationAdapterImpl createModelAdapter(Model model) {
44 return new DesignSpaceExplorationAdapterImpl(model, this); 43 return new DesignSpaceExplorationAdapterImpl(model, this);
45 } 44 }
46 45
47 public LinkedHashSet<TransformationRule> getTransformationSpecifications() { 46 @Override
47 public Set<TransformationRule> getTransformationSpecifications() {
48 return transformationSpecifications; 48 return transformationSpecifications;
49 } 49 }
50 50
51 public LinkedHashSet<RelationalQuery> getGlobalConstraints() { 51 @Override
52 public Set<RelationalQuery> getGlobalConstraints() {
52 return globalConstraints; 53 return globalConstraints;
53 } 54 }
54 55
56 @Override
55 public List<Objective> getObjectives() { 57 public List<Objective> getObjectives() {
56 return objectives; 58 return objectives;
57 } 59 }
58 60
61 @Override
59 public Strategy getStrategy() { 62 public Strategy getStrategy() {
60 return strategy; 63 return strategy;
61 } 64 }
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
index 015d4815..8123c0d6 100644
--- 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
@@ -14,8 +14,7 @@ import tools.refinery.store.query.resultset.OrderedResultSet;
14import tools.refinery.store.query.resultset.ResultSet; 14import tools.refinery.store.query.resultset.ResultSet;
15import tools.refinery.store.tuple.Tuple; 15import tools.refinery.store.tuple.Tuple;
16 16
17import java.util.LinkedHashSet; 17import java.util.*;
18import java.util.Random;
19 18
20public class TransformationRule { 19public class TransformationRule {
21 20
@@ -66,11 +65,11 @@ public class TransformationRule {
66 return precondition; 65 return precondition;
67 } 66 }
68 67
69 public ResultSet<Boolean> getAllActivationsAsSets() { 68 public ResultSet<Boolean> getAllActivationsAsResultSet() {
70 return activations; 69 return activations;
71 } 70 }
72 71
73 public LinkedHashSet<Activation> getAllActivations() { 72 public Set<Activation> getAllActivations() {
74 var result = new LinkedHashSet<Activation>(); 73 var result = new LinkedHashSet<Activation>();
75 var cursor = activations.getAll(); 74 var cursor = activations.getAll();
76 while (cursor.move()) { 75 while (cursor.move()) {
@@ -79,6 +78,15 @@ public class TransformationRule {
79 return result; 78 return result;
80 } 79 }
81 80
81 public List<Activation> getAllActivationsAsList() {
82 var result = new ArrayList<Activation>();
83 var cursor = activations.getAll();
84 while (cursor.move()) {
85 result.add(new Activation(this, cursor.getKey()));
86 }
87 return result;
88 }
89
82 public Activation getRandomActivation() { 90 public Activation getRandomActivation() {
83 return new Activation(this, activations.getKey(random.nextInt(activations.size()))); 91 return new Activation(this, activations.getKey(random.nextInt(activations.size())));
84 } 92 }
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java
new file mode 100644
index 00000000..327d5e2f
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java
@@ -0,0 +1,56 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13
14import java.util.Random;
15
16/**
17 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
18 *
19 * @author Andras Szabolcs Nagy
20 *
21 */
22public class AlwaysSatisfiedRandomHardObjective extends BaseObjective {
23
24 private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
25 private static final Random random = new Random(0);
26
27 public AlwaysSatisfiedRandomHardObjective() {
28 super(DEFAULT_NAME);
29 }
30
31 public AlwaysSatisfiedRandomHardObjective(String name) {
32 super(name);
33 }
34
35 @Override
36 public Double getFitness(DesignSpaceExplorationAdapter context) {
37// return 0d;
38 return random.nextDouble();
39 }
40
41 @Override
42 public boolean isHardObjective() {
43 return true;
44 }
45
46 @Override
47 public boolean satisfiesHardObjective(Double fitness) {
48 return true;
49 }
50
51 @Override
52 public Objective createNew() {
53 return this;
54 }
55
56}
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
index 7df33efe..b76598fb 100644
--- 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
@@ -30,7 +30,7 @@ public abstract class BaseObjective implements Objective {
30 protected boolean isThereFitnessConstraint = false; 30 protected boolean isThereFitnessConstraint = false;
31 protected Comparator<Double> fitnessConstraintComparator; 31 protected Comparator<Double> fitnessConstraintComparator;
32 32
33 public BaseObjective(String name) { 33 protected BaseObjective(String name) {
34 Objects.requireNonNull(name, "Name of the objective cannot be null."); 34 Objects.requireNonNull(name, "Name of the objective cannot be null.");
35 this.name = name; 35 this.name = name;
36 } 36 }
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
index 476504b0..181397b3 100644
--- 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
@@ -15,7 +15,7 @@ public class Comparators {
15 15
16 private Comparators() { /*Utility class constructor*/ } 16 private Comparators() { /*Utility class constructor*/ }
17 17
18 public static final Comparator<Double> HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2); 18 public static final Comparator<Double> HIGHER_IS_BETTER = Double::compareTo;
19 19
20 public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1); 20 public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1);
21 21
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
index 92709d3e..b1dc4442 100644
--- 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
@@ -27,4 +27,20 @@ public class Fitness extends HashMap<String, Double> {
27 public String toString() { 27 public String toString() {
28 return super.toString() + " hardObjectives=" + satisfiesHardObjectives; 28 return super.toString() + " hardObjectives=" + satisfiesHardObjectives;
29 } 29 }
30
31 @Override
32 public boolean equals(Object other) {
33 if (other == null) return false;
34 if (getClass() != other.getClass()) return false;
35 if (!super.equals(other)) return false;
36 return satisfiesHardObjectives == ((Fitness) other).satisfiesHardObjectives;
37 }
38
39 @Override
40 public int hashCode() {
41 int h = super.hashCode();
42 h = h * 31 + (satisfiesHardObjectives ? 1 : 0);
43 return h;
44 }
45
30} 46}
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
index 1d676562..eb03eeaf 100644
--- 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
@@ -49,6 +49,7 @@ public class ObjectiveComparatorHelper {
49 } 49 }
50 } 50 }
51 if (o2HasBetterFitness) { 51 if (o2HasBetterFitness) {
52 return -1;
52 } else if (o1HasBetterFitness) { 53 } else if (o1HasBetterFitness) {
53 return 1; 54 return 1;
54 } 55 }
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
index 8648864c..92d878ce 100644
--- 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
@@ -16,49 +16,52 @@ import tools.refinery.store.dse.internal.Activation;
16import tools.refinery.store.dse.objectives.Fitness; 16import tools.refinery.store.dse.objectives.Fitness;
17import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; 17import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
18 18
19import java.util.Collection; 19import java.util.*;
20import java.util.Iterator;
21import java.util.List;
22import java.util.PriorityQueue;
23 20
24public class BestFirstStrategy implements Strategy { 21public class BestFirstStrategy implements Strategy {
25 22
26 private DesignSpaceExplorationAdapter dseAdapter; 23 private DesignSpaceExplorationAdapter dseAdapter;
27 24
28 private int maxDepth; 25 private int maxDepth = Integer.MAX_VALUE;
26 private int maxSolutions = Integer.MAX_VALUE;
29 private boolean backTrackIfSolution = true; 27 private boolean backTrackIfSolution = true;
30 private boolean onlyBetterFirst = false; 28 private boolean onlyBetterFirst = false;
31 29
32 private PriorityQueue<TrajectoryWithFitness> trajectoriesToExplore; 30 private PriorityQueue<TrajectoryWithFitness> trajectoriesToExplore;
33 31
34 private static class TrajectoryWithFitness { 32 private record TrajectoryWithFitness(List<Version> trajectory, Fitness fitness) {
35 33 @Override
36 public List<Version> trajectory; 34 public String toString() {
37 public Fitness fitness; 35 return trajectory.toString() + fitness.toString();
36 }
38 37
39 public TrajectoryWithFitness(List<Version> trajectory, Fitness fitness) { 38 @Override
40 super(); 39 public int hashCode() {
41 this.trajectory = trajectory; 40 return trajectory.get(trajectory.size() - 1).hashCode();
42 this.fitness = fitness;
43 } 41 }
44 42
45 @Override 43 @Override
46 public String toString() { 44 public boolean equals(Object obj) {
47 return trajectory.toString() + fitness.toString(); 45 if (obj instanceof TrajectoryWithFitness other) {
46 return Objects.equals(trajectory.get(trajectory.size() - 1), other.trajectory.get(other.trajectory.size() - 1));
47// return trajectory.equals(((TrajectoryWithFitness) obj).trajectory);
48 }
49 return false;
48 } 50 }
49
50 } 51 }
51 52
52 public BestFirstStrategy() { 53 public BestFirstStrategy withDepthLimit(int maxDepth) {
53 this(-1); 54 if (maxDepth >= 0) {
55 this.maxDepth = maxDepth;
56 }
57 return this;
54 } 58 }
55 59
56 public BestFirstStrategy(int maxDepth) { 60 public BestFirstStrategy withSolutionLimit(int maxSolutions) {
57 if (maxDepth < 0) { 61 if (maxSolutions >= 0) {
58 this.maxDepth = Integer.MAX_VALUE; 62 this.maxSolutions = maxSolutions;
59 } else {
60 this.maxDepth = maxDepth;
61 } 63 }
64 return this;
62 } 65 }
63 66
64 public BestFirstStrategy continueIfHardObjectivesFulfilled() { 67 public BestFirstStrategy continueIfHardObjectivesFulfilled() {
@@ -72,28 +75,31 @@ public class BestFirstStrategy implements Strategy {
72 } 75 }
73 76
74 @Override 77 @Override
75 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { 78 public void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
76 this.dseAdapter = designSpaceExplorationAdapter; 79 this.dseAdapter = designSpaceExplorationAdapter;
77 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); 80 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
78 81
79 trajectoriesToExplore = new PriorityQueue<TrajectoryWithFitness>(11, 82 trajectoriesToExplore = new PriorityQueue<>(11,
80 (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness)); 83 (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness));
81 } 84 }
82 85
83 @Override 86 @Override
84 public void explore() { 87 public void explore() {
88 if (maxSolutions == 0) {
89 return;
90 }
85 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); 91 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
86 92
87 boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); 93 boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
88 if (!globalConstraintsAreSatisfied) { 94 if (!globalConstraintsAreSatisfied) {
89 // "Global constraint is not satisfied in the first state. Terminate."); 95 // Global constraint is not satisfied in the first state. Terminate.
90 return; 96 return;
91 } 97 }
92 98
93 final Fitness firstFitness = dseAdapter.calculateFitness(); 99 final Fitness firstFitness = dseAdapter.getFitness();
94 if (firstFitness.isSatisfiesHardObjectives()) { 100 if (firstFitness.isSatisfiesHardObjectives()) {
95 dseAdapter.newSolution(); 101 dseAdapter.newSolution();
96 // "First state is a solution. Terminate."); 102 // First state is a solution. Terminate.
97 if (backTrackIfSolution) { 103 if (backTrackIfSolution) {
98 return; 104 return;
99 } 105 }
@@ -103,21 +109,20 @@ public class BestFirstStrategy implements Strategy {
103 return; 109 return;
104 } 110 }
105 111
106 final List<Version> firstTrajectory = dseAdapter.getTrajectory(); 112
107 TrajectoryWithFitness currentTrajectoryWithFitness = new TrajectoryWithFitness(firstTrajectory, firstFitness); 113 var firstTrajectoryWithFitness = new TrajectoryWithFitness(dseAdapter.getTrajectory(), firstFitness);
108 trajectoriesToExplore.add(currentTrajectoryWithFitness); 114 trajectoriesToExplore.add(firstTrajectoryWithFitness);
115 TrajectoryWithFitness currentTrajectoryWithFitness = null;
109 116
110 mainLoop: while (true) { 117 mainLoop: while (true) {
111 118
112 if (currentTrajectoryWithFitness == null) { 119 if (currentTrajectoryWithFitness == null) {
113 if (trajectoriesToExplore.isEmpty()) { 120 if (trajectoriesToExplore.isEmpty()) {
114 // "State space is fully traversed."); 121 // State space is fully traversed.
115 return; 122 return;
116 } else { 123 } else {
117 currentTrajectoryWithFitness = trajectoriesToExplore.element(); 124 currentTrajectoryWithFitness = trajectoriesToExplore.element();
118// if (logger.isDebugEnabled()) { 125 // New trajectory is chosen: " + currentTrajectoryWithFitness
119// "New trajectory is chosen: " + currentTrajectoryWithFitness);
120// }
121 dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory); 126 dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory);
122 } 127 }
123 } 128 }
@@ -130,32 +135,34 @@ public class BestFirstStrategy implements Strategy {
130 while (iterator.hasNext()) { 135 while (iterator.hasNext()) {
131 final Activation nextActivation = iterator.next(); 136 final Activation nextActivation = iterator.next();
132 if (!iterator.hasNext()) { 137 if (!iterator.hasNext()) {
133 // "Last untraversed activation of the state."); 138 // Last untraversed activation of the state.
134 trajectoriesToExplore.remove(currentTrajectoryWithFitness); 139 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
135 } 140 }
136 141
137// if (logger.isDebugEnabled()) { 142 // Executing new activation
138// "Executing new activation: " + nextActivation);
139// }
140 dseAdapter.fireActivation(nextActivation); 143 dseAdapter.fireActivation(nextActivation);
141 if (dseAdapter.isCurrentStateAlreadyTraversed()) { 144 if (dseAdapter.isCurrentStateAlreadyTraversed()) {
142 // "The new state is already visited."); 145 // The new state is already visited.
143 dseAdapter.backtrack(); 146 dseAdapter.backtrack();
144 } else if (!dseAdapter.checkGlobalConstraints()) { 147 } else if (!dseAdapter.checkGlobalConstraints()) {
145 // "Global constraint is not satisfied."); 148 // Global constraint is not satisfied.
146 dseAdapter.backtrack(); 149 dseAdapter.backtrack();
147 } else { 150 } else {
148 final Fitness nextFitness = dseAdapter.calculateFitness(); 151 final Fitness nextFitness = dseAdapter.getFitness();
149 if (nextFitness.isSatisfiesHardObjectives()) { 152 if (nextFitness.isSatisfiesHardObjectives()) {
150 dseAdapter.newSolution(); 153 dseAdapter.newSolution();
151 // "Found a solution."); 154 var solutions = dseAdapter.getSolutions().size();
155 if (solutions >= maxSolutions) {
156 return;
157 }
158 // Found a solution.
152 if (backTrackIfSolution) { 159 if (backTrackIfSolution) {
153 dseAdapter.backtrack(); 160 dseAdapter.backtrack();
154 continue; 161 continue;
155 } 162 }
156 } 163 }
157 if (dseAdapter.getDepth() >= maxDepth) { 164 if (dseAdapter.getDepth() >= maxDepth) {
158 // "Reached max depth."); 165 // Reached max depth.
159 dseAdapter.backtrack(); 166 dseAdapter.backtrack();
160 continue; 167 continue;
161 } 168 }
@@ -167,33 +174,30 @@ public class BestFirstStrategy implements Strategy {
167 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness, 174 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness,
168 nextTrajectoryWithFitness.fitness); 175 nextTrajectoryWithFitness.fitness);
169 if (compare < 0) { 176 if (compare < 0) {
170 // "Better fitness, moving on: " + nextFitness); 177 // Better fitness, moving on
171 currentTrajectoryWithFitness = nextTrajectoryWithFitness; 178 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
172 continue mainLoop; 179 continue mainLoop;
173 } else if (compare == 0) { 180 } else if (compare == 0) {
174 if (onlyBetterFirst) { 181 if (onlyBetterFirst) {
175 // "Equally good fitness, backtrack: " + nextFitness); 182 // Equally good fitness, backtrack
176 dseAdapter.backtrack(); 183 dseAdapter.backtrack();
177 continue;
178 } else { 184 } else {
179 // "Equally good fitness, moving on: " + nextFitness); 185 // Equally good fitness, moving on
180 currentTrajectoryWithFitness = nextTrajectoryWithFitness; 186 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
181 continue mainLoop; 187 continue mainLoop;
182 } 188 }
183 } else { 189 } else {
184 // "Worse fitness."); 190 //"Worse fitness
185 currentTrajectoryWithFitness = null; 191 currentTrajectoryWithFitness = null;
186 continue mainLoop; 192 continue mainLoop;
187 } 193 }
188 } 194 }
189 } 195 }
190 196
191 // "State is fully traversed."); 197 // State is fully traversed.
192 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
193 currentTrajectoryWithFitness = null; 198 currentTrajectoryWithFitness = null;
194 199
195 } 200 }
196 // "Interrupted."); 201 // Interrupted.
197
198 } 202 }
199} 203}
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
index 1405789b..0a0caa7e 100644
--- 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
@@ -1,117 +1,92 @@
1/******************************************************************************* 1/*
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro 2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 * 3 *
8 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/ 5 */
10package tools.refinery.store.dse.strategy; 6package tools.refinery.store.dse.strategy;
11 7
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter; 8import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13import tools.refinery.store.dse.Strategy; 9import tools.refinery.store.dse.Strategy;
14import tools.refinery.store.dse.internal.Activation;
15import tools.refinery.store.dse.objectives.Fitness; 10import tools.refinery.store.dse.objectives.Fitness;
16 11
17import java.util.Collection;
18
19public class DepthFirstStrategy implements Strategy { 12public class DepthFirstStrategy implements Strategy {
20 13
21 private DesignSpaceExplorationAdapter dseAdapter; 14 private DesignSpaceExplorationAdapter dseAdapter;
22 15
23 private int maxDepth; 16 private int maxDepth = Integer.MAX_VALUE;
24 private boolean backTrackIfSolution = true; 17 private int maxSolutions = Integer.MAX_VALUE;
18 private boolean backtrackFromSolution = true;
25 19
26 public DepthFirstStrategy() { 20 public DepthFirstStrategy withDepthLimit(int maxDepth) {
27 this(-1); 21 if (maxDepth >= 0) {
22 this.maxDepth = maxDepth;
23 }
24 return this;
28 } 25 }
29 26
30 public DepthFirstStrategy(int maxDepth) { 27 public DepthFirstStrategy withSolutionLimit(int maxSolutions) {
31 if (maxDepth < 0) { 28 if (maxSolutions >= 0) {
32 this.maxDepth = Integer.MAX_VALUE; 29 this.maxSolutions = maxSolutions;
33 } else {
34 this.maxDepth = maxDepth;
35 } 30 }
31 return this;
36 } 32 }
37 33
38 public DepthFirstStrategy continueIfHardObjectivesFulfilled() { 34 public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
39 backTrackIfSolution = false; 35 backtrackFromSolution = false;
40 return this; 36 return this;
41 } 37 }
42 38
43 @Override 39 @Override
44 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { 40 public void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
45 this.dseAdapter = designSpaceExplorationAdapter; 41 this.dseAdapter = designSpaceExplorationAdapter;
46 } 42 }
47 43
48 @Override 44 @Override
49 public void explore() { 45 public void explore() {
50 mainloop: while (true) { 46 if (maxSolutions == 0) {
51 var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); 47 return;
52 if (!globalConstraintsAreSatisfied) { 48 }
53 var isSuccessfulUndo = dseAdapter.backtrack(); 49 while (dseAdapter.getSolutions().size() < maxSolutions) {
54 if (!isSuccessfulUndo) { 50 if (!checkAndHandleGlobalConstraints()) {
55// "Global constraint is not satisfied and cannot backtrack." 51 return;
56 break;
57 }
58 else {
59// "Global constraint is not satisfied, backtrack."
60 continue;
61 }
62 } 52 }
63 53
64 Fitness fitness = dseAdapter.calculateFitness(); 54 Fitness fitness = dseAdapter.getFitness();
65 if (fitness.isSatisfiesHardObjectives()) { 55 if (fitness.isSatisfiesHardObjectives()) {
66 dseAdapter.newSolution(); 56 dseAdapter.newSolution();
67 if (backTrackIfSolution) { 57 if (backtrackFromSolution && !dseAdapter.backtrack()) {
68 var isSuccessfulUndo = dseAdapter.backtrack(); 58 return;
69 if (!isSuccessfulUndo) {
70// "Found a solution but cannot backtrack."
71 break;
72 } else {
73// "Found a solution, backtrack."
74 continue;
75 }
76 } 59 }
77 } 60 }
78 61
79 var depth = dseAdapter.getDepth(); 62 if (!checkAndHandleDepth()) {
80 if (dseAdapter.getDepth() >= maxDepth) { 63 return;
81 var isSuccessfulUndo = dseAdapter.backtrack();
82 if (!isSuccessfulUndo) {
83// "Reached max depth but cannot backtrack."
84 break;
85 }
86 } 64 }
87 65
88 Collection<Activation> activations; 66 if (!backtrackToLastUntraversed()) {
89 do { 67 return;
90 activations = dseAdapter.getUntraversedActivations(); 68 }
91 if (activations.isEmpty()) { 69
92 if (!dseAdapter.backtrack()) { 70 if (!dseAdapter.fireRandomActivation()) {
93 // "No more transitions from current state and cannot backtrack." 71 return;
94 break mainloop; 72 }
95 } 73 }
96 else { 74 }
97 // "No more transitions from current state, backtrack." 75
98 continue; 76 private boolean checkAndHandleGlobalConstraints() {
99 } 77 return dseAdapter.checkGlobalConstraints() || dseAdapter.backtrack();
100 } 78 }
101 } while (activations.isEmpty()); 79
102 80 private boolean checkAndHandleDepth() {
103 dseAdapter.fireRandomActivation(); 81 return dseAdapter.getDepth() < maxDepth || dseAdapter.backtrack();
104// if (dseAdapter.isCurrentInTrajectory()) { 82 }
105// if (!dseAdapter.backtrack()) { 83
106//// TODO: throw exception 84 private boolean backtrackToLastUntraversed() {
107//// "The new state is present in the trajectory but cannot backtrack. Should never happen!" 85 while (dseAdapter.getUntraversedActivations().isEmpty()) {
108// break; 86 if (!dseAdapter.backtrack()) {
109// } 87 return false;
110// else { 88 }
111//// "The new state is already visited in the trajectory, backtrack."
112// continue;
113// }
114// }
115 } 89 }
90 return true;
116 } 91 }
117} 92}
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
index 4bdb05ec..225de32e 100644
--- 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
@@ -5,7 +5,9 @@
5 */ 5 */
6package tools.refinery.store.dse; 6package tools.refinery.store.dse;
7 7
8import org.junit.jupiter.api.Disabled;
8import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
10import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective;
9import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.ModelQueryAdapter; 12import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.Query; 13import tools.refinery.store.query.dnf.Query;
@@ -25,7 +27,7 @@ import java.util.List;
25 27
26import static tools.refinery.store.query.literal.Literals.not; 28import static tools.refinery.store.query.literal.Literals.not;
27 29
28public class CRAExamplesTest { 30class CRAExamplesTest {
29 private static final Symbol<String> name = Symbol.of("Name", 1, String.class); 31 private static final Symbol<String> name = Symbol.of("Name", 1, String.class);
30 32
31// private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); 33// private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
@@ -180,6 +182,7 @@ public class CRAExamplesTest {
180 }); 182 });
181 183
182 @Test 184 @Test
185 @Disabled("This test is only for debugging purposes")
183 void craTest() { 186 void craTest() {
184 var store = ModelStore.builder() 187 var store = ModelStore.builder()
185 .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency, 188 .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency,
@@ -188,11 +191,18 @@ public class CRAExamplesTest {
188 .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition, 191 .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition,
189 deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition, 192 deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition,
190 moveFeaturePrecondition)) 193 moveFeaturePrecondition))
191 .with(ModelVisualizerAdapter.builder()) 194 .with(ModelVisualizerAdapter.builder()
195 .withOutputpath("test_output")
196 .withFormat(FileFormat.DOT)
197 .withFormat(FileFormat.SVG)
198 .saveStates()
199 .saveDesignSpace()
200 )
192 .with(DesignSpaceExplorationAdapter.builder() 201 .with(DesignSpaceExplorationAdapter.builder()
193 .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) 202 .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule)
194// .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled() 203 .objectives(new AlwaysSatisfiedRandomHardObjective())
195 .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled() 204// .strategy(new DepthFirstStrategy().withDepthLimit(3).continueIfHardObjectivesFulfilled()
205 .strategy(new BestFirstStrategy().withDepthLimit(6).continueIfHardObjectivesFulfilled()
196// .goOnOnlyIfFitnessIsBetter() 206// .goOnOnlyIfFitnessIsBetter()
197 )) 207 ))
198 .build(); 208 .build();
@@ -271,9 +281,6 @@ public class CRAExamplesTest {
271 281
272 var states = dseAdapter.explore(); 282 var states = dseAdapter.explore();
273 System.out.println("states size: " + states.size()); 283 System.out.println("states size: " + states.size());
274 System.out.println("states: " + states);
275 var visualizer = model.getAdapter(ModelVisualizerAdapter.class);
276 visualizer.renderDesignSpace("test_output", FileFormat.SVG);
277 } 284 }
278 285
279} 286}
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
index 101a5362..c6da896c 100644
--- 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
@@ -5,7 +5,9 @@
5 */ 5 */
6package tools.refinery.store.dse; 6package tools.refinery.store.dse;
7 7
8import org.junit.jupiter.api.Disabled;
8import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
10import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective;
9import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.ModelQueryAdapter; 12import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.Query; 13import tools.refinery.store.query.dnf.Query;
@@ -20,7 +22,7 @@ import tools.refinery.store.tuple.Tuple;
20import tools.refinery.visualization.ModelVisualizerAdapter; 22import tools.refinery.visualization.ModelVisualizerAdapter;
21import tools.refinery.visualization.internal.FileFormat; 23import tools.refinery.visualization.internal.FileFormat;
22 24
23public class DebugTest { 25class DebugTest {
24 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); 26 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
25 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); 27 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
26 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1); 28 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
@@ -41,6 +43,7 @@ public class DebugTest {
41 43
42 44
43 @Test 45 @Test
46 @Disabled("This test is only for debugging purposes")
44 void BFSTest() { 47 void BFSTest() {
45 var createClassPrecondition = Query.of("CreateClassPrecondition", 48 var createClassPrecondition = Query.of("CreateClassPrecondition",
46 (builder, model) -> builder.clause( 49 (builder, model) -> builder.clause(
@@ -90,11 +93,18 @@ public class DebugTest {
90 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) 93 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
91 .with(ViatraModelQueryAdapter.builder() 94 .with(ViatraModelQueryAdapter.builder()
92 .queries(createClassPrecondition, createFeaturePrecondition)) 95 .queries(createClassPrecondition, createFeaturePrecondition))
93 .with(ModelVisualizerAdapter.builder()) 96 .with(ModelVisualizerAdapter.builder()
97 .withOutputpath("test_output")
98 .withFormat(FileFormat.DOT)
99 .withFormat(FileFormat.SVG)
100 .saveStates()
101 .saveDesignSpace()
102 )
94 .with(DesignSpaceExplorationAdapter.builder() 103 .with(DesignSpaceExplorationAdapter.builder()
95 .transformations(createClassRule, createFeatureRule) 104 .transformations(createClassRule, createFeatureRule)
96 .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() 105 .objectives(new AlwaysSatisfiedRandomHardObjective())
97// .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() 106 .strategy(new DepthFirstStrategy().withDepthLimit(4).continueIfHardObjectivesFulfilled()
107// .strategy(new BestFirstStrategy().withDepthLimit(4).continueIfHardObjectivesFulfilled()
98// .goOnOnlyIfFitnessIsBetter() 108// .goOnOnlyIfFitnessIsBetter()
99 )) 109 ))
100 .build(); 110 .build();
@@ -113,10 +123,7 @@ public class DebugTest {
113 123
114 124
115 var states = dseAdapter.explore(); 125 var states = dseAdapter.explore();
116 var visualizer = model.getAdapter(ModelVisualizerAdapter.class);
117 visualizer.renderDesignSpace("test_output", FileFormat.SVG);
118 System.out.println("states size: " + states.size()); 126 System.out.println("states size: " + states.size());
119 System.out.println("states: " + states);
120 127
121 } 128 }
122} 129}
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
index f4644407..91e33f4a 100644
--- 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
@@ -17,11 +17,10 @@ import tools.refinery.store.query.view.AnySymbolView;
17import tools.refinery.store.query.view.KeyOnlyView; 17import tools.refinery.store.query.view.KeyOnlyView;
18import tools.refinery.store.representation.Symbol; 18import tools.refinery.store.representation.Symbol;
19import tools.refinery.store.tuple.Tuple; 19import tools.refinery.store.tuple.Tuple;
20import tools.refinery.visualization.ModelVisualizerAdapter;
21 20
22import static org.junit.jupiter.api.Assertions.assertEquals; 21import static org.junit.jupiter.api.Assertions.assertEquals;
23 22
24public class DesignSpaceExplorationTest { 23class DesignSpaceExplorationTest {
25// private static final Symbol<Boolean> namedElement = Symbol.of("NamedElement", 1); 24// private static final Symbol<Boolean> namedElement = Symbol.of("NamedElement", 1);
26// private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1); 25// private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1);
27// private static final Symbol<Boolean> method = Symbol.of("Method", 1); 26// private static final Symbol<Boolean> method = Symbol.of("Method", 1);
@@ -50,7 +49,8 @@ public class DesignSpaceExplorationTest {
50 void createObjectTest() { 49 void createObjectTest() {
51 var store = ModelStore.builder() 50 var store = ModelStore.builder()
52 .with(ViatraModelQueryAdapter.builder()) 51 .with(ViatraModelQueryAdapter.builder())
53 .with(DesignSpaceExplorationAdapter.builder()) 52 .with(DesignSpaceExplorationAdapter.builder()
53 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
54 .build(); 54 .build();
55 55
56 var model = store.createEmptyModel(); 56 var model = store.createEmptyModel();
@@ -78,7 +78,8 @@ public class DesignSpaceExplorationTest {
78 void deleteMiddleObjectTest() { 78 void deleteMiddleObjectTest() {
79 var store = ModelStore.builder() 79 var store = ModelStore.builder()
80 .with(ViatraModelQueryAdapter.builder()) 80 .with(ViatraModelQueryAdapter.builder())
81 .with(DesignSpaceExplorationAdapter.builder()) 81 .with(DesignSpaceExplorationAdapter.builder()
82 .strategy(new DepthFirstStrategy()))
82 .build(); 83 .build();
83 84
84 var model = store.createEmptyModel(); 85 var model = store.createEmptyModel();
@@ -118,9 +119,8 @@ public class DesignSpaceExplorationTest {
118 var store = ModelStore.builder() 119 var store = ModelStore.builder()
119 .symbols(classModel) 120 .symbols(classModel)
120 .with(ViatraModelQueryAdapter.builder()) 121 .with(ViatraModelQueryAdapter.builder())
121 .with(ModelVisualizerAdapter.builder())
122 .with(DesignSpaceExplorationAdapter.builder() 122 .with(DesignSpaceExplorationAdapter.builder()
123 .strategy(new DepthFirstStrategy(0))) 123 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
124 .build(); 124 .build();
125 125
126 var model = store.createEmptyModel(); 126 var model = store.createEmptyModel();
@@ -158,10 +158,9 @@ public class DesignSpaceExplorationTest {
158 .symbols(classModel, classElement, classes) 158 .symbols(classModel, classElement, classes)
159 .with(ViatraModelQueryAdapter.builder() 159 .with(ViatraModelQueryAdapter.builder()
160 .queries(createClassPrecondition)) 160 .queries(createClassPrecondition))
161 .with(ModelVisualizerAdapter.builder())
162 .with(DesignSpaceExplorationAdapter.builder() 161 .with(DesignSpaceExplorationAdapter.builder()
163 .transformations(createClassRule) 162 .transformations(createClassRule)
164 .strategy(new DepthFirstStrategy(4) 163 .strategy(new DepthFirstStrategy().withDepthLimit(0)
165 )) 164 ))
166 .build(); 165 .build();
167 166
@@ -205,10 +204,9 @@ public class DesignSpaceExplorationTest {
205 .symbols(classModel, classElement, classes) 204 .symbols(classModel, classElement, classes)
206 .with(ViatraModelQueryAdapter.builder() 205 .with(ViatraModelQueryAdapter.builder()
207 .queries(createClassPrecondition)) 206 .queries(createClassPrecondition))
208 .with(ModelVisualizerAdapter.builder())
209 .with(DesignSpaceExplorationAdapter.builder() 207 .with(DesignSpaceExplorationAdapter.builder()
210 .transformations(createClassRule) 208 .transformations(createClassRule)
211 .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() 209 .strategy(new DepthFirstStrategy().withDepthLimit(4).continueIfHardObjectivesFulfilled()
212 )) 210 ))
213 .build(); 211 .build();
214 212
@@ -274,10 +272,9 @@ public class DesignSpaceExplorationTest {
274 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) 272 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
275 .with(ViatraModelQueryAdapter.builder() 273 .with(ViatraModelQueryAdapter.builder()
276 .queries(createClassPrecondition, createFeaturePrecondition)) 274 .queries(createClassPrecondition, createFeaturePrecondition))
277 .with(ModelVisualizerAdapter.builder())
278 .with(DesignSpaceExplorationAdapter.builder() 275 .with(DesignSpaceExplorationAdapter.builder()
279 .transformations(createClassRule, createFeatureRule) 276 .transformations(createClassRule, createFeatureRule)
280 .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled() 277 .strategy(new DepthFirstStrategy().withDepthLimit(10).continueIfHardObjectivesFulfilled()
281 )) 278 ))
282 .build(); 279 .build();
283 280
@@ -294,13 +291,81 @@ public class DesignSpaceExplorationTest {
294 } 291 }
295 292
296 @Test 293 @Test
297 void BFSTrivialTest() { 294 void DFSSolutionLimitTest() {
295 var createClassPrecondition = Query.of("CreateClassPrecondition",
296 (builder, model) -> builder.clause(
297 classModelView.call(model)
298 ));
299
300 var createClassRule = new TransformationRule("CreateClass",
301 createClassPrecondition,
302 (model) -> {
303 var classesInterpretation = model.getInterpretation(classes);
304 var classElementInterpretation = model.getInterpretation(classElement);
305 return ((Tuple activation) -> {
306 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
307 var modelElement = activation.get(0);
308
309 var newClassElement = dseAdapter.createObject();
310 var newClassElementId = newClassElement.get(0);
311
312 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
313 classElementInterpretation.put(Tuple.of(newClassElementId), true);
314 });
315 });
316
317 var createFeaturePrecondition = Query.of("CreateFeaturePrecondition",
318 (builder, model) -> builder.clause(
319 classModelView.call(model)
320 ));
321
322 var createFeatureRule = new TransformationRule("CreateFeature",
323 createFeaturePrecondition,
324 (model) -> {
325 var featuresInterpretation = model.getInterpretation(features);
326 var featureInterpretation = model.getInterpretation(feature);
327 return ((Tuple activation) -> {
328 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
329 var modelElement = activation.get(0);
330
331 var newClassElement = dseAdapter.createObject();
332 var newClassElementId = newClassElement.get(0);
333
334 featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
335 featureInterpretation.put(Tuple.of(newClassElementId), true);
336 });
337 });
338
339 var store = ModelStore.builder()
340 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
341 .with(ViatraModelQueryAdapter.builder()
342 .queries(createClassPrecondition, createFeaturePrecondition))
343 .with(DesignSpaceExplorationAdapter.builder()
344 .transformations(createClassRule, createFeatureRule)
345 .strategy(new DepthFirstStrategy().withSolutionLimit(222)
346 .continueIfHardObjectivesFulfilled()
347 ))
348 .build();
349
350 var model = store.createEmptyModel();
351 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
352 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
353
354 var modelElementInterpretation = model.getInterpretation(classModel);
355 modelElementInterpretation.put(dseAdapter.createObject(), true);
356 queryEngine.flushChanges();
357
358 var states = dseAdapter.explore();
359 assertEquals(222, states.size());
360 }
361
362 @Test
363 void BeFSTrivialTest() {
298 var store = ModelStore.builder() 364 var store = ModelStore.builder()
299 .symbols(classModel) 365 .symbols(classModel)
300 .with(ViatraModelQueryAdapter.builder()) 366 .with(ViatraModelQueryAdapter.builder())
301 .with(ModelVisualizerAdapter.builder())
302 .with(DesignSpaceExplorationAdapter.builder() 367 .with(DesignSpaceExplorationAdapter.builder()
303 .strategy(new BestFirstStrategy(0))) 368 .strategy(new BestFirstStrategy().withDepthLimit(0)))
304 .build(); 369 .build();
305 370
306 var model = store.createEmptyModel(); 371 var model = store.createEmptyModel();
@@ -311,7 +376,7 @@ public class DesignSpaceExplorationTest {
311 } 376 }
312 377
313 @Test 378 @Test
314 void BFSOneRuleTest() { 379 void BeFSOneRuleTest() {
315 var createClassPrecondition = Query.of("CreateClassPrecondition", 380 var createClassPrecondition = Query.of("CreateClassPrecondition",
316 (builder, model) -> builder.clause( 381 (builder, model) -> builder.clause(
317 classModelView.call(model) 382 classModelView.call(model)
@@ -338,10 +403,9 @@ public class DesignSpaceExplorationTest {
338 .symbols(classModel, classElement, classes) 403 .symbols(classModel, classElement, classes)
339 .with(ViatraModelQueryAdapter.builder() 404 .with(ViatraModelQueryAdapter.builder()
340 .queries(createClassPrecondition)) 405 .queries(createClassPrecondition))
341 .with(ModelVisualizerAdapter.builder())
342 .with(DesignSpaceExplorationAdapter.builder() 406 .with(DesignSpaceExplorationAdapter.builder()
343 .transformations(createClassRule) 407 .transformations(createClassRule)
344 .strategy(new BestFirstStrategy(4) 408 .strategy(new BestFirstStrategy().withDepthLimit(4)
345 )) 409 ))
346 .build(); 410 .build();
347 411
@@ -358,7 +422,7 @@ public class DesignSpaceExplorationTest {
358 } 422 }
359 423
360 @Test 424 @Test
361 void BFSContinueTest() { 425 void BeFSContinueTest() {
362 var createClassPrecondition = Query.of("CreateClassPrecondition", 426 var createClassPrecondition = Query.of("CreateClassPrecondition",
363 (builder, model) -> builder.clause( 427 (builder, model) -> builder.clause(
364 classModelView.call(model) 428 classModelView.call(model)
@@ -385,10 +449,9 @@ public class DesignSpaceExplorationTest {
385 .symbols(classModel, classElement, classes) 449 .symbols(classModel, classElement, classes)
386 .with(ViatraModelQueryAdapter.builder() 450 .with(ViatraModelQueryAdapter.builder()
387 .queries(createClassPrecondition)) 451 .queries(createClassPrecondition))
388 .with(ModelVisualizerAdapter.builder())
389 .with(DesignSpaceExplorationAdapter.builder() 452 .with(DesignSpaceExplorationAdapter.builder()
390 .transformations(createClassRule) 453 .transformations(createClassRule)
391 .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() 454 .strategy(new BestFirstStrategy().withDepthLimit(4).continueIfHardObjectivesFulfilled()
392 )) 455 ))
393 .build(); 456 .build();
394 457
@@ -405,7 +468,7 @@ public class DesignSpaceExplorationTest {
405 } 468 }
406 469
407 @Test 470 @Test
408 void BFSCompletenessTest() { 471 void BeFSCompletenessTest() {
409 var createClassPrecondition = Query.of("CreateClassPrecondition", 472 var createClassPrecondition = Query.of("CreateClassPrecondition",
410 (builder, model) -> builder.clause( 473 (builder, model) -> builder.clause(
411 classModelView.call(model) 474 classModelView.call(model)
@@ -454,10 +517,9 @@ public class DesignSpaceExplorationTest {
454 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) 517 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
455 .with(ViatraModelQueryAdapter.builder() 518 .with(ViatraModelQueryAdapter.builder()
456 .queries(createClassPrecondition, createFeaturePrecondition)) 519 .queries(createClassPrecondition, createFeaturePrecondition))
457 .with(ModelVisualizerAdapter.builder())
458 .with(DesignSpaceExplorationAdapter.builder() 520 .with(DesignSpaceExplorationAdapter.builder()
459 .transformations(createClassRule, createFeatureRule) 521 .transformations(createClassRule, createFeatureRule)
460 .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled() 522 .strategy(new BestFirstStrategy().withDepthLimit(10).continueIfHardObjectivesFulfilled()
461 )) 523 ))
462 .build(); 524 .build();
463 525
@@ -473,4 +535,73 @@ public class DesignSpaceExplorationTest {
473 assertEquals(2047, states.size()); 535 assertEquals(2047, states.size());
474 } 536 }
475 537
538 @Test
539 void BeFSSolutionLimitTest() {
540 var createClassPrecondition = Query.of("CreateClassPrecondition",
541 (builder, model) -> builder.clause(
542 classModelView.call(model)
543 ));
544
545 var createClassRule = new TransformationRule("CreateClass",
546 createClassPrecondition,
547 (model) -> {
548 var classesInterpretation = model.getInterpretation(classes);
549 var classElementInterpretation = model.getInterpretation(classElement);
550 return ((Tuple activation) -> {
551 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
552 var modelElement = activation.get(0);
553
554 var newClassElement = dseAdapter.createObject();
555 var newClassElementId = newClassElement.get(0);
556
557 classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
558 classElementInterpretation.put(Tuple.of(newClassElementId), true);
559 });
560 });
561
562 var createFeaturePrecondition = Query.of("CreateFeaturePrecondition",
563 (builder, model) -> builder.clause(
564 classModelView.call(model)
565 ));
566
567 var createFeatureRule = new TransformationRule("CreateFeature",
568 createFeaturePrecondition,
569 (model) -> {
570 var featuresInterpretation = model.getInterpretation(features);
571 var featureInterpretation = model.getInterpretation(feature);
572 return ((Tuple activation) -> {
573 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
574 var modelElement = activation.get(0);
575
576 var newClassElement = dseAdapter.createObject();
577 var newClassElementId = newClassElement.get(0);
578
579 featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true);
580 featureInterpretation.put(Tuple.of(newClassElementId), true);
581 });
582 });
583
584 var store = ModelStore.builder()
585 .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates)
586 .with(ViatraModelQueryAdapter.builder()
587 .queries(createClassPrecondition, createFeaturePrecondition))
588 .with(DesignSpaceExplorationAdapter.builder()
589 .transformations(createClassRule, createFeatureRule)
590 .strategy(new BestFirstStrategy().withSolutionLimit(222)
591 .continueIfHardObjectivesFulfilled()
592 ))
593 .build();
594
595 var model = store.createEmptyModel();
596 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
597 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
598
599 var modelElementInterpretation = model.getInterpretation(classModel);
600 modelElementInterpretation.put(dseAdapter.createObject(), true);
601 queryEngine.flushChanges();
602
603 var states = dseAdapter.explore();
604 assertEquals(222, states.size());
605 }
606
476} 607}
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
index 312bcebd..5d24d712 100644
--- 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
@@ -6,6 +6,7 @@
6package tools.refinery.store.dse; 6package tools.refinery.store.dse;
7 7
8import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
9import tools.refinery.store.dse.strategy.DepthFirstStrategy;
9import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.ModelQueryAdapter; 11import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
@@ -23,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
23import static tools.refinery.store.query.literal.Literals.not; 24import static tools.refinery.store.query.literal.Literals.not;
24import static tools.refinery.store.dse.tests.QueryAssertions.assertResults; 25import static tools.refinery.store.dse.tests.QueryAssertions.assertResults;
25 26
26public class TransformationRuleTest { 27class TransformationRuleTest {
27 28
28 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1); 29 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
29 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1); 30 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
@@ -103,7 +104,8 @@ public class TransformationRuleTest {
103 .with(ViatraModelQueryAdapter.builder() 104 .with(ViatraModelQueryAdapter.builder()
104 .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper, 105 .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper,
105 deleteEmptyClassPrecondition)) 106 deleteEmptyClassPrecondition))
106 .with(DesignSpaceExplorationAdapter.builder()) 107 .with(DesignSpaceExplorationAdapter.builder()
108 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
107 .build(); 109 .build();
108 110
109 var model = store.createEmptyModel(); 111 var model = store.createEmptyModel();
@@ -137,8 +139,8 @@ public class TransformationRuleTest {
137 139
138 queryEngine.flushChanges(); 140 queryEngine.flushChanges();
139 141
140 var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets(); 142 var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsResultSet();
141 var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets(); 143 var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsResultSet();
142 144
143 assertResults(Map.of( 145 assertResults(Map.of(
144 Tuple.of(newClass1Id, newFieldId), true, 146 Tuple.of(newClass1Id, newFieldId), true,
@@ -195,7 +197,8 @@ public class TransformationRuleTest {
195 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) 197 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
196 .with(ViatraModelQueryAdapter.builder() 198 .with(ViatraModelQueryAdapter.builder()
197 .queries(deleteEmptyClassPrecondition)) 199 .queries(deleteEmptyClassPrecondition))
198 .with(DesignSpaceExplorationAdapter.builder()) 200 .with(DesignSpaceExplorationAdapter.builder()
201 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
199 .build(); 202 .build();
200 203
201 var model = store.createEmptyModel(); 204 var model = store.createEmptyModel();
@@ -236,12 +239,12 @@ public class TransformationRuleTest {
236 assertResults(Map.of( 239 assertResults(Map.of(
237 Tuple.of(newModelId, newClass1Id), true, 240 Tuple.of(newModelId, newClass1Id), true,
238 Tuple.of(newModelId, newClass2Id), true 241 Tuple.of(newModelId, newClass2Id), true
239 ), deleteEmptyClassRule0.getAllActivationsAsSets()); 242 ), deleteEmptyClassRule0.getAllActivationsAsResultSet());
240 243
241 assertResults(Map.of( 244 assertResults(Map.of(
242 Tuple.of(newModelId, newClass1Id), true, 245 Tuple.of(newModelId, newClass1Id), true,
243 Tuple.of(newModelId, newClass2Id), true 246 Tuple.of(newModelId, newClass2Id), true
244 ), deleteEmptyClassRule1.getAllActivationsAsSets()); 247 ), deleteEmptyClassRule1.getAllActivationsAsResultSet());
245 248
246 assertEquals(Tuple.of(newModelId, newClass2Id), activation0); 249 assertEquals(Tuple.of(newModelId, newClass2Id), activation0);
247 assertEquals(Tuple.of(newModelId, newClass1Id), activation1); 250 assertEquals(Tuple.of(newModelId, newClass1Id), activation1);
@@ -276,7 +279,8 @@ public class TransformationRuleTest {
276 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) 279 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
277 .with(ViatraModelQueryAdapter.builder() 280 .with(ViatraModelQueryAdapter.builder()
278 .queries(deleteEmptyClassPrecondition)) 281 .queries(deleteEmptyClassPrecondition))
279 .with(DesignSpaceExplorationAdapter.builder()) 282 .with(DesignSpaceExplorationAdapter.builder()
283 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
280 .build(); 284 .build();
281 285
282 var model = store.createEmptyModel(); 286 var model = store.createEmptyModel();
@@ -312,7 +316,7 @@ public class TransformationRuleTest {
312 assertResults(Map.of( 316 assertResults(Map.of(
313 Tuple.of(newModelId, newClass1Id), true, 317 Tuple.of(newModelId, newClass1Id), true,
314 Tuple.of(newModelId, newClass2Id), true 318 Tuple.of(newModelId, newClass2Id), true
315 ), deleteEmptyClassRule.getAllActivationsAsSets()); 319 ), deleteEmptyClassRule.getAllActivationsAsResultSet());
316 320
317 321
318 deleteEmptyClassRule.fireActivation(Tuple.of(0, 1)); 322 deleteEmptyClassRule.fireActivation(Tuple.of(0, 1));
@@ -320,7 +324,7 @@ public class TransformationRuleTest {
320 assertResults(Map.of( 324 assertResults(Map.of(
321 Tuple.of(newModelId, newClass1Id), false, 325 Tuple.of(newModelId, newClass1Id), false,
322 Tuple.of(newModelId, newClass2Id), true 326 Tuple.of(newModelId, newClass2Id), true
323 ), deleteEmptyClassRule.getAllActivationsAsSets()); 327 ), deleteEmptyClassRule.getAllActivationsAsResultSet());
324 } 328 }
325 329
326 @Test 330 @Test
@@ -352,7 +356,8 @@ public class TransformationRuleTest {
352 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) 356 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
353 .with(ViatraModelQueryAdapter.builder() 357 .with(ViatraModelQueryAdapter.builder()
354 .queries(deleteEmptyClassPrecondition)) 358 .queries(deleteEmptyClassPrecondition))
355 .with(DesignSpaceExplorationAdapter.builder()) 359 .with(DesignSpaceExplorationAdapter.builder()
360 .strategy(new DepthFirstStrategy().withDepthLimit(0)))
356 .build(); 361 .build();
357 362
358 var model = store.createEmptyModel(); 363 var model = store.createEmptyModel();
@@ -388,21 +393,21 @@ public class TransformationRuleTest {
388 assertResults(Map.of( 393 assertResults(Map.of(
389 Tuple.of(newModelId, newClass1Id), true, 394 Tuple.of(newModelId, newClass1Id), true,
390 Tuple.of(newModelId, newClass2Id), true 395 Tuple.of(newModelId, newClass2Id), true
391 ), deleteEmptyClassRule.getAllActivationsAsSets()); 396 ), deleteEmptyClassRule.getAllActivationsAsResultSet());
392 397
393 deleteEmptyClassRule.fireRandomActivation(); 398 deleteEmptyClassRule.fireRandomActivation();
394 399
395 assertResults(Map.of( 400 assertResults(Map.of(
396 Tuple.of(newModelId, newClass1Id), true, 401 Tuple.of(newModelId, newClass1Id), true,
397 Tuple.of(newModelId, newClass2Id), false 402 Tuple.of(newModelId, newClass2Id), false
398 ), deleteEmptyClassRule.getAllActivationsAsSets()); 403 ), deleteEmptyClassRule.getAllActivationsAsResultSet());
399 404
400 deleteEmptyClassRule.fireRandomActivation(); 405 deleteEmptyClassRule.fireRandomActivation();
401 406
402 assertResults(Map.of( 407 assertResults(Map.of(
403 Tuple.of(newModelId, newClass1Id), false, 408 Tuple.of(newModelId, newClass1Id), false,
404 Tuple.of(newModelId, newClass2Id), false 409 Tuple.of(newModelId, newClass2Id), false
405 ), deleteEmptyClassRule.getAllActivationsAsSets()); 410 ), deleteEmptyClassRule.getAllActivationsAsResultSet());
406 411
407 } 412 }
408} 413}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
index bc32323d..ae87d8ac 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
@@ -8,9 +8,10 @@ package tools.refinery.visualization;
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.map.Version; 9import tools.refinery.store.map.Version;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.visualization.internal.FileFormat;
12import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; 11import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl;
13 12
13import java.util.Collection;
14
14public interface ModelVisualizerAdapter extends ModelAdapter { 15public interface ModelVisualizerAdapter extends ModelAdapter {
15 16
16 ModelVisualizerStoreAdapter getStoreAdapter(); 17 ModelVisualizerStoreAdapter getStoreAdapter();
@@ -18,27 +19,14 @@ public interface ModelVisualizerAdapter extends ModelAdapter {
18 return new ModelVisualizerBuilderImpl(); 19 return new ModelVisualizerBuilderImpl();
19 } 20 }
20 21
21 public String createDotForCurrentModelState();
22
23 public String createDotForModelState(Version version);
24
25 public boolean saveDot(String dot, String filePath);
26
27 public boolean renderDot(String dot, String filePath);
28
29 public boolean renderDot(String dot, FileFormat format, String filePath);
30
31 public void addTransition(Version from, Version to, String action); 22 public void addTransition(Version from, Version to, String action);
32 23
33 24
34 public void addTransition(Version from, Version to, String action, Tuple activation); 25 public void addTransition(Version from, Version to, String action, Tuple activation);
35 public void addState(Version state); 26 public void addState(Version state);
27 public void addState(Version state, Collection<Double> fitness);
28 public void addState(Version state, String label);
36 public void addSolution(Version state); 29 public void addSolution(Version state);
37 30 public void visualize();
38 public boolean saveDesignSpace(String path);
39
40 public boolean renderDesignSpace(String path);
41
42 public boolean renderDesignSpace(String path, FileFormat format);
43 31
44} 32}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
index 56cc425e..592f5fcf 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
@@ -6,6 +6,11 @@
6package tools.refinery.visualization; 6package tools.refinery.visualization;
7 7
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.visualization.internal.FileFormat;
9 10
10public interface ModelVisualizerBuilder extends ModelAdapterBuilder { 11public interface ModelVisualizerBuilder extends ModelAdapterBuilder {
12 ModelVisualizerBuilder withOutputpath(String outputpath);
13 ModelVisualizerBuilder withFormat(FileFormat format);
14 ModelVisualizerBuilder saveDesignSpace();
15 ModelVisualizerBuilder saveStates();
11} 16}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java
index 6599d4c3..46663b2a 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java
@@ -6,7 +6,17 @@
6package tools.refinery.visualization; 6package tools.refinery.visualization;
7 7
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.query.ModelQueryStoreAdapter; 9import tools.refinery.visualization.internal.FileFormat;
10
11import java.util.Set;
10 12
11public interface ModelVisualizerStoreAdapter extends ModelStoreAdapter { 13public interface ModelVisualizerStoreAdapter extends ModelStoreAdapter {
14
15 String getOutputPath();
16
17 boolean isRenderDesignSpace();
18
19 boolean isRenderStates();
20
21 Set<FileFormat> getFormats();
12} 22}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java
index b4db2682..04be22d6 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java
@@ -10,11 +10,22 @@ import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
11import tools.refinery.visualization.ModelVisualizerStoreAdapter; 11import tools.refinery.visualization.ModelVisualizerStoreAdapter;
12 12
13import java.util.Set;
14
13public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapter { 15public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapter {
14 private final ModelStore store; 16 private final ModelStore store;
17 private final String outputPath;
18 private final boolean renderDesignSpace;
19 private final boolean renderStates;
20 private final Set<FileFormat> formats;
15 21
16 public ModelVisualizeStoreAdapterImpl(ModelStore store) { 22 public ModelVisualizeStoreAdapterImpl(ModelStore store, String outputPath, Set<FileFormat> formats,
23 boolean renderDesignSpace, boolean renderStates) {
17 this.store = store; 24 this.store = store;
25 this.outputPath = outputPath;
26 this.formats = formats;
27 this.renderDesignSpace = renderDesignSpace;
28 this.renderStates = renderStates;
18 } 29 }
19 30
20 @Override 31 @Override
@@ -26,4 +37,24 @@ public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapt
26 public ModelAdapter createModelAdapter(Model model) { 37 public ModelAdapter createModelAdapter(Model model) {
27 return new ModelVisualizerAdapterImpl(model, this); 38 return new ModelVisualizerAdapterImpl(model, this);
28 } 39 }
40
41 @Override
42 public String getOutputPath() {
43 return outputPath;
44 }
45
46 @Override
47 public boolean isRenderDesignSpace() {
48 return renderDesignSpace;
49 }
50
51 @Override
52 public boolean isRenderStates() {
53 return renderStates;
54 }
55
56 @Override
57 public Set<FileFormat> getFormats() {
58 return formats;
59 }
29} 60}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
index 06cc8113..531969b4 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
@@ -21,38 +21,52 @@ import java.util.stream.Collectors;
21public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { 21public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
22 private final Model model; 22 private final Model model;
23 private final ModelVisualizerStoreAdapter storeAdapter; 23 private final ModelVisualizerStoreAdapter storeAdapter;
24 private final Map<AnySymbol, Interpretation<?>> interpretations; 24 private final Map<AnySymbol, Interpretation<?>> allInterpretations;
25 private final StringBuilder designSpaceBuilder = new StringBuilder(); 25 private final StringBuilder designSpaceBuilder = new StringBuilder();
26 private final Map<Version, Integer> states = new HashMap<>(); 26 private final Map<Version, Integer> states = new HashMap<>();
27 private int transitionCounter = 0; 27 private int transitionCounter = 0;
28 private Integer numberOfStates = 0; 28 private Integer numberOfStates = 0;
29 private static final Map<Object, String> truthValueToDot = new HashMap<>() 29 private final String outputPath;
30 {{ 30 private final Set<FileFormat> formats;
31 put(TruthValue.TRUE, "1"); 31 private final boolean renderDesignSpace;
32 put(TruthValue.FALSE, "0"); 32 private final boolean renderStates;
33 put(TruthValue.UNKNOWN, "½"); 33
34 put(TruthValue.ERROR, "E"); 34 private static final Map<Object, String> truthValueToDot = Map.of(
35 put(true, "1"); 35 TruthValue.TRUE, "1",
36 put(false, "0"); 36 TruthValue.FALSE, "0",
37 }}; 37 TruthValue.UNKNOWN, "½",
38 TruthValue.ERROR, "E",
39 true, "1",
40 false, "0"
41 );
38 42
39 public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) { 43 public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) {
40 this.model = model; 44 this.model = model;
41 this.storeAdapter = storeAdapter; 45 this.storeAdapter = storeAdapter;
42 this.interpretations = new HashMap<>(); 46 this.outputPath = storeAdapter.getOutputPath();
47 this.formats = storeAdapter.getFormats();
48 if (formats.isEmpty()) {
49 formats.add(FileFormat.SVG);
50 }
51 this.renderDesignSpace = storeAdapter.isRenderDesignSpace();
52 this.renderStates = storeAdapter.isRenderStates();
53
54 this.allInterpretations = new HashMap<>();
43 for (var symbol : storeAdapter.getStore().getSymbols()) { 55 for (var symbol : storeAdapter.getStore().getSymbols()) {
44 var arity = symbol.arity(); 56 var arity = symbol.arity();
45 if (arity < 1 || arity > 2) { 57 if (arity < 1 || arity > 2) {
46 continue; 58 continue;
47 } 59 }
48 var interpretation = (Interpretation<?>) model.getInterpretation(symbol); 60 var interpretation = (Interpretation<?>) model.getInterpretation(symbol);
49 interpretations.put(symbol, interpretation); 61 allInterpretations.put(symbol, interpretation);
50 } 62 }
51 designSpaceBuilder.append("digraph designSpace {\n"); 63 designSpaceBuilder.append("digraph designSpace {\n");
52 designSpaceBuilder.append(""" 64 designSpaceBuilder.append("""
65 nodesep=0
66 ranksep=5
53 node[ 67 node[
54 style=filled 68 \tstyle=filled
55 fillcolor=white 69 \tfillcolor=white
56 ] 70 ]
57 """); 71 """);
58 } 72 }
@@ -67,8 +81,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
67 return storeAdapter; 81 return storeAdapter;
68 } 82 }
69 83
70 @Override 84 private String createDotForCurrentModelState() {
71 public String createDotForCurrentModelState() {
72 85
73 var unaryTupleToInterpretationsMap = new HashMap<Tuple, LinkedHashSet<Interpretation<?>>>(); 86 var unaryTupleToInterpretationsMap = new HashMap<Tuple, LinkedHashSet<Interpretation<?>>>();
74 87
@@ -90,7 +103,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
90 ] 103 ]
91 """); 104 """);
92 105
93 for (var entry : interpretations.entrySet()) { 106 for (var entry : allInterpretations.entrySet()) {
94 var key = entry.getKey(); 107 var key = entry.getKey();
95 var arity = key.arity(); 108 var arity = key.arity();
96 var cursor = entry.getValue().getAll(); 109 var cursor = entry.getValue().getAll();
@@ -228,8 +241,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
228 }; 241 };
229 } 242 }
230 243
231 @Override 244 private String createDotForModelState(Version version) {
232 public String createDotForModelState(Version version) {
233 var currentVersion = model.getState(); 245 var currentVersion = model.getState();
234 model.restore(version); 246 model.restore(version);
235 var graph = createDotForCurrentModelState(); 247 var graph = createDotForCurrentModelState();
@@ -237,8 +249,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
237 return graph; 249 return graph;
238 } 250 }
239 251
240 @Override 252 private boolean saveDot(String dot, String filePath) {
241 public boolean saveDot(String dot, String filePath) {
242 File file = new File(filePath); 253 File file = new File(filePath);
243 file.getParentFile().mkdirs(); 254 file.getParentFile().mkdirs();
244 255
@@ -251,13 +262,11 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
251 return true; 262 return true;
252 } 263 }
253 264
254 @Override 265 private boolean renderDot(String dot, String filePath) {
255 public boolean renderDot(String dot, String filePath) {
256 return renderDot(dot, FileFormat.SVG, filePath); 266 return renderDot(dot, FileFormat.SVG, filePath);
257 } 267 }
258 268
259 @Override 269 private boolean renderDot(String dot, FileFormat format, String filePath) {
260 public boolean renderDot(String dot, FileFormat format, String filePath) {
261 try { 270 try {
262 Process process = new ProcessBuilder("dot", "-T" + format.getFormat(), "-o", filePath).start(); 271 Process process = new ProcessBuilder("dot", "-T" + format.getFormat(), "-o", filePath).start();
263 272
@@ -303,6 +312,26 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
303 } 312 }
304 313
305 @Override 314 @Override
315 public void addState(Version state, Collection<Double> fitness) {
316 var labelBuilder = new StringBuilder();
317 for (var f : fitness) {
318 labelBuilder.append(f).append(", ");
319 }
320 addState(state, labelBuilder.toString());
321 }
322
323 @Override
324 public void addState(Version state, String label) {
325 if (states.containsKey(state)) {
326 return;
327 }
328 states.put(state, numberOfStates++);
329 designSpaceBuilder.append(states.get(state)).append(" [label = \"").append(states.get(state)).append(" (");
330 designSpaceBuilder.append(label);
331 designSpaceBuilder.append(")\"\n").append("URL=\"./").append(states.get(state)).append(".svg\"]\n");
332 }
333
334 @Override
306 public void addSolution(Version state) { 335 public void addSolution(Version state) {
307 addState(state); 336 addState(state);
308 designSpaceBuilder.append(states.get(state)).append(" [shape = doublecircle]\n"); 337 designSpaceBuilder.append(states.get(state)).append(" [shape = doublecircle]\n");
@@ -313,8 +342,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
313 return designSpaceBuilder.toString(); 342 return designSpaceBuilder.toString();
314 } 343 }
315 344
316 @Override 345 private boolean saveDesignSpace(String path) {
317 public boolean saveDesignSpace(String path) {
318 saveDot(buildDesignSpaceDot(), path + "/designSpace.dot"); 346 saveDot(buildDesignSpaceDot(), path + "/designSpace.dot");
319 for (var entry : states.entrySet()) { 347 for (var entry : states.entrySet()) {
320 saveDot(createDotForModelState(entry.getKey()), path + "/" + entry.getValue() + ".dot"); 348 saveDot(createDotForModelState(entry.getKey()), path + "/" + entry.getValue() + ".dot");
@@ -322,21 +350,38 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
322 return true; 350 return true;
323 } 351 }
324 352
325 @Override 353 private void renderDesignSpace(String path, Set<FileFormat> formats) {
326 public boolean renderDesignSpace(String path) { 354 File filePath = new File(path);
327 return renderDesignSpace(path, FileFormat.SVG); 355 filePath.mkdirs();
356 if (renderStates) {
357 for (var entry : states.entrySet()) {
358 var stateId = entry.getValue();
359 var stateDot = createDotForModelState(entry.getKey());
360 for (var format : formats) {
361 if (format == FileFormat.DOT) {
362 saveDot(stateDot, path + "/" + stateId + ".dot");
363 }
364 else {
365 renderDot(stateDot, format, path + "/" + stateId + "." + format.getFormat());
366 }
367 }
368 }
369 }
370 if (renderDesignSpace) {
371 var designSpaceDot = buildDesignSpaceDot();
372 for (var format : formats) {
373 if (format == FileFormat.DOT) {
374 saveDot(designSpaceDot, path + "/designSpace.dot");
375 }
376 else {
377 renderDot(designSpaceDot, format, path + "/designSpace." + format.getFormat());
378 }
379 }
380 }
328 } 381 }
329 382
330 @Override 383 @Override
331 public boolean renderDesignSpace(String path, FileFormat format) { 384 public void visualize() {
332 for (var entry : states.entrySet()) { 385 renderDesignSpace(outputPath, formats);
333 var stateId = entry.getValue();
334 var stateDot = createDotForModelState(entry.getKey());
335 saveDot(stateDot, path + "/" + stateId + ".dot");
336 renderDot(stateDot, format, path + "/" + stateId + "." + format.getFormat());
337 }
338 var designSpaceDot = buildDesignSpaceDot();
339 saveDot(designSpaceDot, path + "/designSpace.dot");
340 return renderDot(designSpaceDot, format, path + "/designSpace." + format.getFormat());
341 } 386 }
342} 387}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
index d19cf2cf..e4d801d8 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
@@ -9,11 +9,47 @@ import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
10import tools.refinery.visualization.ModelVisualizerBuilder; 10import tools.refinery.visualization.ModelVisualizerBuilder;
11 11
12import java.util.LinkedHashSet;
13import java.util.Set;
14
12public class ModelVisualizerBuilderImpl 15public class ModelVisualizerBuilderImpl
13 extends AbstractModelAdapterBuilder<ModelVisualizeStoreAdapterImpl> 16 extends AbstractModelAdapterBuilder<ModelVisualizeStoreAdapterImpl>
14 implements ModelVisualizerBuilder { 17 implements ModelVisualizerBuilder {
18 private String outputPath;
19 private boolean saveDesignSpace = false;
20 private boolean saveStates = false;
21 private Set<FileFormat> formats = new LinkedHashSet<>();
22
15 @Override 23 @Override
16 protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) { 24 protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) {
17 return new ModelVisualizeStoreAdapterImpl(store); 25 return new ModelVisualizeStoreAdapterImpl(store, outputPath, formats, saveDesignSpace, saveStates);
26 }
27
28 @Override
29 public ModelVisualizerBuilder withOutputpath(String outputpath) {
30 checkNotConfigured();
31 this.outputPath = outputpath;
32 return this;
33 }
34
35 @Override
36 public ModelVisualizerBuilder withFormat(FileFormat format) {
37 checkNotConfigured();
38 this.formats.add(format);
39 return this;
40 }
41
42 @Override
43 public ModelVisualizerBuilder saveDesignSpace() {
44 checkNotConfigured();
45 this.saveDesignSpace = true;
46 return this;
47 }
48
49 @Override
50 public ModelVisualizerBuilder saveStates() {
51 checkNotConfigured();
52 this.saveStates = true;
53 return this;
18 } 54 }
19} 55}