aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
authorLibravatar nagilooh <ficsorattila96@gmail.com>2023-07-21 16:49:53 +0200
committerLibravatar nagilooh <ficsorattila96@gmail.com>2023-07-26 00:11:53 +0200
commitb34d844a40d0bc4095df6e4d7c4fad4eec2d919b (patch)
tree3abbf039176a432cd4c012ce0fd50fae4be53ca4 /subprojects
parentMerge pull request #30 from OszkarSemerath/datastructure (diff)
downloadrefinery-b34d844a40d0bc4095df6e4d7c4fad4eec2d919b.tar.gz
refinery-b34d844a40d0bc4095df6e4d7c4fad4eec2d919b.tar.zst
refinery-b34d844a40d0bc4095df6e4d7c4fad4eec2d919b.zip
Add Design space exploration and DFS strategy
- Transformation rules - Design Space Exploration adapter - Depth First Strategy
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/store-query-viatra/build.gradle.kts1
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java9
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java55
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java55
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java6
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java10
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java9
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java256
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java77
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java64
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java85
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java51
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java147
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java25
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java21
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java114
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java110
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java218
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java108
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java117
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java403
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java6
22 files changed, 1944 insertions, 3 deletions
diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts
index e3a22145..85ea7e2e 100644
--- a/subprojects/store-query-viatra/build.gradle.kts
+++ b/subprojects/store-query-viatra/build.gradle.kts
@@ -12,4 +12,5 @@ dependencies {
12 implementation(libs.ecore) 12 implementation(libs.ecore)
13 api(libs.viatra) 13 api(libs.viatra)
14 api(project(":refinery-store-query")) 14 api(project(":refinery-store-query"))
15 api(project(":refinery-store-reasoning"))
15} 16}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java
new file mode 100644
index 00000000..e2f452c3
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.query.dse;
2
3import org.eclipse.collections.api.block.procedure.Procedure;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.tuple.Tuple;
6
7public interface ActionFactory {
8 Procedure<Tuple> prepare(Model model);
9}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java
new file mode 100644
index 00000000..e7ce7b2c
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java
@@ -0,0 +1,55 @@
1package tools.refinery.store.query.dse;
2
3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.query.dse.internal.Activation;
5import tools.refinery.store.query.dse.internal.DesignSpaceExplorationBuilderImpl;
6import tools.refinery.store.query.dse.objectives.Fitness;
7import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper;
8import tools.refinery.store.tuple.Tuple;
9import tools.refinery.store.tuple.Tuple1;
10
11import java.util.Collection;
12import java.util.List;
13
14public interface DesignSpaceExplorationAdapter extends ModelAdapter {
15 @Override
16 DesignSpaceExplorationStoreAdapter getStoreAdapter();
17
18 static DesignSpaceExplorationBuilder builder() {
19 return new DesignSpaceExplorationBuilderImpl();
20 }
21
22 Collection<Long> explore();
23
24 public int getModelSize();
25
26 public Tuple1 createObject();
27
28 public Tuple deleteObject(Tuple tuple);
29
30 public boolean checkGlobalConstraints();
31
32 public boolean backtrack();
33
34 public Fitness calculateFitness();
35
36 public void newSolution();
37
38 public int getDepth();
39
40 public Collection<Activation> getUntraversedActivations();
41
42 public boolean fireActivation(Activation activation);
43
44 public void fireRandomActivation();
45
46 public boolean isCurrentInTrajectory();
47
48 public List<Long> getTrajectory();
49
50 public boolean isCurrentStateAlreadyTraversed();
51
52 public ObjectiveComparatorHelper getObjectiveComparatorHelper();
53
54 public void restoreTrajectory(List<Long> trajectory);
55}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java
new file mode 100644
index 00000000..0ec6f599
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java
@@ -0,0 +1,55 @@
1package tools.refinery.store.query.dse;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.query.dnf.AnyQuery;
5import tools.refinery.store.query.dnf.RelationalQuery;
6import tools.refinery.store.query.dse.internal.TransformationRule;
7import tools.refinery.store.query.dse.objectives.Objective;
8
9import java.util.Collection;
10import java.util.List;
11
12public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder {
13 default DesignSpaceExplorationBuilder stopConditions(AnyQuery... stopConditions) {
14 return stopConditions(List.of(stopConditions));
15 }
16
17 default DesignSpaceExplorationBuilder stopConditions(Collection<? extends AnyQuery> stopConditions) {
18 stopConditions.forEach(this::stopCondition);
19 return this;
20 }
21
22 default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) {
23 return transformations(List.of(transformationRules));
24 }
25
26 default DesignSpaceExplorationBuilder transformations(Collection<? extends TransformationRule> transformationRules) {
27 transformationRules.forEach(this::transformation);
28 return this;
29 }
30
31 default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) {
32 return globalConstraints(List.of(globalConstraints));
33 }
34
35 default DesignSpaceExplorationBuilder globalConstraints(Collection<RelationalQuery> globalConstraints) {
36 globalConstraints.forEach(this::globalConstraint);
37 return this;
38 }
39
40 default DesignSpaceExplorationBuilder objectives(Objective... objectives) {
41 return objectives(List.of(objectives));
42 }
43
44 default DesignSpaceExplorationBuilder objectives(Collection<? extends Objective> objectives) {
45 objectives.forEach(this::objective);
46 return this;
47 }
48
49 DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition);
50
51 DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule);
52 DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint);
53 DesignSpaceExplorationBuilder objective(Objective objective);
54 DesignSpaceExplorationBuilder strategy(Strategy strategy);
55}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java
new file mode 100644
index 00000000..21b10f0e
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java
@@ -0,0 +1,6 @@
1package tools.refinery.store.query.dse;
2
3import tools.refinery.store.adapter.ModelStoreAdapter;
4
5public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter {
6}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java
new file mode 100644
index 00000000..0aeea818
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java
@@ -0,0 +1,10 @@
1package tools.refinery.store.query.dse;
2
3import tools.refinery.store.model.Model;
4
5public interface Strategy {
6
7 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter);
8
9 public void explore();
10}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java
new file mode 100644
index 00000000..82a4c978
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.query.dse.internal;
2
3import tools.refinery.store.tuple.Tuple;
4
5public record Activation(TransformationRule transformationRule, Tuple activation) {
6 public boolean fire() {
7 return transformationRule.fireActivation(activation);
8 }
9}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java
new file mode 100644
index 00000000..5adf8306
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java
@@ -0,0 +1,256 @@
1package tools.refinery.store.query.dse.internal;
2
3import tools.refinery.store.model.Interpretation;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.RelationalQuery;
7import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter;
8import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter;
9import tools.refinery.store.query.dse.Strategy;
10import tools.refinery.store.query.dse.objectives.Fitness;
11import tools.refinery.store.query.dse.objectives.LeveledObjectivesHelper;
12import tools.refinery.store.query.dse.objectives.Objective;
13import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper;
14import tools.refinery.store.query.resultset.ResultSet;
15import tools.refinery.store.representation.Symbol;
16import tools.refinery.store.tuple.Tuple;
17import tools.refinery.store.tuple.Tuple1;
18
19import java.util.*;
20
21public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter {
22 static final Symbol<Integer> NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0);
23 private final Model model;
24 private final ModelQueryAdapter queryEngine;
25 private final DesignSpaceExplorationStoreAdapterImpl storeAdapter;
26 private final Set<TransformationRule> transformationRules;
27 private final Set<RelationalQuery> globalConstraints;
28 private final List<Objective> objectives;
29 private final Set<ResultSet<Boolean>> globalConstraintResultSets = new HashSet<>();
30 private final Interpretation<Integer> sizeInterpretation;
31 private final Strategy strategy;
32
33 private ObjectiveComparatorHelper objectiveComparatorHelper;
34 private List<Long> trajectory = new LinkedList<>();
35 private Fitness lastFitness;
36 private final Set<Long> solutions = new HashSet<>();
37// private Map<Long, Collection<Activation>> statesAndActivations;
38 private Map<Long, Collection<Activation>> statesAndUntraversedActivations;
39 private Map<Long, Collection<Activation>> statesAndTraversedActivations;
40 private Random random = new Random();
41 private Objective[][] leveledObjectives;
42 private boolean isNewState = false;
43
44 public List<Long> getTrajectory() {
45 return trajectory;
46 }
47
48 public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) {
49 this.model = model;
50 this.storeAdapter = storeAdapter;
51 this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL);
52 queryEngine = model.getAdapter(ModelQueryAdapter.class);
53
54 globalConstraints = storeAdapter.getGlobalConstraints();
55 for (var constraint : globalConstraints) {
56 globalConstraintResultSets.add(queryEngine.getResultSet(constraint));
57 }
58
59 transformationRules = storeAdapter.getTransformationSpecifications();
60 for (var rule : transformationRules) {
61 rule.prepare(model, queryEngine);
62 }
63
64 objectives = storeAdapter.getObjectives();
65 leveledObjectives = new LeveledObjectivesHelper(objectives).initLeveledObjectives();
66 statesAndUntraversedActivations = new HashMap<>();
67 statesAndTraversedActivations = new HashMap<>();
68 strategy = storeAdapter.getStrategy();
69
70 }
71
72 @Override
73 public Model getModel() {
74 return model;
75 }
76
77 @Override
78 public DesignSpaceExplorationStoreAdapter getStoreAdapter() {
79 return storeAdapter;
80 }
81
82 @Override
83 public Collection<Long> explore() {
84 var state = model.commit();
85 trajectory.add(state);
86 statesAndUntraversedActivations.put(state, getAllActivations());
87 statesAndTraversedActivations.put(state, new HashSet<>());
88 strategy.initStrategy(this);
89 strategy.explore();
90 return solutions;
91 }
92
93 @Override
94 public int getModelSize() {
95 return sizeInterpretation.get(Tuple.of());
96 }
97
98 @Override
99 public Tuple1 createObject() {
100 var newNodeId = getModelSize();
101 sizeInterpretation.put(Tuple.of(), newNodeId + 1);
102 return Tuple.of(newNodeId);
103 }
104
105 @Override
106 public Tuple deleteObject(Tuple tuple) {
107 if (tuple.getSize() != 1) {
108 throw new IllegalArgumentException("Tuple size must be 1");
109 }
110// TODO: implement more efficient deletion
111// if (tuple.get(0) == getModelSize() - 1) {
112// sizeInterpretation.put(Tuple.of(), getModelSize() - 1);
113// }
114 return tuple;
115 }
116
117 @Override
118 public boolean checkGlobalConstraints() {
119 for (var resultSet : globalConstraintResultSets) {
120 if (resultSet.size() > 0) {
121 return false;
122 }
123 }
124 return true;
125 }
126
127 @Override
128 public boolean backtrack() {
129 if (trajectory.size() < 2) {
130 return false;
131 }
132 model.restore(trajectory.get(trajectory.size() - 2));
133 trajectory.remove(trajectory.size() - 1);
134 return true;
135 }
136
137 @Override
138 public void restoreTrajectory(List<Long> trajectory) {
139 model.restore(trajectory.get(trajectory.size() - 1));
140 this.trajectory = trajectory;
141
142 }
143
144 @Override
145 public Fitness calculateFitness() {
146 Fitness result = new Fitness();
147 boolean satisfiesHardObjectives = true;
148 for (Objective objective : objectives) {
149 var fitness = objective.getFitness(this);
150 result.put(objective.getName(), fitness);
151 if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) {
152 satisfiesHardObjectives = false;
153 }
154 }
155 result.setSatisfiesHardObjectives(satisfiesHardObjectives);
156
157 lastFitness = result;
158
159 return result;
160 }
161
162 @Override
163 public void newSolution() {
164 var state = model.getState();
165 solutions.add(state);
166 }
167
168 @Override
169 public int getDepth() {
170 return trajectory.size() - 1;
171 }
172
173 public Collection<Activation> getUntraversedActivations() {
174// return statesAndUntraversedActivations.get(model.getState());
175 List<Activation> untraversedActivations = new ArrayList<>();
176 for (Activation activation : getAllActivations()) {
177 if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) {
178 untraversedActivations.add(activation);
179 }
180 }
181
182 return untraversedActivations;
183 }
184
185 @Override
186 public boolean fireActivation(Activation activation) {
187 if (activation == null) {
188 return false;
189 }
190 long previousState = model.getState();
191 if (!statesAndUntraversedActivations.get(previousState).contains(activation)) {
192// TODO: throw exception?
193 return false;
194 }
195 if (!activation.fire()) {
196 return false;
197 }
198 statesAndUntraversedActivations.get(previousState).remove(activation);
199 statesAndTraversedActivations.get(previousState).add(activation);
200 long newState = model.commit();
201 trajectory.add(newState);
202 isNewState = !statesAndUntraversedActivations.containsKey(newState);
203 statesAndUntraversedActivations.put(newState, getAllActivations());
204 statesAndTraversedActivations.put(newState, new HashSet<>());
205 return true;
206 }
207
208 @Override
209 public void fireRandomActivation() {
210 var activations = getUntraversedActivations();
211 if (activations.isEmpty()) {
212// TODO: throw exception
213 return;
214 }
215 int index = random.nextInt(activations.size());
216 var iterator = activations.iterator();
217 while (index-- > 0) {
218 iterator.next();
219 }
220 var activationId = iterator.next();
221 fireActivation(activationId);
222 }
223
224 @Override
225 public boolean isCurrentInTrajectory() {
226 return trajectory.contains(model.getState());
227 }
228
229 public Collection<Activation> getAllActivations() {
230 Collection<Activation> result = new HashSet<>();
231 for (var rule : transformationRules) {
232 result.addAll(rule.getAllActivations());
233 }
234 return result;
235 }
236
237 public boolean isCurrentStateAlreadyTraversed() {
238// TODO: check isomorphism?
239 return !isNewState;
240 }
241
242 public Fitness getLastFitness() {
243 return lastFitness;
244 }
245
246 public ObjectiveComparatorHelper getObjectiveComparatorHelper() {
247 if (objectiveComparatorHelper == null) {
248 objectiveComparatorHelper = new ObjectiveComparatorHelper(leveledObjectives);
249 }
250 return objectiveComparatorHelper;
251 }
252
253 public Objective[][] getLeveledObjectives() {
254 return leveledObjectives;
255 }
256}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java
new file mode 100644
index 00000000..79864de0
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java
@@ -0,0 +1,77 @@
1package tools.refinery.store.query.dse.internal;
2
3import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.model.ModelStoreBuilder;
6import tools.refinery.store.query.dnf.AnyQuery;
7import tools.refinery.store.query.dnf.RelationalQuery;
8import tools.refinery.store.query.dse.DesignSpaceExplorationBuilder;
9import tools.refinery.store.query.dse.Strategy;
10import tools.refinery.store.query.dse.objectives.Objective;
11
12import java.util.LinkedHashSet;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Set;
16
17public class DesignSpaceExplorationBuilderImpl
18 extends AbstractModelAdapterBuilder<DesignSpaceExplorationStoreAdapterImpl>
19 implements DesignSpaceExplorationBuilder {
20
21 private final Set<AnyQuery> stopConditionSpecifications = new LinkedHashSet<>();
22 private final Set<TransformationRule> transformationSpecifications = new LinkedHashSet<>();
23 private final Set<RelationalQuery> globalConstraints = new LinkedHashSet<>();
24 private final List<Objective> objectives = new LinkedList<>();
25 private Strategy strategy;
26
27 @Override
28 protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) {
29 return new DesignSpaceExplorationStoreAdapterImpl(store, stopConditionSpecifications,
30 transformationSpecifications, globalConstraints, objectives, strategy);
31 }
32
33 @Override
34 public DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition) {
35 checkNotConfigured();
36 stopConditionSpecifications.add(stopCondition);
37 return this;
38 }
39
40 @Override
41 public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) {
42 checkNotConfigured();
43 transformationSpecifications.add(transformationRule);
44 return this;
45 }
46
47 @Override
48 public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) {
49 checkNotConfigured();
50 globalConstraints.add(globalConstraint);
51 return this;
52 }
53
54 @Override
55 public DesignSpaceExplorationBuilder objective(Objective objective) {
56 checkNotConfigured();
57 objectives.add(objective);
58 return this;
59 }
60
61 @Override
62 public DesignSpaceExplorationBuilder strategy(Strategy strategy) {
63 checkNotConfigured();
64 this.strategy = strategy;
65 return this;
66 }
67
68 public Set<AnyQuery> getStopConditionSpecifications() {
69 return stopConditionSpecifications;
70 }
71
72 @Override
73 protected void doConfigure(ModelStoreBuilder storeBuilder) {
74 storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL);
75 super.doConfigure(storeBuilder);
76 }
77}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java
new file mode 100644
index 00000000..9c2fa4d6
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java
@@ -0,0 +1,64 @@
1package tools.refinery.store.query.dse.internal;
2
3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.query.dnf.AnyQuery;
5import tools.refinery.store.query.dnf.RelationalQuery;
6import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter;
7import tools.refinery.store.model.Model;
8import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.query.dse.Strategy;
10import tools.refinery.store.query.dse.objectives.Objective;
11
12import java.util.List;
13import java.util.Set;
14
15public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter {
16 private final ModelStore store;
17 private final Set<AnyQuery> stopConditionSpecifications;
18 private final Set<TransformationRule> transformationSpecifications;
19 private final Set<RelationalQuery> globalConstraints;
20 private final List<Objective> objectives;
21 private final Strategy strategy;
22
23 public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, Set<AnyQuery> stopConditionSpecifications,
24 Set<TransformationRule> transformationSpecifications,
25 Set<RelationalQuery> globalConstraints, List<Objective> objectives,
26 Strategy strategy) {
27 this.store = store;
28 this.stopConditionSpecifications = stopConditionSpecifications;
29 this.transformationSpecifications = transformationSpecifications;
30 this.globalConstraints = globalConstraints;
31 this.objectives = objectives;
32 this.strategy = strategy;
33 }
34
35 @Override
36 public ModelStore getStore() {
37 return store;
38 }
39
40 @Override
41 public ModelAdapter createModelAdapter(Model model) {
42 return new DesignSpaceExplorationAdapterImpl(model, this);
43 }
44
45 public Set<AnyQuery> getStopConditionSpecifications() {
46 return stopConditionSpecifications;
47 }
48
49 public Set<TransformationRule> getTransformationSpecifications() {
50 return transformationSpecifications;
51 }
52
53 public Set<RelationalQuery> getGlobalConstraints() {
54 return globalConstraints;
55 }
56
57 public List<Objective> getObjectives() {
58 return objectives;
59 }
60
61 public Strategy getStrategy() {
62 return strategy;
63 }
64}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java
new file mode 100644
index 00000000..c46ff712
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java
@@ -0,0 +1,85 @@
1package tools.refinery.store.query.dse.internal;
2
3import org.eclipse.collections.api.block.procedure.Procedure;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.RelationalQuery;
7import tools.refinery.store.query.dse.ActionFactory;
8import tools.refinery.store.query.resultset.OrderedResultSet;
9import tools.refinery.store.query.resultset.ResultSet;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.HashSet;
13import java.util.Random;
14import java.util.Set;
15
16public class TransformationRule {
17
18 private final String name;
19 private final RelationalQuery precondition;
20 private final ActionFactory actionFactory;
21 private Procedure<Tuple> action;
22 private OrderedResultSet<Boolean> activations;
23 private Random random;
24 private ModelQueryAdapter queryEngine;
25
26 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) {
27 this(name, precondition, actionFactory, new Random());
28 }
29
30 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) {
31 this(name, precondition, actionFactory, new Random(seed));
32 }
33
34 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) {
35 this.name = name;
36 this.precondition = precondition;
37 this.actionFactory = actionFactory;
38 this.random = random;
39 }
40 public boolean prepare(Model model, ModelQueryAdapter queryEngine) {
41 action = actionFactory.prepare(model);
42 this.queryEngine = queryEngine;
43 activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition));
44 return true;
45 }
46
47 public boolean fireActivation(Tuple activation) {
48 action.accept(activation);
49 queryEngine.flushChanges();
50 return true;
51 }
52
53 public boolean fireRandomActivation() {
54 return getRandomActivation().fire();
55 }
56
57 public String getName() {
58 return name;
59 }
60
61 public RelationalQuery getPrecondition() {
62 return precondition;
63 }
64
65 public ResultSet<Boolean> getAllActivationsAsSets() {
66 return activations;
67 }
68
69 public Set<Activation> getAllActivations() {
70 var result = new HashSet<Activation>();
71 var cursor = activations.getAll();
72 while (cursor.move()) {
73 result.add(new Activation(this, cursor.getKey()));
74 }
75 return result;
76 }
77
78 public Activation getRandomActivation() {
79 return new Activation(this, activations.getKey(random.nextInt(activations.size())));
80 }
81
82 public Activation getActivation(int index) {
83 return new Activation(this, activations.getKey(index));
84 }
85}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java
new file mode 100644
index 00000000..26744d94
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter;
12
13/**
14 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
15 *
16 * @author Andras Szabolcs Nagy
17 *
18 */
19public class AlwaysSatisfiedDummyHardObjective extends BaseObjective {
20
21 private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
22
23 public AlwaysSatisfiedDummyHardObjective() {
24 super(DEFAULT_NAME);
25 }
26
27 public AlwaysSatisfiedDummyHardObjective(String name) {
28 super(name);
29 }
30
31 @Override
32 public Double getFitness(DesignSpaceExplorationAdapter context) {
33 return 0d;
34 }
35
36 @Override
37 public boolean isHardObjective() {
38 return true;
39 }
40
41 @Override
42 public boolean satisfiesHardObjective(Double fitness) {
43 return true;
44 }
45
46 @Override
47 public Objective createNew() {
48 return this;
49 }
50
51}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java
new file mode 100644
index 00000000..fd8529f7
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java
@@ -0,0 +1,147 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter;
12
13import java.util.Comparator;
14import java.util.Objects;
15
16/**
17 * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name,
18 * comparator, level and fitness hard constraint.
19 *
20 * @author Andras Szabolcs Nagy
21 *
22 */
23public abstract class BaseObjective implements Objective {
24
25 protected final String name;
26 protected Comparator<Double> comparator = Comparators.HIGHER_IS_BETTER;
27 protected int level = 0;
28
29 protected double fitnessConstraint;
30 protected boolean isThereFitnessConstraint = false;
31 protected Comparator<Double> fitnessConstraintComparator;
32
33 public BaseObjective(String name) {
34 Objects.requireNonNull(name, "Name of the objective cannot be null.");
35 this.name = name;
36 }
37
38 @Override
39 public String getName() {
40 return name;
41 }
42
43 @Override
44 public void setComparator(Comparator<Double> comparator) {
45 this.comparator = comparator;
46 }
47
48 @Override
49 public Comparator<Double> getComparator() {
50 return comparator;
51 }
52
53 @Override
54 public void setLevel(int level) {
55 this.level = level;
56 }
57
58 @Override
59 public int getLevel() {
60 return level;
61 }
62
63 public BaseObjective withLevel(int level) {
64 setLevel(level);
65 return this;
66 }
67
68 public BaseObjective withComparator(Comparator<Double> comparator) {
69 setComparator(comparator);
70 return this;
71 }
72
73 /**
74 * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
75 * current state as a solution.
76 *
77 * @param fitnessConstraint
78 * Solutions should be better than this value.
79 * @param fitnessConstraintComparator
80 * {@link Comparator} to determine if the current state is better than the given value.
81 * @return The actual instance to enable builder pattern like usage.
82 */
83 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint,
84 Comparator<Double> fitnessConstraintComparator) {
85 this.fitnessConstraint = fitnessConstraint;
86 this.fitnessConstraintComparator = fitnessConstraintComparator;
87 this.isThereFitnessConstraint = true;
88 return this;
89 }
90
91 /**
92 * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
93 * current state as a solution. The provided comparator will be used.
94 *
95 * @param fitnessConstraint
96 * Solutions should be better than this value.
97 * @return The actual instance to enable builder pattern like usage.
98 */
99 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) {
100 return withHardConstraintOnFitness(fitnessConstraint, null);
101 }
102
103 @Override
104 public void init(DesignSpaceExplorationAdapter context) {
105 if (fitnessConstraintComparator == null) {
106 fitnessConstraintComparator = comparator;
107 }
108 }
109
110 @Override
111 public boolean isHardObjective() {
112 return isThereFitnessConstraint;
113 }
114
115 @Override
116 public boolean satisfiesHardObjective(Double fitness) {
117 if (isThereFitnessConstraint) {
118 int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint);
119 if (compare < 0) {
120 return false;
121 }
122 }
123 return true;
124 }
125
126 @Override
127 public int hashCode() {
128 return name.hashCode();
129 }
130
131 @Override
132 public boolean equals(Object obj) {
133 if (this == obj) {
134 return true;
135 }
136 if (obj instanceof BaseObjective baseObjective) {
137 return name.equals(baseObjective.getName());
138 }
139 return false;
140 }
141
142 @Override
143 public String toString() {
144 return name;
145 }
146
147}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java
new file mode 100644
index 00000000..7fba6736
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java
@@ -0,0 +1,25 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import java.util.Comparator;
12
13public class Comparators {
14
15 private Comparators() { /*Utility class constructor*/ }
16
17 public static final Comparator<Double> HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2);
18
19 public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1);
20
21 private static final Double ZERO = (double) 0;
22
23 public static final Comparator<Double> DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2));
24
25}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java
new file mode 100644
index 00000000..ea80ed55
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java
@@ -0,0 +1,21 @@
1package tools.refinery.store.query.dse.objectives;
2
3import java.util.HashMap;
4
5public class Fitness extends HashMap<String, Double> {
6
7 private boolean satisfiesHardObjectives;
8
9 public boolean isSatisfiesHardObjectives() {
10 return satisfiesHardObjectives;
11 }
12
13 public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) {
14 this.satisfiesHardObjectives = satisfiesHardObjectives;
15 }
16
17 @Override
18 public String toString() {
19 return super.toString() + " hardObjectives=" + satisfiesHardObjectives;
20 }
21}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java
new file mode 100644
index 00000000..6c4e7837
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java
@@ -0,0 +1,114 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Comparator;
14import java.util.List;
15
16public class LeveledObjectivesHelper {
17
18 private List<Objective> objectives = new ArrayList<Objective>();
19 private Objective[][] leveledObjectives;
20
21 public LeveledObjectivesHelper(List<Objective> objectives) {
22 this.objectives = objectives;
23 }
24
25 public Objective[][] initLeveledObjectives() {
26 if (objectives.isEmpty()) {
27 leveledObjectives = new Objective[0][0];
28 return leveledObjectives;
29 }
30
31 int level = objectives.get(0).getLevel();
32 boolean oneLevelOnly = true;
33 for (Objective objective : objectives) {
34 if (objective.getLevel() != level) {
35 oneLevelOnly = false;
36 break;
37 }
38 }
39
40 if (oneLevelOnly) {
41 leveledObjectives = new Objective[1][objectives.size()];
42 for (int i = 0; i < objectives.size(); i++) {
43 leveledObjectives[0][i] = objectives.get(i);
44 }
45 return leveledObjectives;
46 }
47
48 Objective[] objectivesArray = getSortedByLevelObjectives(objectives);
49
50 int numberOfLevels = getNumberOfObjectiveLevels(objectivesArray);
51
52 leveledObjectives = new Objective[numberOfLevels][];
53
54 fillLeveledObjectives(objectivesArray);
55
56 return leveledObjectives;
57 }
58
59 private void fillLeveledObjectives(Objective[] objectivesArray) {
60 int actLevel = objectivesArray[0].getLevel();
61 int levelIndex = 0;
62 int lastIndex = 0;
63 int corrigationForLastLevel = 0;
64 boolean oneObjectiveAtLastLevel = false;
65 for (int i = 0; i < objectivesArray.length; i++) {
66 if (i == objectivesArray.length - 1) {
67 corrigationForLastLevel = 1;
68 if (objectivesArray[i - 1].getLevel() != objectivesArray[i].getLevel()) {
69 oneObjectiveAtLastLevel = true;
70 corrigationForLastLevel = 0;
71 }
72 }
73 if (objectivesArray[i].getLevel() != actLevel || corrigationForLastLevel == 1 || oneObjectiveAtLastLevel) {
74 leveledObjectives[levelIndex] = new Objective[i - lastIndex + corrigationForLastLevel];
75 for (int j = lastIndex; j < i + corrigationForLastLevel; j++) {
76 leveledObjectives[levelIndex][j - lastIndex] = objectivesArray[j];
77 }
78 if (oneObjectiveAtLastLevel) {
79 leveledObjectives[levelIndex + 1] = new Objective[1];
80 leveledObjectives[levelIndex + 1][0] = objectivesArray[i];
81 }
82 actLevel = objectivesArray[i].getLevel();
83 levelIndex++;
84 lastIndex = i;
85 }
86 }
87 }
88
89 private int getNumberOfObjectiveLevels(Objective[] objectivesArray) {
90
91 int actLevel = objectivesArray[0].getLevel();
92 int numberOfLevels = 1;
93
94 for (int i = 1; i < objectivesArray.length; i++) {
95 if (objectivesArray[i].getLevel() != actLevel) {
96 numberOfLevels++;
97 actLevel = objectivesArray[i].getLevel();
98 }
99 }
100
101 return numberOfLevels;
102 }
103
104 private Objective[] getSortedByLevelObjectives(List<Objective> objectives) {
105 Objective[] objectivesArray = objectives.toArray(new Objective[objectives.size()]);
106 Arrays.sort(objectivesArray, Comparator.comparingInt(Objective::getLevel));
107 return objectivesArray;
108 }
109
110 public Objective[][] getLeveledObjectives() {
111 return leveledObjectives;
112 }
113
114}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java
new file mode 100644
index 00000000..b160b453
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java
@@ -0,0 +1,110 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter;
12
13import java.util.Comparator;
14
15/**
16 *
17 * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution
18 * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated
19 * value.
20 * <p>
21 * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard
22 * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution.
23 * <p>
24 * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary
25 * for every new thread, and the {@code createNew} method should not return the same instance more than once.
26 *
27 * @author Andras Szabolcs Nagy
28 *
29 */
30public interface Objective {
31
32 /**
33 * Returns the name of the objective.
34 *
35 * @return The name of the objective.
36 */
37 String getName();
38
39 /**
40 * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to
41 * minimize or maximize (or minimize or maximize a delta from a given number).
42 *
43 * @param comparator The comparator.
44 */
45 void setComparator(Comparator<Double> comparator);
46
47 /**
48 * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is
49 * to minimize or maximize (or minimize or maximize a delta from a given number).
50 *
51 * @return The comparator.
52 */
53 Comparator<Double> getComparator();
54
55 /**
56 * Calculates the value of the objective on a given solution (trajectory).
57 *
58 * @param context
59 * The {@link DesignSpaceExplorationAdapter}
60 * @return The objective value in double.
61 */
62 Double getFitness(DesignSpaceExplorationAdapter context);
63
64 /**
65 * Initializes the objective. It is called exactly once for every thread starts.
66 *
67 * @param context
68 * The {@link DesignSpaceExplorationAdapter}.
69 */
70 void init(DesignSpaceExplorationAdapter context);
71
72 /**
73 * Returns an instance of the {@link Objective}. If it returns the same instance, all the methods has to be thread
74 * save as they are called concurrently.
75 *
76 * @return An instance of the objective.
77 */
78 Objective createNew();
79
80 /**
81 * Returns true if the objective is a hard objective. In such a case the method
82 * {@link Objective#satisfiesHardObjective(Double)} is called.
83 *
84 * @return True if the objective is a hard objective.
85 * @see Objective#satisfiesHardObjective(Double)
86 * @see Objective
87 */
88 boolean isHardObjective();
89
90 /**
91 * Determines if the given fitness value satisfies the hard objective.
92 *
93 * @param fitness
94 * The fitness value of a solution.
95 * @return True if it satisfies the hard objective or it is a soft constraint.
96 * @see Objective
97 */
98 boolean satisfiesHardObjective(Double fitness);
99
100 /**
101 * Set the level of the objective.
102 */
103 void setLevel(int level);
104
105 /**
106 * Gets the level of the objective.
107 */
108 int getLevel();
109
110}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java
new file mode 100644
index 00000000..23fb24ee
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java
@@ -0,0 +1,218 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.dse.objectives;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16import java.util.Random;
17
18import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
19
20/**
21 * This class is responsible to compare and sort fitness values. {@link TrajectoryFitness} instances can be added to an
22 * instance of this class, that it can sort them.
23 *
24 * @author András Szabolcs Nagy
25 */
26public class ObjectiveComparatorHelper {
27
28 private Objective[][] leveledObjectives;
29 private List<TrajectoryFitness> trajectoryFitnesses = new ArrayList<TrajectoryFitness>();
30 private Random random = new Random();
31 private boolean computeCrowdingDistance = false;
32
33 public ObjectiveComparatorHelper(Objective[][] leveledObjectives) {
34 this.leveledObjectives = leveledObjectives;
35 }
36
37 public void setComputeCrowdingDistance(boolean computeCrowdingDistance) {
38 this.computeCrowdingDistance = computeCrowdingDistance;
39 }
40
41 /**
42 * Compares two fitnesses based on hierarchical dominance. Returns -1 if the second parameter {@code o2} is a better
43 * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates
44 * {@code o2}) and returns 0 if they are non-dominating each other.
45 */
46 public int compare(Fitness o1, Fitness o2) {
47
48 levelsLoop:
49 for (Objective[] leveledObjective : leveledObjectives) {
50
51 boolean o1HasBetterFitness = false;
52 boolean o2HasBetterFitness = false;
53
54 for (Objective objective : leveledObjective) {
55 String objectiveName = objective.getName();
56 int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName));
57
58 if (sgn < 0) {
59 o2HasBetterFitness = true;
60 }
61 if (sgn > 0) {
62 o1HasBetterFitness = true;
63 }
64 if (o1HasBetterFitness && o2HasBetterFitness) {
65 continue levelsLoop;
66 }
67 }
68 if (o2HasBetterFitness) {
69 return -1;
70 } else if (o1HasBetterFitness) {
71 return 1;
72 }
73 }
74
75 return 0;
76
77 }
78
79 /**
80 * Adds a {@link TrajectoryFitness} to an inner list to compare later.
81 *
82 * @param trajectoryFitness
83 */
84 public void addTrajectoryFitness(TrajectoryFitness trajectoryFitness) {
85 trajectoryFitnesses.add(trajectoryFitness);
86 }
87
88 /**
89 * Clears the inner {@link TrajectoryFitness} list.
90 */
91 public void clearTrajectoryFitnesses() {
92 trajectoryFitnesses.clear();
93 }
94
95 /**
96 * Returns the inner {@link TrajectoryFitness} list.
97 */
98 public List<TrajectoryFitness> getTrajectoryFitnesses() {
99 return trajectoryFitnesses;
100 }
101
102 /**
103 * Returns a random {@link TrajectoryFitness} from the pareto front.
104 */
105 public TrajectoryFitness getRandomBest() {
106 List<TrajectoryFitness> paretoFront = getParetoFront();
107 int randomIndex = random.nextInt(paretoFront.size());
108 return paretoFront.get(randomIndex);
109 }
110
111 /**
112 * Returns the pareto front of the previously added {@link TrajectoryFitness}.
113 */
114 public List<TrajectoryFitness> getParetoFront() {
115 return getFronts().get(0);
116 }
117
118 /**
119 * Returns the previously added {@link TrajectoryFitness} instances in fronts.
120 */
121 public List<? extends List<TrajectoryFitness>> getFronts() {
122 Preconditions.checkArgument(!trajectoryFitnesses.isEmpty(), "No trajectory fitnesses were added.");
123 List<ArrayList<TrajectoryFitness>> fronts = new ArrayList<ArrayList<TrajectoryFitness>>();
124
125 Map<TrajectoryFitness, ArrayList<TrajectoryFitness>> dominatedInstances = new HashMap<TrajectoryFitness, ArrayList<TrajectoryFitness>>();
126 Map<TrajectoryFitness, Integer> dominatingInstances = new HashMap<TrajectoryFitness, Integer>();
127
128 // calculate dominations
129 for (TrajectoryFitness TrajectoryFitnessP : trajectoryFitnesses) {
130 dominatedInstances.put(TrajectoryFitnessP, new ArrayList<TrajectoryFitness>());
131 dominatingInstances.put(TrajectoryFitnessP, 0);
132
133 for (TrajectoryFitness TrajectoryFitnessQ : trajectoryFitnesses) {
134 int dominates = compare(TrajectoryFitnessP.fitness, TrajectoryFitnessQ.fitness);
135 if (dominates > 0) {
136 dominatedInstances.get(TrajectoryFitnessP).add(TrajectoryFitnessQ);
137 } else if (dominates < 0) {
138 dominatingInstances.put(TrajectoryFitnessP, dominatingInstances.get(TrajectoryFitnessP) + 1);
139 }
140 }
141
142 if (dominatingInstances.get(TrajectoryFitnessP) == 0) {
143 // p belongs to the first front
144 TrajectoryFitnessP.rank = 1;
145 if (fronts.isEmpty()) {
146 ArrayList<TrajectoryFitness> firstDominationFront = new ArrayList<TrajectoryFitness>();
147 firstDominationFront.add(TrajectoryFitnessP);
148 fronts.add(firstDominationFront);
149 } else {
150 List<TrajectoryFitness> firstDominationFront = fronts.get(0);
151 firstDominationFront.add(TrajectoryFitnessP);
152 }
153 }
154 }
155
156 // create fronts
157 int i = 1;
158 while (fronts.size() == i) {
159 ArrayList<TrajectoryFitness> nextDominationFront = new ArrayList<TrajectoryFitness>();
160 for (TrajectoryFitness TrajectoryFitnessP : fronts.get(i - 1)) {
161 for (TrajectoryFitness TrajectoryFitnessQ : dominatedInstances.get(TrajectoryFitnessP)) {
162 dominatingInstances.put(TrajectoryFitnessQ, dominatingInstances.get(TrajectoryFitnessQ) - 1);
163 if (dominatingInstances.get(TrajectoryFitnessQ) == 0) {
164 TrajectoryFitnessQ.rank = i + 1;
165 nextDominationFront.add(TrajectoryFitnessQ);
166 }
167 }
168 }
169 i++;
170 if (!nextDominationFront.isEmpty()) {
171 if (computeCrowdingDistance) {
172 crowdingDistanceAssignment(nextDominationFront, leveledObjectives);
173 }
174 fronts.add(nextDominationFront);
175 }
176 }
177
178 return fronts;
179 }
180
181 /**
182 * Executes the crowding distance assignment for the specified front.
183 *
184 * @param front
185 */
186 public static void crowdingDistanceAssignment(List<TrajectoryFitness> front, Objective[][] leveledObjectives) {
187
188 for (TrajectoryFitness InstanceData : front) {
189 // initialize crowding distance
190 InstanceData.crowdingDistance = 0;
191 }
192
193 for (final Objective[] objectives : leveledObjectives) {
194 for (final Objective objective : objectives) {
195
196 final String m = objective.getName();
197 TrajectoryFitness[] sortedFront = front.toArray(new TrajectoryFitness[0]);
198 // sort using m-th objective value
199 Arrays.sort(sortedFront, (o1, o2) -> objective.getComparator().compare(o1.fitness.get(m), o2.fitness.get(m)));
200 // so that boundary points are always selected
201 sortedFront[0].crowdingDistance = Double.POSITIVE_INFINITY;
202 sortedFront[sortedFront.length - 1].crowdingDistance = Double.POSITIVE_INFINITY;
203 // If minimal and maximal fitness value for this objective are
204 // equal, then do not change crowding distance
205 if (sortedFront[0].fitness.get(m) != sortedFront[sortedFront.length - 1].fitness.get(m)) {
206 for (int i = 1; i < sortedFront.length - 1; i++) {
207 double newCrowdingDistance = sortedFront[i].crowdingDistance;
208 newCrowdingDistance += (sortedFront[i + 1].fitness.get(m) - sortedFront[i - 1].fitness.get(m))
209 / (sortedFront[sortedFront.length - 1].fitness.get(m) - sortedFront[0].fitness.get(m));
210
211 sortedFront[i].crowdingDistance = newCrowdingDistance;
212 }
213 }
214 }
215 }
216 }
217
218}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java
new file mode 100644
index 00000000..8192048a
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java
@@ -0,0 +1,108 @@
1package tools.refinery.store.query.dse.strategy;
2
3import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter;
4import tools.refinery.store.query.dse.Strategy;
5import tools.refinery.store.query.dse.internal.Activation;
6import tools.refinery.store.query.dse.objectives.Fitness;
7
8import java.util.Collection;
9
10public class DepthFirstStrategy implements Strategy {
11
12 private DesignSpaceExplorationAdapter dseAdapter;
13
14 private int maxDepth;
15 private boolean backTrackIfSolution = true;
16
17 public DepthFirstStrategy() {
18 this(-1);
19 }
20
21 public DepthFirstStrategy(int maxDepth) {
22 if (maxDepth < 0) {
23 this.maxDepth = Integer.MAX_VALUE;
24 } else {
25 this.maxDepth = maxDepth;
26 }
27 }
28
29 public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
30 backTrackIfSolution = false;
31 return this;
32 }
33
34 @Override
35 public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
36 this.dseAdapter = designSpaceExplorationAdapter;
37 }
38
39 @Override
40 public void explore() {
41 mainloop: while (true) {
42 var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
43 if (!globalConstraintsAreSatisfied) {
44 var isSuccessfulUndo = dseAdapter.backtrack();
45 if (!isSuccessfulUndo) {
46// "Global constraint is not satisfied and cannot backtrack."
47 break;
48 }
49 else {
50// "Global constraint is not satisfied, backtrack."
51 continue;
52 }
53 }
54
55 Fitness fitness = dseAdapter.calculateFitness();
56 if (fitness.isSatisfiesHardObjectives()) {
57 dseAdapter.newSolution();
58 if (backTrackIfSolution) {
59 var isSuccessfulUndo = dseAdapter.backtrack();
60 if (!isSuccessfulUndo) {
61// "Found a solution but cannot backtrack."
62 break;
63 } else {
64// "Found a solution, backtrack."
65 continue;
66 }
67 }
68 }
69
70 var depth = dseAdapter.getDepth();
71 if (dseAdapter.getDepth() >= maxDepth) {
72 var isSuccessfulUndo = dseAdapter.backtrack();
73 if (!isSuccessfulUndo) {
74// "Reached max depth but cannot backtrack."
75 break;
76 }
77 }
78
79 Collection<Activation> activations;
80 do {
81 activations = dseAdapter.getUntraversedActivations();
82 if (activations.isEmpty()) {
83 if (!dseAdapter.backtrack()) {
84 // "No more transitions from current state and cannot backtrack."
85 break mainloop;
86 }
87 else {
88 // "No more transitions from current state, backtrack."
89 continue;
90 }
91 }
92 } while (activations.isEmpty());
93
94 dseAdapter.fireRandomActivation();
95// if (dseAdapter.isCurrentInTrajectory()) {
96// if (!dseAdapter.backtrack()) {
97//// TODO: throw exception
98//// "The new state is present in the trajectory but cannot backtrack. Should never happen!"
99// break;
100// }
101// else {
102//// "The new state is already visited in the trajectory, backtrack."
103// continue;
104// }
105// }
106 }
107 }
108}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java
new file mode 100644
index 00000000..06e2e076
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java
@@ -0,0 +1,117 @@
1package tools.refinery.store.query.dse;
2
3import guru.nidi.graphviz.engine.Format;
4import org.junit.jupiter.api.Test;
5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.dnf.Query;
8import tools.refinery.store.query.dse.internal.TransformationRule;
9import tools.refinery.store.query.dse.strategy.BestFirstStrategy;
10import tools.refinery.store.query.dse.strategy.DepthFirstStrategy;
11import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
12import tools.refinery.store.query.view.AnySymbolView;
13import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.tuple.Tuple;
16import tools.refinery.visualization.ModelVisualizerAdapter;
17
18import java.util.List;
19import java.util.Map;
20
21import static org.junit.jupiter.api.Assertions.assertEquals;
22import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
24
25public class DesignSpaceExplorationTest {
26// private static final Symbol<Boolean> namedElement = Symbol.of("NamedElement", 1);
27// private static final Symbol<Boolean> attribute = Symbol.of("Attribute", 1);
28// private static final Symbol<Boolean> method = Symbol.of("Method", 1);
29// private static final Symbol<Boolean> dataDependency = Symbol.of("DataDependency", 2);
30// private static final Symbol<Boolean> functionalDependency = Symbol.of("FunctionalDependency", 2);
31
32 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
33 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
34 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
35
36 private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
37 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
38
39 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
40 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
41
42 private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
43 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
44 private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
45 private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
46 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
47 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
48 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
49
50 @Test
51 void createObjectTest() {
52 var store = ModelStore.builder()
53 .with(ViatraModelQueryAdapter.builder())
54 .with(DesignSpaceExplorationAdapter.builder())
55 .build();
56
57 var model = store.createEmptyModel();
58 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
59
60 assertEquals(0, dseAdapter.getModelSize());
61
62 var newModel = dseAdapter.createObject();
63 var newModelId = newModel.get(0);
64 var newClass1 = dseAdapter.createObject();
65 var newClass1Id = newClass1.get(0);
66 var newClass2 = dseAdapter.createObject();
67 var newClass2Id = newClass2.get(0);
68 var newField = dseAdapter.createObject();
69 var newFieldId = newField.get(0);
70
71 assertEquals(0, newModelId);
72 assertEquals(1, newClass1Id);
73 assertEquals(2, newClass2Id);
74 assertEquals(3, newFieldId);
75 assertEquals(4, dseAdapter.getModelSize());
76 }
77
78 @Test
79 void deleteMiddleObjectTest() {
80 var store = ModelStore.builder()
81 .with(ViatraModelQueryAdapter.builder())
82 .with(DesignSpaceExplorationAdapter.builder())
83 .build();
84
85 var model = store.createEmptyModel();
86 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
87
88 assertEquals(0, dseAdapter.getModelSize());
89
90 var newObject0 = dseAdapter.createObject();
91 var newObject0Id = newObject0.get(0);
92 var newObject1 = dseAdapter.createObject();
93 var newObject1Id = newObject1.get(0);
94 var newObject2 = dseAdapter.createObject();
95 var newObject2Id = newObject2.get(0);
96 var newObject3 = dseAdapter.createObject();
97 var newObject3Id = newObject3.get(0);
98
99 assertEquals(0, newObject0Id);
100 assertEquals(1, newObject1Id);
101 assertEquals(2, newObject2Id);
102 assertEquals(3, newObject3Id);
103 assertEquals(4, dseAdapter.getModelSize());
104
105 dseAdapter.deleteObject(newObject1);
106 assertEquals(4, dseAdapter.getModelSize());
107
108 var newObject4 = dseAdapter.createObject();
109 var newObject4Id = newObject4.get(0);
110 assertEquals(4, newObject4Id);
111 assertEquals(5, dseAdapter.getModelSize());
112
113 dseAdapter.deleteObject(newObject4);
114 assertEquals(5, dseAdapter.getModelSize());
115 }
116
117}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java
new file mode 100644
index 00000000..1fb3421b
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java
@@ -0,0 +1,403 @@
1package tools.refinery.store.query.dse;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Query;
7import tools.refinery.store.query.dse.internal.TransformationRule;
8import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
9import tools.refinery.store.query.view.AnySymbolView;
10import tools.refinery.store.query.view.KeyOnlyView;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.List;
15import java.util.Map;
16
17import static org.junit.jupiter.api.Assertions.assertEquals;
18import static tools.refinery.store.query.literal.Literals.not;
19import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
20
21public class TransformationRuleTest {
22
23 private static final Symbol<Boolean> classModel = Symbol.of("ClassModel", 1);
24 private static final Symbol<Boolean> classElement = Symbol.of("ClassElement", 1);
25 private static final Symbol<Boolean> feature = Symbol.of("Feature", 1);
26
27 private static final Symbol<Boolean> isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2);
28 private static final Symbol<Boolean> encapsulates = Symbol.of("Encapsulates", 2);
29
30 private static final Symbol<Boolean> features = Symbol.of("Features", 2);
31 private static final Symbol<Boolean> classes = Symbol.of("Classes", 2);
32
33 private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel);
34 private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement);
35 private static final AnySymbolView featureView = new KeyOnlyView<>(feature);
36 private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy);
37 private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates);
38 private static final AnySymbolView featuresView = new KeyOnlyView<>(features);
39 private static final AnySymbolView classesView = new KeyOnlyView<>(classes);
40
41 @Test
42 void activationsTest() {
43 var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper",
44 (builder, model, c, f) -> builder.clause(
45 classElementView.call(c),
46 classesView.call(model, c),
47 encapsulatesView.call(c, f)
48 ));
49
50 var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f)
51 -> builder.clause((model, c1) -> List.of(
52 classModelView.call(model),
53 featureView.call(f),
54 classElementView.call(c2),
55 featuresView.call(model, f),
56 classesView.call(model, c1),
57 not(assignFeaturePreconditionHelper.call(model, c2, f)),
58 not(encapsulatesView.call(c2, f))
59 )));
60
61 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
62 (builder, model, c) -> builder.clause((f) -> List.of(
63 classModelView.call(model),
64 classElementView.call(c),
65 featuresView.call(model, f),
66 not(encapsulatesView.call(c, f))
67 )));
68
69 TransformationRule assignFeatureRule = new TransformationRule("AssignFeature",
70 assignFeaturePrecondition,
71 (model) -> {
72 var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy);
73 return ((Tuple activation) -> {
74 var feature = activation.get(0);
75 var classElement = activation.get(1);
76
77 isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true);
78 });
79 });
80
81 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass",
82 deleteEmptyClassPrecondition,
83 (model) -> {
84 var classesInterpretation = model.getInterpretation(classes);
85 var classElementInterpretation = model.getInterpretation(classElement);
86 return ((Tuple activation) -> {
87 var modelElement = activation.get(0);
88 var classElement = activation.get(1);
89
90 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
91 classElementInterpretation.put(Tuple.of(classElement), false);
92 });
93 });
94
95
96 var store = ModelStore.builder()
97 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
98 .with(ViatraModelQueryAdapter.builder()
99 .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper,
100 deleteEmptyClassPrecondition))
101 .with(DesignSpaceExplorationAdapter.builder())
102 .build();
103
104 var model = store.createEmptyModel();
105 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
106 assignFeatureRule.prepare(model, queryEngine);
107 deleteEmptyClassRule.prepare(model, queryEngine);
108
109 var classModelInterpretation = model.getInterpretation(classModel);
110 var classElementInterpretation = model.getInterpretation(classElement);
111 var featureInterpretation = model.getInterpretation(feature);
112 var featuresInterpretation = model.getInterpretation(features);
113 var classesInterpretation = model.getInterpretation(classes);
114
115 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
116 var newModel = dseAdapter.createObject();
117 var newModelId = newModel.get(0);
118 var newClass1 = dseAdapter.createObject();
119 var newClass1Id = newClass1.get(0);
120 var newClass2 = dseAdapter.createObject();
121 var newClass2Id = newClass2.get(0);
122 var newField = dseAdapter.createObject();
123 var newFieldId = newField.get(0);
124
125 classModelInterpretation.put(newModel, true);
126 classElementInterpretation.put(newClass1, true);
127 classElementInterpretation.put(newClass2, true);
128 featureInterpretation.put(newField, true);
129 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
130 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
131 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
132
133 queryEngine.flushChanges();
134
135 var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets();
136 var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets();
137
138 assertResults(Map.of(
139 Tuple.of(newClass1Id, newFieldId), true,
140 Tuple.of(newClass2Id, newFieldId), true
141 ), assignFeatureRuleActivations);
142
143 assertResults(Map.of(
144 Tuple.of(newModelId, newClass1Id), true,
145 Tuple.of(newModelId, newClass2Id), true
146 ), deleteEmptyClassRuleActivations);
147 }
148
149 @Test
150 void randomActivationTest() {
151 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
152 (builder, model, c) -> builder.clause((f) -> List.of(
153 classModelView.call(model),
154 classElementView.call(c),
155 featuresView.call(model, f),
156 not(encapsulatesView.call(c, f))
157 )));
158
159 TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0",
160 deleteEmptyClassPrecondition,
161 (model) -> {
162 var classesInterpretation = model.getInterpretation(classes);
163 var classElementInterpretation = model.getInterpretation(classElement);
164 return ((Tuple activation) -> {
165 var modelElement = activation.get(0);
166 var classElement = activation.get(1);
167
168 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
169 classElementInterpretation.put(Tuple.of(classElement), false);
170 });
171 },
172 0L);
173
174 TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1",
175 deleteEmptyClassPrecondition,
176 (model) -> {
177 var classesInterpretation = model.getInterpretation(classes);
178 var classElementInterpretation = model.getInterpretation(classElement);
179 return ((Tuple activation) -> {
180 var modelElement = activation.get(0);
181 var classElement = activation.get(1);
182
183 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
184 classElementInterpretation.put(Tuple.of(classElement), false);
185 });
186 },
187 78634L);
188
189 var store = ModelStore.builder()
190 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
191 .with(ViatraModelQueryAdapter.builder()
192 .queries(deleteEmptyClassPrecondition))
193 .with(DesignSpaceExplorationAdapter.builder())
194 .build();
195
196 var model = store.createEmptyModel();
197 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
198 deleteEmptyClassRule0.prepare(model, queryEngine);
199 deleteEmptyClassRule1.prepare(model, queryEngine);
200
201 var classModelInterpretation = model.getInterpretation(classModel);
202 var classElementInterpretation = model.getInterpretation(classElement);
203 var featureInterpretation = model.getInterpretation(feature);
204 var featuresInterpretation = model.getInterpretation(features);
205 var classesInterpretation = model.getInterpretation(classes);
206
207 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
208 var newModel = dseAdapter.createObject();
209 var newModelId = newModel.get(0);
210 var newClass1 = dseAdapter.createObject();
211 var newClass1Id = newClass1.get(0);
212 var newClass2 = dseAdapter.createObject();
213 var newClass2Id = newClass2.get(0);
214 var newField = dseAdapter.createObject();
215 var newFieldId = newField.get(0);
216
217 classModelInterpretation.put(newModel, true);
218 classElementInterpretation.put(newClass1, true);
219 classElementInterpretation.put(newClass2, true);
220 featureInterpretation.put(newField, true);
221 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
222 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
223 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
224
225 queryEngine.flushChanges();
226
227
228 var activation0 = deleteEmptyClassRule0.getRandomActivation().activation();
229 var activation1 = deleteEmptyClassRule1.getRandomActivation().activation();
230
231 assertResults(Map.of(
232 Tuple.of(newModelId, newClass1Id), true,
233 Tuple.of(newModelId, newClass2Id), true
234 ), deleteEmptyClassRule0.getAllActivationsAsSets());
235
236 assertResults(Map.of(
237 Tuple.of(newModelId, newClass1Id), true,
238 Tuple.of(newModelId, newClass2Id), true
239 ), deleteEmptyClassRule1.getAllActivationsAsSets());
240
241 assertEquals(Tuple.of(newModelId, newClass2Id), activation0);
242 assertEquals(Tuple.of(newModelId, newClass1Id), activation1);
243
244 }
245
246 @Test
247 void fireTest() {
248 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
249 (builder, model, c) -> builder.clause((f) -> List.of(
250 classModelView.call(model),
251 classElementView.call(c),
252 featuresView.call(model, f),
253 not(encapsulatesView.call(c, f))
254 )));
255
256 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass",
257 deleteEmptyClassPrecondition,
258 (model) -> {
259 var classesInterpretation = model.getInterpretation(classes);
260 var classElementInterpretation = model.getInterpretation(classElement);
261 return ((Tuple activation) -> {
262 var modelElement = activation.get(0);
263 var classElement = activation.get(1);
264
265 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
266 classElementInterpretation.put(Tuple.of(classElement), false);
267 });
268 });
269
270 var store = ModelStore.builder()
271 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
272 .with(ViatraModelQueryAdapter.builder()
273 .queries(deleteEmptyClassPrecondition))
274 .with(DesignSpaceExplorationAdapter.builder())
275 .build();
276
277 var model = store.createEmptyModel();
278 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
279 deleteEmptyClassRule.prepare(model, queryEngine);
280
281 var classModelInterpretation = model.getInterpretation(classModel);
282 var classElementInterpretation = model.getInterpretation(classElement);
283 var featureInterpretation = model.getInterpretation(feature);
284 var featuresInterpretation = model.getInterpretation(features);
285 var classesInterpretation = model.getInterpretation(classes);
286
287 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
288 var newModel = dseAdapter.createObject();
289 var newModelId = newModel.get(0);
290 var newClass1 = dseAdapter.createObject();
291 var newClass1Id = newClass1.get(0);
292 var newClass2 = dseAdapter.createObject();
293 var newClass2Id = newClass2.get(0);
294 var newField = dseAdapter.createObject();
295 var newFieldId = newField.get(0);
296
297 classModelInterpretation.put(newModel, true);
298 classElementInterpretation.put(newClass1, true);
299 classElementInterpretation.put(newClass2, true);
300 featureInterpretation.put(newField, true);
301 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
302 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
303 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
304
305 queryEngine.flushChanges();
306
307 assertResults(Map.of(
308 Tuple.of(newModelId, newClass1Id), true,
309 Tuple.of(newModelId, newClass2Id), true
310 ), deleteEmptyClassRule.getAllActivationsAsSets());
311
312
313 deleteEmptyClassRule.fireActivation(Tuple.of(0, 1));
314
315 assertResults(Map.of(
316 Tuple.of(newModelId, newClass1Id), false,
317 Tuple.of(newModelId, newClass2Id), true
318 ), deleteEmptyClassRule.getAllActivationsAsSets());
319 }
320
321 @Test
322 void randomFireTest() {
323 var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition",
324 (builder, model, c) -> builder.clause((f) -> List.of(
325 classModelView.call(model),
326 classElementView.call(c),
327 featuresView.call(model, f),
328 not(encapsulatesView.call(c, f))
329 )));
330
331 TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0",
332 deleteEmptyClassPrecondition,
333 (model) -> {
334 var classesInterpretation = model.getInterpretation(classes);
335 var classElementInterpretation = model.getInterpretation(classElement);
336 return ((Tuple activation) -> {
337 var modelElement = activation.get(0);
338 var classElement = activation.get(1);
339
340 classesInterpretation.put(Tuple.of(modelElement, classElement), false);
341 classElementInterpretation.put(Tuple.of(classElement), false);
342 });
343 },
344 0L);
345
346 var store = ModelStore.builder()
347 .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features)
348 .with(ViatraModelQueryAdapter.builder()
349 .queries(deleteEmptyClassPrecondition))
350 .with(DesignSpaceExplorationAdapter.builder())
351 .build();
352
353 var model = store.createEmptyModel();
354 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
355 deleteEmptyClassRule.prepare(model, queryEngine);
356
357 var classModelInterpretation = model.getInterpretation(classModel);
358 var classElementInterpretation = model.getInterpretation(classElement);
359 var featureInterpretation = model.getInterpretation(feature);
360 var featuresInterpretation = model.getInterpretation(features);
361 var classesInterpretation = model.getInterpretation(classes);
362
363 var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
364 var newModel = dseAdapter.createObject();
365 var newModelId = newModel.get(0);
366 var newClass1 = dseAdapter.createObject();
367 var newClass1Id = newClass1.get(0);
368 var newClass2 = dseAdapter.createObject();
369 var newClass2Id = newClass2.get(0);
370 var newField = dseAdapter.createObject();
371 var newFieldId = newField.get(0);
372
373 classModelInterpretation.put(newModel, true);
374 classElementInterpretation.put(newClass1, true);
375 classElementInterpretation.put(newClass2, true);
376 featureInterpretation.put(newField, true);
377 classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true);
378 classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true);
379 featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true);
380
381 queryEngine.flushChanges();
382
383 assertResults(Map.of(
384 Tuple.of(newModelId, newClass1Id), true,
385 Tuple.of(newModelId, newClass2Id), true
386 ), deleteEmptyClassRule.getAllActivationsAsSets());
387
388 deleteEmptyClassRule.fireRandomActivation();
389
390 assertResults(Map.of(
391 Tuple.of(newModelId, newClass1Id), true,
392 Tuple.of(newModelId, newClass2Id), false
393 ), deleteEmptyClassRule.getAllActivationsAsSets());
394
395 deleteEmptyClassRule.fireRandomActivation();
396
397 assertResults(Map.of(
398 Tuple.of(newModelId, newClass1Id), false,
399 Tuple.of(newModelId, newClass2Id), false
400 ), deleteEmptyClassRule.getAllActivationsAsSets());
401
402 }
403}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
index aafbe130..24d4088a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -59,13 +59,13 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
59 59
60 @Override 60 @Override
61 public ModelStore build() { 61 public ModelStore build() {
62 for (int i = adapters.size() - 1; i >= 0; i--) {
63 adapters.get(i).configure(this);
64 }
62 var stores = new HashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size()); 65 var stores = new HashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size());
63 for (var entry : equivalenceClasses.entrySet()) { 66 for (var entry : equivalenceClasses.entrySet()) {
64 createStores(stores, entry.getKey(), entry.getValue()); 67 createStores(stores, entry.getKey(), entry.getValue());
65 } 68 }
66 for (int i = adapters.size() - 1; i >= 0; i--) {
67 adapters.get(i).configure(this);
68 }
69 var modelStore = new ModelStoreImpl(stores, adapters.size()); 69 var modelStore = new ModelStoreImpl(stores, adapters.size());
70 for (var adapterBuilder : adapters) { 70 for (var adapterBuilder : adapters) {
71 var storeAdapter = adapterBuilder.build(modelStore); 71 var storeAdapter = adapterBuilder.build(modelStore);