aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-07 23:08:09 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-07 23:08:47 +0200
commit59dff3ea8673e402c576d94a28ec26d3ab181a92 (patch)
treefcc769ea25605a8cd7289c76784db9bfab68defa
parentMerge remote-tracking branch 'nagilooh/datastructure' into partial-interpreta... (diff)
downloadrefinery-59dff3ea8673e402c576d94a28ec26d3ab181a92.tar.gz
refinery-59dff3ea8673e402c576d94a28ec26d3ab181a92.tar.zst
refinery-59dff3ea8673e402c576d94a28ec26d3ab181a92.zip
fix(dse): best-first strategy
The query engine must be flushed after firing a tranformation activation.
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java2
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java6
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java136
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java6
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java29
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java19
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java5
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java35
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java35
-rw-r--r--subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java4
10 files changed, 98 insertions, 179 deletions
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
index 592f5fcf..1ee41cc3 100644
--- a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
@@ -9,7 +9,7 @@ import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.visualization.internal.FileFormat; 9import tools.refinery.visualization.internal.FileFormat;
10 10
11public interface ModelVisualizerBuilder extends ModelAdapterBuilder { 11public interface ModelVisualizerBuilder extends ModelAdapterBuilder {
12 ModelVisualizerBuilder withOutputpath(String outputpath); 12 ModelVisualizerBuilder withOutputPath(String outputPath);
13 ModelVisualizerBuilder withFormat(FileFormat format); 13 ModelVisualizerBuilder withFormat(FileFormat format);
14 ModelVisualizerBuilder saveDesignSpace(); 14 ModelVisualizerBuilder saveDesignSpace();
15 ModelVisualizerBuilder saveStates(); 15 ModelVisualizerBuilder saveStates();
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
index e4d801d8..9ba2abe8 100644
--- a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
@@ -18,7 +18,7 @@ public class ModelVisualizerBuilderImpl
18 private String outputPath; 18 private String outputPath;
19 private boolean saveDesignSpace = false; 19 private boolean saveDesignSpace = false;
20 private boolean saveStates = false; 20 private boolean saveStates = false;
21 private Set<FileFormat> formats = new LinkedHashSet<>(); 21 private final Set<FileFormat> formats = new LinkedHashSet<>();
22 22
23 @Override 23 @Override
24 protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) { 24 protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) {
@@ -26,9 +26,9 @@ public class ModelVisualizerBuilderImpl
26 } 26 }
27 27
28 @Override 28 @Override
29 public ModelVisualizerBuilder withOutputpath(String outputpath) { 29 public ModelVisualizerBuilder withOutputPath(String outputPath) {
30 checkNotConfigured(); 30 checkNotConfigured();
31 this.outputPath = outputpath; 31 this.outputPath = outputPath;
32 return this; 32 return this;
33 } 33 }
34 34
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
index a2b6268f..8f7e3bdc 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
@@ -5,7 +5,6 @@
5 */ 5 */
6package tools.refinery.store.dse.strategy; 6package tools.refinery.store.dse.strategy;
7 7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
10 9
11import java.util.Random; 10import java.util.Random;
@@ -13,6 +12,7 @@ import java.util.Random;
13public class BestFirstExplorer extends BestFirstWorker { 12public class BestFirstExplorer extends BestFirstWorker {
14 final int id; 13 final int id;
15 Random random; 14 Random random;
15
16 public BestFirstExplorer(BestFirstStoreManager storeManager, Model model, int id) { 16 public BestFirstExplorer(BestFirstStoreManager storeManager, Model model, int id) {
17 super(storeManager, model); 17 super(storeManager, model);
18 this.id = id; 18 this.id = id;
@@ -20,6 +20,7 @@ public class BestFirstExplorer extends BestFirstWorker {
20 } 20 }
21 21
22 private boolean interrupted = false; 22 private boolean interrupted = false;
23
23 public void interrupt() { 24 public void interrupt() {
24 this.interrupted = true; 25 this.interrupted = true;
25 } 26 }
@@ -29,138 +30,37 @@ public class BestFirstExplorer extends BestFirstWorker {
29 } 30 }
30 31
31 public void explore() { 32 public void explore() {
32 VersionWithObjectiveValue lastVisited = submit().newVersion(); 33 var lastBest = submit().newVersion();
33
34 while (shouldRun()) { 34 while (shouldRun()) {
35 35 if (lastBest == null) {
36 if (lastVisited == null) { 36 lastBest = restoreToBest();
37 lastVisited = this.restoreToBest(); 37 if (lastBest == null) {
38 if(lastVisited == null) {
39 return; 38 return;
40 } 39 }
41 } 40 }
42
43 boolean tryActivation = true; 41 boolean tryActivation = true;
44 while(tryActivation && shouldRun()) { 42 while (tryActivation && shouldRun()) {
45 RandomVisitResult randomVisitResult = this.visitRandomUnvisited(random); 43 var randomVisitResult = this.visitRandomUnvisited(random);
46
47 tryActivation = randomVisitResult.shouldRetry(); 44 tryActivation = randomVisitResult.shouldRetry();
48 var newSubmit = randomVisitResult.submitResult(); 45 var newSubmit = randomVisitResult.submitResult();
49 if(newSubmit != null) { 46 if (newSubmit != null) {
50 if(!newSubmit.include()) { 47 if (!newSubmit.include()) {
51 restoreToLast(); 48 restoreToLast();
52 } else { 49 } else {
53 var newVisit = newSubmit.newVersion(); 50 var newVisit = newSubmit.newVersion();
54 int compareResult = compare(lastVisited,newVisit); 51 int compareResult = compare(lastBest, newVisit);
55 if(compareResult >= 0) { 52 if (compareResult >= 0) {
56 lastVisited = newVisit; 53 lastBest = newVisit;
57 break;
58 }
59 }
60 }
61 else {
62 lastVisited = null;
63 break;
64 }
65 }
66
67 //final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
68
69 /*boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
70 if (!globalConstraintsAreSatisfied) {
71 // Global constraint is not satisfied in the first state. Terminate.
72 return;
73 }
74
75 final Fitness firstFitness = dseAdapter.getFitness();
76 if (firstFitness.isSatisfiesHardObjectives()) {
77 dseAdapter.newSolution();
78 // First state is a solution. Terminate.
79 if (backTrackIfSolution) {
80 return;
81 }
82 }
83
84 if (maxDepth == 0) {
85 return;
86 }*/
87
88 /*
89 var firstTrajectoryWithFitness = new TrajectoryWithFitness(dseAdapter.getTrajectory(), firstFitness);
90 trajectoriesToExplore.add(firstTrajectoryWithFitness);
91 TrajectoryWithFitness currentTrajectoryWithFitness = null;
92 */
93/*
94 Collection<Activation> activations = dseAdapter.getUntraversedActivations();
95 Iterator<Activation> iterator = activations.iterator();
96
97 while (iterator.hasNext()) {
98 final Activation nextActivation = iterator.next();
99 if (!iterator.hasNext()) {
100 // Last untraversed activation of the state.
101 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
102 }
103
104 // Executing new activation
105 dseAdapter.fireActivation(nextActivation);
106 if (dseAdapter.isCurrentStateAlreadyTraversed()) {
107 // The new state is already visited.
108 dseAdapter.backtrack();
109 } else if (!dseAdapter.checkGlobalConstraints()) {
110 // Global constraint is not satisfied.
111 dseAdapter.backtrack();
112 } else {
113 final Fitness nextFitness = dseAdapter.getFitness();
114 if (nextFitness.isSatisfiesHardObjectives()) {
115 dseAdapter.newSolution();
116 var solutions = dseAdapter.getSolutions().size();
117 if (solutions >= maxSolutions) {
118 return;
119 }
120 // Found a solution.
121 if (backTrackIfSolution) {
122 dseAdapter.backtrack();
123 continue;
124 }
125 }
126 if (dseAdapter.getDepth() >= maxDepth) {
127 // Reached max depth.
128 dseAdapter.backtrack();
129 continue;
130 }
131
132 TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness(
133 dseAdapter.getTrajectory(), nextFitness);
134 trajectoriesToExplore.add(nextTrajectoryWithFitness);
135
136 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness,
137 nextTrajectoryWithFitness.fitness);
138 if (compare < 0) {
139 // Better fitness, moving on
140 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
141 continue mainLoop;
142 } else if (compare == 0) {
143 if (onlyBetterFirst) {
144 // Equally good fitness, backtrack
145 dseAdapter.backtrack();
146 } else { 54 } else {
147 // Equally good fitness, moving on 55 lastBest = null;
148 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
149 continue mainLoop;
150 } 56 }
151 } else { 57 break;
152 //"Worse fitness
153 currentTrajectoryWithFitness = null;
154 continue mainLoop;
155 } 58 }
59 } else {
60 lastBest = null;
61 break;
156 } 62 }
157 } 63 }
158
159 // State is fully traversed.
160 currentTrajectoryWithFitness = null;
161*/
162 } 64 }
163 // Interrupted.
164
165 } 65 }
166} 66}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java
index 4ccba6f7..02634a02 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java
@@ -17,9 +17,7 @@ import tools.refinery.store.dse.transition.statespace.internal.ObjectivePriority
17import tools.refinery.store.dse.transition.statespace.internal.SolutionStoreImpl; 17import tools.refinery.store.dse.transition.statespace.internal.SolutionStoreImpl;
18import tools.refinery.store.map.Version; 18import tools.refinery.store.map.Version;
19import tools.refinery.store.model.ModelStore; 19import tools.refinery.store.model.ModelStore;
20import tools.refinery.store.statecoding.StateCoderResult;
21import tools.refinery.store.statecoding.StateCoderStoreAdapter; 20import tools.refinery.store.statecoding.StateCoderStoreAdapter;
22import tools.refinery.visualization.ModelVisualizerStoreAdapter;
23import tools.refinery.visualization.statespace.VisualizationStore; 21import tools.refinery.visualization.statespace.VisualizationStore;
24import tools.refinery.visualization.statespace.internal.VisualizationStoreImpl; 22import tools.refinery.visualization.statespace.internal.VisualizationStoreImpl;
25 23
@@ -34,7 +32,7 @@ public class BestFirstStoreManager {
34 EquivalenceClassStore equivalenceClassStore; 32 EquivalenceClassStore equivalenceClassStore;
35 VisualizationStore visualizationStore; 33 VisualizationStore visualizationStore;
36 34
37 public BestFirstStoreManager(ModelStore modelStore) { 35 public BestFirstStoreManager(ModelStore modelStore, int maxNumberOfSolutions) {
38 this.modelStore = modelStore; 36 this.modelStore = modelStore;
39 DesignSpaceExplorationStoreAdapter storeAdapter = 37 DesignSpaceExplorationStoreAdapter storeAdapter =
40 modelStore.getAdapter(DesignSpaceExplorationStoreAdapter.class); 38 modelStore.getAdapter(DesignSpaceExplorationStoreAdapter.class);
@@ -42,7 +40,7 @@ public class BestFirstStoreManager {
42 objectiveStore = new ObjectivePriorityQueueImpl(storeAdapter.getObjectives()); 40 objectiveStore = new ObjectivePriorityQueueImpl(storeAdapter.getObjectives());
43 Consumer<VersionWithObjectiveValue> whenAllActivationsVisited = x -> objectiveStore.remove(x); 41 Consumer<VersionWithObjectiveValue> whenAllActivationsVisited = x -> objectiveStore.remove(x);
44 activationStore = new ActivationStoreImpl(storeAdapter.getTransformations().size(), whenAllActivationsVisited); 42 activationStore = new ActivationStoreImpl(storeAdapter.getTransformations().size(), whenAllActivationsVisited);
45 solutionStore = new SolutionStoreImpl(50); 43 solutionStore = new SolutionStoreImpl(maxNumberOfSolutions);
46 equivalenceClassStore = new FastEquivalenceClassStore(modelStore.getAdapter(StateCoderStoreAdapter.class)) { 44 equivalenceClassStore = new FastEquivalenceClassStore(modelStore.getAdapter(StateCoderStoreAdapter.class)) {
47 @Override 45 @Override
48 protected void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept) { 46 protected void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept) {
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java
index f1bec14f..5d738297 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java
@@ -40,11 +40,13 @@ public class BestFirstWorker {
40 isVisualizationEnabled = visualizationStore != null; 40 isVisualizationEnabled = visualizationStore != null;
41 } 41 }
42 42
43 private VersionWithObjectiveValue last = null; 43 protected VersionWithObjectiveValue last = null;
44
45 //public boolean isIncluded
46 44
47 public SubmitResult submit() { 45 public SubmitResult submit() {
46 checkSynchronized();
47 if (queryAdapter.hasPendingChanges()) {
48 throw new AssertionError("Pending changes detected before model submission");
49 }
48 if (explorationAdapter.checkExclude()) { 50 if (explorationAdapter.checkExclude()) {
49 return new SubmitResult(false, false, null, null); 51 return new SubmitResult(false, false, null, null);
50 } 52 }
@@ -86,14 +88,11 @@ public class BestFirstWorker {
86 88
87 public VersionWithObjectiveValue restoreToBest() { 89 public VersionWithObjectiveValue restoreToBest() {
88 var bestVersion = storeManager.getObjectiveStore().getBest(); 90 var bestVersion = storeManager.getObjectiveStore().getBest();
91 last = bestVersion;
89 if (bestVersion != null) { 92 if (bestVersion != null) {
90 var oldVersion = model.getState();
91 this.model.restore(bestVersion.version()); 93 this.model.restore(bestVersion.version());
92 if (isVisualizationEnabled) {
93 visualizationStore.addTransition(oldVersion, last.version(), "");
94 }
95 } 94 }
96 return bestVersion; 95 return last;
97 } 96 }
98 97
99 public VersionWithObjectiveValue restoreToRandom(Random random) { 98 public VersionWithObjectiveValue restoreToRandom(Random random) {
@@ -102,7 +101,7 @@ public class BestFirstWorker {
102 if (randomVersion != null) { 101 if (randomVersion != null) {
103 this.model.restore(randomVersion.version()); 102 this.model.restore(randomVersion.version());
104 } 103 }
105 return randomVersion; 104 return last;
106 } 105 }
107 106
108 public int compare(VersionWithObjectiveValue s1, VersionWithObjectiveValue s2) { 107 public int compare(VersionWithObjectiveValue s1, VersionWithObjectiveValue s2) {
@@ -121,9 +120,10 @@ public class BestFirstWorker {
121 } 120 }
122 121
123 public RandomVisitResult visitRandomUnvisited(Random random) { 122 public RandomVisitResult visitRandomUnvisited(Random random) {
123 checkSynchronized();
124 if (!model.hasUncommittedChanges()) { 124 if (!model.hasUncommittedChanges()) {
125 queryAdapter.flushChanges();
126 var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); 125 var visitResult = activationStoreWorker.fireRandomActivation(this.last, random);
126 queryAdapter.flushChanges();
127 127
128 if (visitResult.successfulVisit()) { 128 if (visitResult.successfulVisit()) {
129 Version oldVersion = null; 129 Version oldVersion = null;
@@ -133,7 +133,8 @@ public class BestFirstWorker {
133 var submitResult = submit(); 133 var submitResult = submit();
134 if (isVisualizationEnabled && submitResult.newVersion() != null) { 134 if (isVisualizationEnabled && submitResult.newVersion() != null) {
135 var newVersion = submitResult.newVersion().version(); 135 var newVersion = submitResult.newVersion().version();
136 visualizationStore.addTransition(oldVersion, newVersion, ""); 136 visualizationStore.addTransition(oldVersion, newVersion,
137 "fire: " + visitResult.transformation() + ", " + visitResult.activation());
137 } 138 }
138 return new RandomVisitResult(submitResult, visitResult.mayHaveMore()); 139 return new RandomVisitResult(submitResult, visitResult.mayHaveMore());
139 } else { 140 } else {
@@ -147,4 +148,10 @@ public class BestFirstWorker {
147 public boolean hasEnoughSolution() { 148 public boolean hasEnoughSolution() {
148 return storeManager.solutionStore.hasEnoughSolution(); 149 return storeManager.solutionStore.hasEnoughSolution();
149 } 150 }
151
152 private void checkSynchronized() {
153 if (last != null && !last.version().equals(model.getState())) {
154 throw new AssertionError("Worker is not synchronized with model state");
155 }
156 }
150} 157}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java
index 24145d03..c204ae35 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java
@@ -16,32 +16,35 @@ public class ActivationStoreBitVectorEntry extends ActivationStoreEntry {
16 @Override 16 @Override
17 public int getNumberOfVisitedActivations() { 17 public int getNumberOfVisitedActivations() {
18 int visited = 0; 18 int visited = 0;
19 for (int i : selected) { 19 // Use indexed for loop to avoid allocating an iterator.
20 visited += Integer.bitCount(i); 20 //noinspection ForLoopReplaceableByForEach
21 for (int i = 0; i < selected.length; i++) {
22 visited += Integer.bitCount(selected[i]);
21 } 23 }
22 return visited; 24 return visited;
23 } 25 }
24 26
25 private static final int ELEMENT_POSITION = 5; // size of Integer.SIZE 27 private static final int ELEMENT_POSITION = 5; // size of Integer.SIZE
26 private static final int ELEMENT_BITMASK = (1<<ELEMENT_POSITION)-1; 28 private static final int ELEMENT_BITMASK = (1 << ELEMENT_POSITION) - 1;
29
27 @Override 30 @Override
28 public int getAndAddActivationAfter(int index) { 31 public int getAndAddActivationAfter(int index) {
29 int position = index; 32 int position = index;
30 do { 33 do {
31 final int selectedElement = position >> ELEMENT_POSITION; 34 final int selectedElement = position >> ELEMENT_POSITION;
32 final int selectedBit = 1<<(position & ELEMENT_BITMASK); 35 final int selectedBit = 1 << (position & ELEMENT_BITMASK);
33 36
34 if((selected[selectedElement] & selectedBit) == 0) { 37 if ((selected[selectedElement] & selectedBit) == 0) {
35 selected[selectedElement] |= selectedBit; 38 selected[selectedElement] |= selectedBit;
36 return position; 39 return position;
37 } else { 40 } else {
38 if(position < this.numberOfActivations-1) { 41 if (position < this.numberOfActivations - 1) {
39 position++; 42 position++;
40 } else { 43 } else {
41 position = 0; 44 position = 0;
42 } 45 }
43 } 46 }
44 } while(position != index); 47 } while (position != index);
45 throw new IllegalArgumentException("There is are no unvisited activations!"); 48 throw new IllegalArgumentException("There is are no unvisited activations!");
46 } 49 }
47} 50}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java
index d7339805..7249751c 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java
@@ -17,6 +17,11 @@ public abstract class ActivationStoreEntry {
17 public int getNumberOfUnvisitedActivations() { 17 public int getNumberOfUnvisitedActivations() {
18 return numberOfActivations - getNumberOfVisitedActivations(); 18 return numberOfActivations - getNumberOfVisitedActivations();
19 } 19 }
20
21 public int getNumberOfActivations() {
22 return numberOfActivations;
23 }
24
20 public abstract int getAndAddActivationAfter(int index); 25 public abstract int getAndAddActivationAfter(int index);
21 26
22 // public abstract boolean contains(int activation) 27 // public abstract boolean contains(int activation)
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java
index 4d775b5a..d9e29eca 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java
@@ -28,7 +28,7 @@ public class ActivationStoreImpl implements ActivationStore {
28 var entries = versionToActivations.computeIfAbsent(to, x -> { 28 var entries = versionToActivations.computeIfAbsent(to, x -> {
29 successful[0] = true; 29 successful[0] = true;
30 List<ActivationStoreEntry> result = new ArrayList<>(emptyEntrySizes.length); 30 List<ActivationStoreEntry> result = new ArrayList<>(emptyEntrySizes.length);
31 for(int emptyEntrySize : emptyEntrySizes) { 31 for (int emptyEntrySize : emptyEntrySizes) {
32 result.add(ActivationStoreEntry.create(emptyEntrySize)); 32 result.add(ActivationStoreEntry.create(emptyEntrySize));
33 } 33 }
34 return result; 34 return result;
@@ -40,13 +40,14 @@ public class ActivationStoreImpl implements ActivationStore {
40 break; 40 break;
41 } 41 }
42 } 42 }
43 if(!hasMore) { 43 if (!hasMore) {
44 actionWhenAllActivationVisited.accept(to); 44 actionWhenAllActivationVisited.accept(to);
45 } 45 }
46 return new VisitResult(successful[0], hasMore, -1, -1); 46 return new VisitResult(successful[0], hasMore, -1, -1);
47 } 47 }
48 48
49 public synchronized VisitResult visitActivation(VersionWithObjectiveValue from, int transformationIndex, int activationIndex) { 49 public synchronized VisitResult visitActivation(VersionWithObjectiveValue from, int transformationIndex,
50 int activationIndex) {
50 var entries = versionToActivations.get(from); 51 var entries = versionToActivations.get(from);
51 var entry = entries.get(transformationIndex); 52 var entry = entries.get(transformationIndex);
52 final int unvisited = entry.getNumberOfUnvisitedActivations(); 53 final int unvisited = entry.getNumberOfUnvisitedActivations();
@@ -66,7 +67,7 @@ public class ActivationStoreImpl implements ActivationStore {
66 activation = -1; 67 activation = -1;
67 } 68 }
68 69
69 if(!hasMoreInActivation) { 70 if (!hasMoreInActivation) {
70 boolean hasMoreInOtherTransformation = false; 71 boolean hasMoreInOtherTransformation = false;
71 for (var e : entries) { 72 for (var e : entries) {
72 if (e != entry && e.getNumberOfUnvisitedActivations() > 0) { 73 if (e != entry && e.getNumberOfUnvisitedActivations() > 0) {
@@ -79,7 +80,7 @@ public class ActivationStoreImpl implements ActivationStore {
79 hasMore = true; 80 hasMore = true;
80 } 81 }
81 82
82 if(!hasMore) { 83 if (!hasMore) {
83 actionWhenAllActivationVisited.accept(from); 84 actionWhenAllActivationVisited.accept(from);
84 } 85 }
85 86
@@ -103,34 +104,28 @@ public class ActivationStoreImpl implements ActivationStore {
103 public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) { 104 public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) {
104 var entries = versionToActivations.get(version); 105 var entries = versionToActivations.get(version);
105 106
106 int sum1 = 0; 107 int numberOfAllUnvisitedActivations = 0;
107 for (var entry : entries) { 108 for (var entry : entries) {
108 sum1 += entry.getNumberOfUnvisitedActivations(); 109 numberOfAllUnvisitedActivations += entry.getNumberOfUnvisitedActivations();
109 } 110 }
110 111
111 if(sum1 == 0) { 112 if (numberOfAllUnvisitedActivations == 0) {
112 this.actionWhenAllActivationVisited.accept(version); 113 this.actionWhenAllActivationVisited.accept(version);
113 return new VisitResult(false, false, -1, -1); 114 return new VisitResult(false, false, -1, -1);
114 } 115 }
115 116
116 int selected = random.nextInt(sum1); 117 int offset = random.nextInt(numberOfAllUnvisitedActivations);
117 int sum2 = 0;
118 int transformation = 0; 118 int transformation = 0;
119 int activation = -1;
120 for (; transformation < entries.size(); transformation++) { 119 for (; transformation < entries.size(); transformation++) {
121 var entry = entries.get(transformation); 120 var entry = entries.get(transformation);
122 int unvisited = entry.getNumberOfUnvisitedActivations(); 121 int unvisited = entry.getNumberOfUnvisitedActivations();
123 if (selected < sum2 + unvisited) { 122 if (unvisited > 0 && offset < unvisited) {
124 activation = sum2 + unvisited - selected - 1; 123 int activation = random.nextInt(entry.getNumberOfActivations());
125 break; 124 return this.visitActivation(version, transformation, activation);
126 } else {
127 sum2 += unvisited;
128 } 125 }
129 } 126 offset -= unvisited;
130 if (activation == -1) {
131 throw new IllegalArgumentException("no unvisited");
132 } 127 }
133 128
134 return this.visitActivation(version, transformation, activation); 129 throw new AssertionError("Unvisited activation %d not found".formatted(offset));
135 } 130 }
136} 131}
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 685b88bd..63da6cc3 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
@@ -11,10 +11,11 @@ import tools.refinery.store.dse.modification.DanglingEdges;
11import tools.refinery.store.dse.modification.ModificationAdapter; 11import tools.refinery.store.dse.modification.ModificationAdapter;
12import tools.refinery.store.dse.strategy.BestFirstStoreManager; 12import tools.refinery.store.dse.strategy.BestFirstStoreManager;
13import tools.refinery.store.dse.tests.DummyCriterion; 13import tools.refinery.store.dse.tests.DummyCriterion;
14import tools.refinery.store.dse.tests.DummyRandomCriterion;
15import tools.refinery.store.dse.tests.DummyRandomObjective; 14import tools.refinery.store.dse.tests.DummyRandomObjective;
16import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 15import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
17import tools.refinery.store.dse.transition.Rule; 16import tools.refinery.store.dse.transition.Rule;
17import tools.refinery.store.dse.transition.objectives.Criteria;
18import tools.refinery.store.dse.transition.objectives.Objectives;
18import tools.refinery.store.model.ModelStore; 19import tools.refinery.store.model.ModelStore;
19import tools.refinery.store.query.ModelQueryAdapter; 20import tools.refinery.store.query.ModelQueryAdapter;
20import tools.refinery.store.query.dnf.Query; 21import tools.refinery.store.query.dnf.Query;
@@ -59,6 +60,12 @@ class CRAExamplesTest {
59 methodView.call(f) 60 methodView.call(f)
60 )); 61 ));
61 62
63 private static final RelationalQuery unEncapsulatedFeature = Query.of("unEncapsulatedFeature",
64 (builder, f) -> builder.clause(
65 feature.call(f),
66 not(encapsulatesView.call(Variable.of(), f))
67 ));
68
62 private static final Rule assignFeatureRule = Rule.of("AssignFeature", (builder, f, c1) -> builder 69 private static final Rule assignFeatureRule = Rule.of("AssignFeature", (builder, f, c1) -> builder
63 .clause( 70 .clause(
64 feature.call(f), 71 feature.call(f),
@@ -66,24 +73,24 @@ class CRAExamplesTest {
66 not(encapsulatesView.call(Variable.of(), f)) 73 not(encapsulatesView.call(Variable.of(), f))
67 ) 74 )
68 .action( 75 .action(
69 add(encapsulates, f, c1) 76 add(encapsulates, c1, f)
70 )); 77 ));
71 78
72 private static final Rule deleteEmptyClassRule = Rule.of("DeleteEmptyClass", (builder, c) -> builder 79 private static final Rule deleteEmptyClassRule = Rule.of("DeleteEmptyClass", (builder, c) -> builder
73 .clause((f) -> List.of( 80 .clause(
74 classElementView.call(c), 81 classElementView.call(c),
75 not(encapsulatesView.call(c, f)) 82 not(encapsulatesView.call(c, Variable.of()))
76 )) 83 )
77 .action( 84 .action(
78 remove(classElement, c), 85 remove(classElement, c),
79 delete(c, DanglingEdges.IGNORE) 86 delete(c, DanglingEdges.IGNORE)
80 )); 87 ));
81 88
82 private static final Rule createClassRule = Rule.of("CreateClass", (builder, f) -> builder 89 private static final Rule createClassRule = Rule.of("CreateClass", (builder, f) -> builder
83 .clause((c) -> List.of( 90 .clause(
84 feature.call(f), 91 feature.call(f),
85 not(encapsulatesView.call(f, c)) 92 not(encapsulatesView.call(Variable.of(), f))
86 )) 93 )
87 .action((newClass) -> List.of( 94 .action((newClass) -> List.of(
88 create(newClass), 95 create(newClass),
89 add(classElement, newClass), 96 add(classElement, newClass),
@@ -110,7 +117,7 @@ class CRAExamplesTest {
110 .symbols(classElement, encapsulates, attribute, method, dataDependency, functionalDependency, name) 117 .symbols(classElement, encapsulates, attribute, method, dataDependency, functionalDependency, name)
111 .with(ViatraModelQueryAdapter.builder()) 118 .with(ViatraModelQueryAdapter.builder())
112 .with(ModelVisualizerAdapter.builder() 119 .with(ModelVisualizerAdapter.builder()
113 .withOutputpath("test_output") 120 .withOutputPath("test_output")
114 .withFormat(FileFormat.DOT) 121 .withFormat(FileFormat.DOT)
115 .withFormat(FileFormat.SVG) 122 .withFormat(FileFormat.SVG)
116 .saveStates() 123 .saveStates()
@@ -119,8 +126,11 @@ class CRAExamplesTest {
119 .with(ModificationAdapter.builder()) 126 .with(ModificationAdapter.builder())
120 .with(DesignSpaceExplorationAdapter.builder() 127 .with(DesignSpaceExplorationAdapter.builder()
121 .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) 128 .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule)
122 .objectives(new DummyRandomObjective()) 129 .objectives(Objectives.sum(
123 .accept(new DummyRandomCriterion()) 130 new DummyRandomObjective(),
131 Objectives.count(unEncapsulatedFeature)
132 ))
133 .accept(Criteria.whenNoMatch(unEncapsulatedFeature))
124 .exclude(new DummyCriterion(false))) 134 .exclude(new DummyCriterion(false)))
125 .build(); 135 .build();
126 136
@@ -192,9 +202,10 @@ class CRAExamplesTest {
192 var initialVersion = model.commit(); 202 var initialVersion = model.commit();
193 queryEngine.flushChanges(); 203 queryEngine.flushChanges();
194 204
195 var bestFirst = new BestFirstStoreManager(store); 205 var bestFirst = new BestFirstStoreManager(store, 50);
196 bestFirst.startExploration(initialVersion); 206 bestFirst.startExploration(initialVersion);
197 var resultStore = bestFirst.getSolutionStore(); 207 var resultStore = bestFirst.getSolutionStore();
198 System.out.println("states size: " + resultStore.getSolutions().size()); 208 System.out.println("states size: " + resultStore.getSolutions().size());
209 model.getAdapter(ModelVisualizerAdapter.class).visualize(bestFirst.getVisualizationStore());
199 } 210 }
200} 211}
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 baa7c8a4..b912eba3 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
@@ -64,7 +64,7 @@ class DebugTest {
64 .symbols(classModel, classElement, feature, classes, features) 64 .symbols(classModel, classElement, feature, classes, features)
65 .with(ViatraModelQueryAdapter.builder()) 65 .with(ViatraModelQueryAdapter.builder())
66 .with(ModelVisualizerAdapter.builder() 66 .with(ModelVisualizerAdapter.builder()
67 .withOutputpath("test_output") 67 .withOutputPath("test_output")
68 .withFormat(FileFormat.DOT) 68 .withFormat(FileFormat.DOT)
69 .withFormat(FileFormat.SVG) 69 .withFormat(FileFormat.SVG)
70 .saveStates() 70 .saveStates()
@@ -91,7 +91,7 @@ class DebugTest {
91 var initialVersion = model.commit(); 91 var initialVersion = model.commit();
92 queryEngine.flushChanges(); 92 queryEngine.flushChanges();
93 93
94 var bestFirst = new BestFirstStoreManager(store); 94 var bestFirst = new BestFirstStoreManager(store, 50);
95 bestFirst.startExploration(initialVersion); 95 bestFirst.startExploration(initialVersion);
96 var resultStore = bestFirst.getSolutionStore(); 96 var resultStore = bestFirst.getSolutionStore();
97 System.out.println("states size: " + resultStore.getSolutions().size()); 97 System.out.println("states size: " + resultStore.getSolutions().size());