diff options
Diffstat (limited to 'subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java')
-rw-r--r-- | subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java | 164 |
1 files changed, 164 insertions, 0 deletions
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 new file mode 100644 index 00000000..aca800a3 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.dse.strategy; | ||
7 | |||
8 | import org.jetbrains.annotations.Nullable; | ||
9 | import tools.refinery.store.dse.propagation.PropagationAdapter; | ||
10 | import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; | ||
11 | import tools.refinery.store.dse.transition.ObjectiveValue; | ||
12 | import tools.refinery.store.dse.transition.VersionWithObjectiveValue; | ||
13 | import tools.refinery.store.dse.transition.statespace.internal.ActivationStoreWorker; | ||
14 | import tools.refinery.store.map.Version; | ||
15 | import tools.refinery.store.model.Model; | ||
16 | import tools.refinery.store.query.ModelQueryAdapter; | ||
17 | import tools.refinery.store.statecoding.StateCoderAdapter; | ||
18 | import tools.refinery.visualization.statespace.VisualizationStore; | ||
19 | |||
20 | import java.util.Random; | ||
21 | |||
22 | public class BestFirstWorker { | ||
23 | final BestFirstStoreManager storeManager; | ||
24 | final Model model; | ||
25 | final ActivationStoreWorker activationStoreWorker; | ||
26 | final StateCoderAdapter stateCoderAdapter; | ||
27 | final DesignSpaceExplorationAdapter explorationAdapter; | ||
28 | final ModelQueryAdapter queryAdapter; | ||
29 | final @Nullable PropagationAdapter propagationAdapter; | ||
30 | final VisualizationStore visualizationStore; | ||
31 | final boolean isVisualizationEnabled; | ||
32 | |||
33 | public BestFirstWorker(BestFirstStoreManager storeManager, Model model) { | ||
34 | this.storeManager = storeManager; | ||
35 | this.model = model; | ||
36 | |||
37 | explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); | ||
38 | stateCoderAdapter = model.getAdapter(StateCoderAdapter.class); | ||
39 | queryAdapter = model.getAdapter(ModelQueryAdapter.class); | ||
40 | propagationAdapter = model.tryGetAdapter(PropagationAdapter.class).orElse(null); | ||
41 | activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(), | ||
42 | explorationAdapter.getTransformations()); | ||
43 | visualizationStore = storeManager.getVisualizationStore(); | ||
44 | isVisualizationEnabled = visualizationStore != null; | ||
45 | } | ||
46 | |||
47 | protected VersionWithObjectiveValue last = null; | ||
48 | |||
49 | public SubmitResult submit() { | ||
50 | checkSynchronized(); | ||
51 | if (queryAdapter.hasPendingChanges()) { | ||
52 | throw new AssertionError("Pending changes detected before model submission"); | ||
53 | } | ||
54 | if (explorationAdapter.checkExclude()) { | ||
55 | return new SubmitResult(false, false, null, null); | ||
56 | } | ||
57 | |||
58 | var code = stateCoderAdapter.calculateStateCode(); | ||
59 | |||
60 | boolean isNew = storeManager.getEquivalenceClassStore().submit(code); | ||
61 | if (isNew) { | ||
62 | Version version = model.commit(); | ||
63 | ObjectiveValue objectiveValue = explorationAdapter.getObjectiveValue(); | ||
64 | var versionWithObjectiveValue = new VersionWithObjectiveValue(version, objectiveValue); | ||
65 | last = versionWithObjectiveValue; | ||
66 | var accepted = explorationAdapter.checkAccept(); | ||
67 | |||
68 | storeManager.getObjectiveStore().submit(versionWithObjectiveValue); | ||
69 | storeManager.getActivationStore().markNewAsVisited(versionWithObjectiveValue, activationStoreWorker.calculateEmptyActivationSize()); | ||
70 | if(accepted) { | ||
71 | storeManager.solutionStore.submit(versionWithObjectiveValue); | ||
72 | } | ||
73 | |||
74 | if (isVisualizationEnabled) { | ||
75 | visualizationStore.addState(last.version(), last.objectiveValue().toString()); | ||
76 | if (accepted) { | ||
77 | visualizationStore.addSolution(last.version()); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | return new SubmitResult(true, accepted, objectiveValue, last); | ||
82 | } | ||
83 | |||
84 | return new SubmitResult(false, false, null, null); | ||
85 | } | ||
86 | |||
87 | public void restoreToLast() { | ||
88 | if (explorationAdapter.getModel().hasUncommittedChanges()) { | ||
89 | explorationAdapter.getModel().restore(last.version()); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | public VersionWithObjectiveValue restoreToBest() { | ||
94 | var bestVersion = storeManager.getObjectiveStore().getBest(); | ||
95 | last = bestVersion; | ||
96 | if (bestVersion != null) { | ||
97 | this.model.restore(bestVersion.version()); | ||
98 | } | ||
99 | return last; | ||
100 | } | ||
101 | |||
102 | public VersionWithObjectiveValue restoreToRandom(Random random) { | ||
103 | var objectiveStore = storeManager.getObjectiveStore(); | ||
104 | if (objectiveStore.getSize() == 0) { | ||
105 | return null; | ||
106 | } | ||
107 | var randomVersion = objectiveStore.getRandom(random); | ||
108 | last = randomVersion; | ||
109 | if (randomVersion != null) { | ||
110 | this.model.restore(randomVersion.version()); | ||
111 | } | ||
112 | return last; | ||
113 | } | ||
114 | |||
115 | public int compare(VersionWithObjectiveValue s1, VersionWithObjectiveValue s2) { | ||
116 | return storeManager.getObjectiveStore().getComparator().compare(s1, s2); | ||
117 | } | ||
118 | |||
119 | public record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) { | ||
120 | } | ||
121 | |||
122 | public RandomVisitResult visitRandomUnvisited(Random random) { | ||
123 | checkSynchronized(); | ||
124 | if (model.hasUncommittedChanges()) { | ||
125 | throw new IllegalStateException("The model has uncommitted changes!"); | ||
126 | } | ||
127 | |||
128 | var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); | ||
129 | |||
130 | if (!visitResult.successfulVisit()) { | ||
131 | return new RandomVisitResult(null, visitResult.mayHaveMore()); | ||
132 | } | ||
133 | |||
134 | if (propagationAdapter != null) { | ||
135 | var propagationResult = propagationAdapter.propagate(); | ||
136 | if (propagationResult.isRejected()) { | ||
137 | return new RandomVisitResult(null, visitResult.mayHaveMore()); | ||
138 | } | ||
139 | } | ||
140 | queryAdapter.flushChanges(); | ||
141 | |||
142 | Version oldVersion = null; | ||
143 | if (isVisualizationEnabled) { | ||
144 | oldVersion = last.version(); | ||
145 | } | ||
146 | var submitResult = submit(); | ||
147 | if (isVisualizationEnabled && submitResult.newVersion() != null) { | ||
148 | var newVersion = submitResult.newVersion().version(); | ||
149 | visualizationStore.addTransition(oldVersion, newVersion, | ||
150 | "fire: " + visitResult.transformation() + ", " + visitResult.activation()); | ||
151 | } | ||
152 | return new RandomVisitResult(submitResult, visitResult.mayHaveMore()); | ||
153 | } | ||
154 | |||
155 | public boolean hasEnoughSolution() { | ||
156 | return storeManager.solutionStore.hasEnoughSolution(); | ||
157 | } | ||
158 | |||
159 | private void checkSynchronized() { | ||
160 | if (last != null && !last.version().equals(model.getState())) { | ||
161 | throw new AssertionError("Worker is not synchronized with model state"); | ||
162 | } | ||
163 | } | ||
164 | } | ||