diff options
23 files changed, 666 insertions, 314 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..c45f088a 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 | ||
@@ -50,8 +52,6 @@ public interface DesignSpaceExplorationAdapter extends ModelAdapter { | |||
50 | 52 | ||
51 | public void fireRandomActivation(); | 53 | public void fireRandomActivation(); |
52 | 54 | ||
53 | public boolean isCurrentInTrajectory(); | ||
54 | |||
55 | public List<Version> getTrajectory(); | 55 | public List<Version> getTrajectory(); |
56 | 56 | ||
57 | public boolean isCurrentStateAlreadyTraversed(); | 57 | public boolean isCurrentStateAlreadyTraversed(); |
@@ -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 @@ | |||
6 | package tools.refinery.store.dse; | 6 | package tools.refinery.store.dse; |
7 | 7 | ||
8 | import tools.refinery.store.adapter.ModelStoreAdapter; | 8 | import tools.refinery.store.adapter.ModelStoreAdapter; |
9 | import tools.refinery.store.dse.internal.TransformationRule; | ||
10 | import tools.refinery.store.dse.objectives.Objective; | ||
11 | import tools.refinery.store.model.Model; | ||
12 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
13 | |||
14 | import java.util.List; | ||
15 | import java.util.Set; | ||
9 | 16 | ||
10 | public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { | 17 | public 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 | ||
8 | public interface Strategy { | 8 | public 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..04bba885 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,26 +240,20 @@ 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 | // TODO: Change to this: |
242 | trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(), | 256 | modelVisualizerAdapter.addTransition(previousState, newState, activation.transformationRule().getName(), |
243 | activation.activation()); | 257 | activation.activation()); |
244 | } | 258 | } |
245 | return true; | 259 | return true; |
@@ -261,15 +275,10 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration | |||
261 | fireActivation(activationId); | 275 | fireActivation(activationId); |
262 | } | 276 | } |
263 | 277 | ||
264 | @Override | 278 | public List<Activation> getAllActivations() { |
265 | public boolean isCurrentInTrajectory() { | 279 | 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) { | 280 | for (var rule : transformationRules) { |
272 | result.addAll(rule.getAllActivations()); | 281 | result.addAll(rule.getAllActivationsAsList()); |
273 | } | 282 | } |
274 | return result; | 283 | return result; |
275 | } | 284 | } |
@@ -279,10 +288,6 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration | |||
279 | return !isNewState; | 288 | return !isNewState; |
280 | } | 289 | } |
281 | 290 | ||
282 | public Fitness getLastFitness() { | ||
283 | return lastFitness; | ||
284 | } | ||
285 | |||
286 | public ObjectiveComparatorHelper getObjectiveComparatorHelper() { | 291 | public ObjectiveComparatorHelper getObjectiveComparatorHelper() { |
287 | if (objectiveComparatorHelper == null) { | 292 | if (objectiveComparatorHelper == null) { |
288 | objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives); | 293 | 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 | */ |
6 | package tools.refinery.store.dse.internal; | 6 | package tools.refinery.store.dse.internal; |
7 | 7 | ||
8 | import tools.refinery.store.adapter.ModelAdapter; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
12 | import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; | 8 | import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; |
13 | import tools.refinery.store.dse.Strategy; | 9 | import tools.refinery.store.dse.Strategy; |
14 | import tools.refinery.store.dse.objectives.Objective; | 10 | import tools.refinery.store.dse.objectives.Objective; |
11 | import tools.refinery.store.model.Model; | ||
12 | import tools.refinery.store.model.ModelStore; | ||
13 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
15 | 14 | ||
16 | import java.util.LinkedHashSet; | ||
17 | import java.util.List; | 15 | import java.util.List; |
16 | import java.util.Set; | ||
18 | 17 | ||
19 | public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { | 18 | public 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; | |||
14 | import tools.refinery.store.query.resultset.ResultSet; | 14 | import tools.refinery.store.query.resultset.ResultSet; |
15 | import tools.refinery.store.tuple.Tuple; | 15 | import tools.refinery.store.tuple.Tuple; |
16 | 16 | ||
17 | import java.util.LinkedHashSet; | 17 | import java.util.*; |
18 | import java.util.Random; | ||
19 | 18 | ||
20 | public class TransformationRule { | 19 | public 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 | *******************************************************************************/ | ||
10 | package tools.refinery.store.dse.objectives; | ||
11 | |||
12 | import tools.refinery.store.dse.DesignSpaceExplorationAdapter; | ||
13 | |||
14 | import 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 | */ | ||
22 | public 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..047b204a 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; | |||
16 | import tools.refinery.store.dse.objectives.Fitness; | 16 | import tools.refinery.store.dse.objectives.Fitness; |
17 | import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; | 17 | import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; |
18 | 18 | ||
19 | import java.util.Collection; | 19 | import java.util.*; |
20 | import java.util.Iterator; | ||
21 | import java.util.List; | ||
22 | import java.util.PriorityQueue; | ||
23 | 20 | ||
24 | public class BestFirstStrategy implements Strategy { | 21 | public 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,31 @@ 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); | 198 | trajectoriesToExplore.remove(currentTrajectoryWithFitness); |
193 | currentTrajectoryWithFitness = null; | 199 | currentTrajectoryWithFitness = null; |
194 | 200 | ||
195 | } | 201 | } |
196 | // "Interrupted."); | 202 | // Interrupted. |
197 | |||
198 | } | 203 | } |
199 | } | 204 | } |
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..5f7f61b8 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,90 @@ | |||
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 | */ |
10 | package tools.refinery.store.dse.strategy; | 6 | package tools.refinery.store.dse.strategy; |
11 | 7 | ||
12 | import tools.refinery.store.dse.DesignSpaceExplorationAdapter; | 8 | import tools.refinery.store.dse.DesignSpaceExplorationAdapter; |
13 | import tools.refinery.store.dse.Strategy; | 9 | import tools.refinery.store.dse.Strategy; |
14 | import tools.refinery.store.dse.internal.Activation; | ||
15 | import tools.refinery.store.dse.objectives.Fitness; | 10 | import tools.refinery.store.dse.objectives.Fitness; |
16 | 11 | ||
17 | import java.util.Collection; | ||
18 | |||
19 | public class DepthFirstStrategy implements Strategy { | 12 | public 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()) { | ||
92 | if (!dseAdapter.backtrack()) { | ||
93 | // "No more transitions from current state and cannot backtrack." | ||
94 | break mainloop; | ||
95 | } | ||
96 | else { | ||
97 | // "No more transitions from current state, backtrack." | ||
98 | continue; | ||
99 | } | ||
100 | } | ||
101 | } while (activations.isEmpty()); | ||
102 | 69 | ||
103 | dseAdapter.fireRandomActivation(); | 70 | dseAdapter.fireRandomActivation(); |
104 | // if (dseAdapter.isCurrentInTrajectory()) { | ||
105 | // if (!dseAdapter.backtrack()) { | ||
106 | //// TODO: throw exception | ||
107 | //// "The new state is present in the trajectory but cannot backtrack. Should never happen!" | ||
108 | // break; | ||
109 | // } | ||
110 | // else { | ||
111 | //// "The new state is already visited in the trajectory, backtrack." | ||
112 | // continue; | ||
113 | // } | ||
114 | // } | ||
115 | } | 71 | } |
116 | } | 72 | } |
73 | |||
74 | private boolean checkAndHandleGlobalConstraints() { | ||
75 | return dseAdapter.checkGlobalConstraints() || dseAdapter.backtrack(); | ||
76 | } | ||
77 | |||
78 | private boolean checkAndHandleDepth() { | ||
79 | return dseAdapter.getDepth() < maxDepth || dseAdapter.backtrack(); | ||
80 | } | ||
81 | |||
82 | private boolean backtrackToLastUntraversed() { | ||
83 | while (dseAdapter.getUntraversedActivations().isEmpty()) { | ||
84 | if (!dseAdapter.backtrack()) { | ||
85 | return false; | ||
86 | } | ||
87 | } | ||
88 | return true; | ||
89 | } | ||
117 | } | 90 | } |
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 | */ |
6 | package tools.refinery.store.dse; | 6 | package tools.refinery.store.dse; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Disabled; | ||
8 | import org.junit.jupiter.api.Test; | 9 | import org.junit.jupiter.api.Test; |
10 | import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective; | ||
9 | import tools.refinery.store.model.ModelStore; | 11 | import tools.refinery.store.model.ModelStore; |
10 | import tools.refinery.store.query.ModelQueryAdapter; | 12 | import tools.refinery.store.query.ModelQueryAdapter; |
11 | import tools.refinery.store.query.dnf.Query; | 13 | import tools.refinery.store.query.dnf.Query; |
@@ -25,7 +27,7 @@ import java.util.List; | |||
25 | 27 | ||
26 | import static tools.refinery.store.query.literal.Literals.not; | 28 | import static tools.refinery.store.query.literal.Literals.not; |
27 | 29 | ||
28 | public class CRAExamplesTest { | 30 | class 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 | */ |
6 | package tools.refinery.store.dse; | 6 | package tools.refinery.store.dse; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Disabled; | ||
8 | import org.junit.jupiter.api.Test; | 9 | import org.junit.jupiter.api.Test; |
10 | import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective; | ||
9 | import tools.refinery.store.model.ModelStore; | 11 | import tools.refinery.store.model.ModelStore; |
10 | import tools.refinery.store.query.ModelQueryAdapter; | 12 | import tools.refinery.store.query.ModelQueryAdapter; |
11 | import tools.refinery.store.query.dnf.Query; | 13 | import tools.refinery.store.query.dnf.Query; |
@@ -20,7 +22,7 @@ import tools.refinery.store.tuple.Tuple; | |||
20 | import tools.refinery.visualization.ModelVisualizerAdapter; | 22 | import tools.refinery.visualization.ModelVisualizerAdapter; |
21 | import tools.refinery.visualization.internal.FileFormat; | 23 | import tools.refinery.visualization.internal.FileFormat; |
22 | 24 | ||
23 | public class DebugTest { | 25 | class 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; | |||
17 | import tools.refinery.store.query.view.KeyOnlyView; | 17 | import tools.refinery.store.query.view.KeyOnlyView; |
18 | import tools.refinery.store.representation.Symbol; | 18 | import tools.refinery.store.representation.Symbol; |
19 | import tools.refinery.store.tuple.Tuple; | 19 | import tools.refinery.store.tuple.Tuple; |
20 | import tools.refinery.visualization.ModelVisualizerAdapter; | ||
21 | 20 | ||
22 | import static org.junit.jupiter.api.Assertions.assertEquals; | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; |
23 | 22 | ||
24 | public class DesignSpaceExplorationTest { | 23 | class 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 @@ | |||
6 | package tools.refinery.store.dse; | 6 | package tools.refinery.store.dse; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.dse.strategy.DepthFirstStrategy; | ||
9 | import tools.refinery.store.model.ModelStore; | 10 | import tools.refinery.store.model.ModelStore; |
10 | import tools.refinery.store.query.ModelQueryAdapter; | 11 | import tools.refinery.store.query.ModelQueryAdapter; |
11 | import tools.refinery.store.query.dnf.Query; | 12 | import tools.refinery.store.query.dnf.Query; |
@@ -23,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; | |||
23 | import static tools.refinery.store.query.literal.Literals.not; | 24 | import static tools.refinery.store.query.literal.Literals.not; |
24 | import static tools.refinery.store.dse.tests.QueryAssertions.assertResults; | 25 | import static tools.refinery.store.dse.tests.QueryAssertions.assertResults; |
25 | 26 | ||
26 | public class TransformationRuleTest { | 27 | class 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; | |||
8 | import tools.refinery.store.adapter.ModelAdapter; | 8 | import tools.refinery.store.adapter.ModelAdapter; |
9 | import tools.refinery.store.map.Version; | 9 | import tools.refinery.store.map.Version; |
10 | import tools.refinery.store.tuple.Tuple; | 10 | import tools.refinery.store.tuple.Tuple; |
11 | import tools.refinery.visualization.internal.FileFormat; | ||
12 | import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; | 11 | import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; |
13 | 12 | ||
13 | import java.util.Collection; | ||
14 | |||
14 | public interface ModelVisualizerAdapter extends ModelAdapter { | 15 | public 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 @@ | |||
6 | package tools.refinery.visualization; | 6 | package tools.refinery.visualization; |
7 | 7 | ||
8 | import tools.refinery.store.adapter.ModelAdapterBuilder; | 8 | import tools.refinery.store.adapter.ModelAdapterBuilder; |
9 | import tools.refinery.visualization.internal.FileFormat; | ||
9 | 10 | ||
10 | public interface ModelVisualizerBuilder extends ModelAdapterBuilder { | 11 | public 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 @@ | |||
6 | package tools.refinery.visualization; | 6 | package tools.refinery.visualization; |
7 | 7 | ||
8 | import tools.refinery.store.adapter.ModelStoreAdapter; | 8 | import tools.refinery.store.adapter.ModelStoreAdapter; |
9 | import tools.refinery.store.query.ModelQueryStoreAdapter; | 9 | import tools.refinery.visualization.internal.FileFormat; |
10 | |||
11 | import java.util.Set; | ||
10 | 12 | ||
11 | public interface ModelVisualizerStoreAdapter extends ModelStoreAdapter { | 13 | public 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; | |||
10 | import tools.refinery.store.model.ModelStore; | 10 | import tools.refinery.store.model.ModelStore; |
11 | import tools.refinery.visualization.ModelVisualizerStoreAdapter; | 11 | import tools.refinery.visualization.ModelVisualizerStoreAdapter; |
12 | 12 | ||
13 | import java.util.Set; | ||
14 | |||
13 | public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapter { | 15 | public 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; | |||
21 | public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { | 21 | public 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; | |||
9 | import tools.refinery.store.model.ModelStore; | 9 | import tools.refinery.store.model.ModelStore; |
10 | import tools.refinery.visualization.ModelVisualizerBuilder; | 10 | import tools.refinery.visualization.ModelVisualizerBuilder; |
11 | 11 | ||
12 | import java.util.LinkedHashSet; | ||
13 | import java.util.Set; | ||
14 | |||
12 | public class ModelVisualizerBuilderImpl | 15 | public 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 | } |