aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-09-14 19:29:36 +0200
committerLibravatar GitHub <noreply@github.com>2023-09-14 19:29:36 +0200
commit98ed3b6db5f4e51961a161050cc31c66015116e8 (patch)
tree8bfd6d9bc8d6ed23b9eb0f889dd40b6c24fe8f92 /subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
parentMerge pull request #38 from nagilooh/design-space-exploration (diff)
parentMerge remote-tracking branch 'upstream/main' into partial-interpretation (diff)
downloadrefinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.gz
refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.zst
refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.zip
Merge pull request #39 from kris7t/partial-interpretation
Implement partial interpretation based model generation
Diffstat (limited to 'subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java')
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java233
1 files changed, 233 insertions, 0 deletions
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
new file mode 100644
index 00000000..9ee74207
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
@@ -0,0 +1,233 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.generator;
7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import org.eclipse.emf.common.util.URI;
11import org.eclipse.xtext.diagnostics.Severity;
12import org.eclipse.xtext.resource.IResourceFactory;
13import org.eclipse.xtext.resource.XtextResourceSet;
14import org.eclipse.xtext.service.OperationCanceledManager;
15import org.eclipse.xtext.util.LazyStringInputStream;
16import org.eclipse.xtext.validation.CheckMode;
17import org.eclipse.xtext.validation.IResourceValidator;
18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory;
20import tools.refinery.language.model.problem.Problem;
21import tools.refinery.language.semantics.metadata.MetadataCreator;
22import tools.refinery.language.semantics.model.ModelInitializer;
23import tools.refinery.language.web.semantics.PartialInterpretation2Json;
24import tools.refinery.language.web.xtext.server.ThreadPoolExecutorServiceProvider;
25import tools.refinery.language.web.xtext.server.push.PushWebDocument;
26import tools.refinery.store.dse.propagation.PropagationAdapter;
27import tools.refinery.store.dse.strategy.BestFirstStoreManager;
28import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
29import tools.refinery.store.model.ModelStore;
30import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
31import tools.refinery.store.reasoning.ReasoningAdapter;
32import tools.refinery.store.reasoning.ReasoningStoreAdapter;
33import tools.refinery.store.reasoning.literal.Concreteness;
34import tools.refinery.store.statecoding.StateCoderAdapter;
35import tools.refinery.store.util.CancellationToken;
36
37import java.io.IOException;
38import java.util.Map;
39import java.util.UUID;
40import java.util.concurrent.*;
41
42public class ModelGenerationWorker implements Runnable {
43 private static final Logger LOG = LoggerFactory.getLogger(ModelGenerationWorker.class);
44
45 private final UUID uuid = UUID.randomUUID();
46
47 private PushWebDocument state;
48
49 private String text;
50
51 private volatile boolean timedOut;
52
53 private volatile boolean cancelled;
54
55 @Inject
56 private OperationCanceledManager operationCanceledManager;
57
58 @Inject
59 private Provider<XtextResourceSet> resourceSetProvider;
60
61 @Inject
62 private IResourceFactory resourceFactory;
63
64 @Inject
65 private IResourceValidator resourceValidator;
66
67 @Inject
68 private ModelInitializer initializer;
69
70 @Inject
71 private MetadataCreator metadataCreator;
72
73 @Inject
74 private PartialInterpretation2Json partialInterpretation2Json;
75
76 private final Object lockObject = new Object();
77
78 private ExecutorService executorService;
79
80 private ScheduledExecutorService scheduledExecutorService;
81
82 private int randomSeed;
83
84 private long timeoutSec;
85
86 private Future<?> future;
87
88 private ScheduledFuture<?> timeoutFuture;
89
90 private final CancellationToken cancellationToken = () -> {
91 if (cancelled || Thread.interrupted()) {
92 operationCanceledManager.throwOperationCanceledException();
93 }
94 };
95
96 @Inject
97 public void setExecutorServiceProvider(ThreadPoolExecutorServiceProvider provider) {
98 executorService = provider.get(ModelGenerationService.MODEL_GENERATION_EXECUTOR);
99 scheduledExecutorService = provider.getScheduled(ModelGenerationService.MODEL_GENERATION_TIMEOUT_EXECUTOR);
100 }
101
102 public void setState(PushWebDocument state, int randomSeed, long timeoutSec) {
103 this.state = state;
104 this.randomSeed = randomSeed;
105 this.timeoutSec = timeoutSec;
106 text = state.getText();
107 }
108
109 public UUID getUuid() {
110 return uuid;
111 }
112
113 public void start() {
114 synchronized (lockObject) {
115 LOG.debug("Enqueueing model generation: {}", uuid);
116 future = executorService.submit(this);
117 }
118 }
119
120 public void startTimeout() {
121 synchronized (lockObject) {
122 LOG.debug("Starting model generation: {}", uuid);
123 cancellationToken.checkCancelled();
124 timeoutFuture = scheduledExecutorService.schedule(() -> cancel(true), timeoutSec, TimeUnit.SECONDS);
125 }
126 }
127
128 // We catch {@code Throwable} to handle {@code OperationCancelledError}, but we rethrow fatal JVM errors.
129 @SuppressWarnings("squid:S1181")
130 @Override
131 public void run() {
132 startTimeout();
133 notifyResult(new ModelGenerationStatusResult(uuid, "Initializing model generator"));
134 ModelGenerationResult result;
135 try {
136 result = doRun();
137 } catch (Throwable e) {
138 if (operationCanceledManager.isOperationCanceledException(e)) {
139 var message = timedOut ? "Model generation timed out" : "Model generation cancelled";
140 LOG.debug("{}: {}", message, uuid);
141 notifyResult(new ModelGenerationErrorResult(uuid, message));
142 } else if (e instanceof Error error) {
143 // Make sure we don't try to recover from any fatal JVM errors.
144 throw error;
145 } else {
146 LOG.debug("Model generation error", e);
147 notifyResult(new ModelGenerationErrorResult(uuid, e.toString()));
148 }
149 return;
150 }
151 notifyResult(result);
152 }
153
154 private void notifyResult(ModelGenerationResult result) {
155 state.notifyPrecomputationListeners(ModelGenerationService.SERVICE_NAME, result);
156 }
157
158 public ModelGenerationResult doRun() throws IOException {
159 cancellationToken.checkCancelled();
160 var resourceSet = resourceSetProvider.get();
161 var uri = URI.createURI("__synthetic_" + uuid + ".problem");
162 var resource = resourceFactory.createResource(uri);
163 resourceSet.getResources().add(resource);
164 var inputStream = new LazyStringInputStream(text);
165 resource.load(inputStream, Map.of());
166 cancellationToken.checkCancelled();
167 var issues = resourceValidator.validate(resource, CheckMode.ALL, () -> cancelled || Thread.interrupted());
168 cancellationToken.checkCancelled();
169 for (var issue : issues) {
170 if (issue.getSeverity() == Severity.ERROR) {
171 return new ModelGenerationErrorResult(uuid, "Validation error: " + issue.getMessage());
172 }
173 }
174 if (resource.getContents().isEmpty() || !(resource.getContents().get(0) instanceof Problem problem)) {
175 return new ModelGenerationErrorResult(uuid, "Model generation problem not found");
176 }
177 cancellationToken.checkCancelled();
178 var storeBuilder = ModelStore.builder()
179 .cancellationToken(cancellationToken)
180 .with(ViatraModelQueryAdapter.builder())
181 .with(PropagationAdapter.builder())
182 .with(StateCoderAdapter.builder())
183 .with(DesignSpaceExplorationAdapter.builder())
184 .with(ReasoningAdapter.builder()
185 .requiredInterpretations(Concreteness.CANDIDATE));
186 var modelSeed = initializer.createModel(problem, storeBuilder);
187 var store = storeBuilder.build();
188 cancellationToken.checkCancelled();
189 var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed);
190 var initialVersion = model.commit();
191 cancellationToken.checkCancelled();
192 notifyResult(new ModelGenerationStatusResult(uuid, "Generating model"));
193 var bestFirst = new BestFirstStoreManager(store, 1);
194 bestFirst.startExploration(initialVersion, randomSeed);
195 cancellationToken.checkCancelled();
196 var solutionStore = bestFirst.getSolutionStore();
197 if (solutionStore.getSolutions().isEmpty()) {
198 return new ModelGenerationErrorResult(uuid, "Problem is unsatisfiable");
199 }
200 notifyResult(new ModelGenerationStatusResult(uuid, "Saving generated model"));
201 model.restore(solutionStore.getSolutions().get(0).version());
202 cancellationToken.checkCancelled();
203 metadataCreator.setInitializer(initializer);
204 var nodesMetadata = metadataCreator.getNodesMetadata(model.getAdapter(ReasoningAdapter.class).getNodeCount(),
205 false);
206 cancellationToken.checkCancelled();
207 var relationsMetadata = metadataCreator.getRelationsMetadata();
208 cancellationToken.checkCancelled();
209 var partialInterpretation = partialInterpretation2Json.getPartialInterpretation(initializer, model,
210 Concreteness.CANDIDATE, cancellationToken);
211 return new ModelGenerationSuccessResult(uuid, nodesMetadata, relationsMetadata, partialInterpretation);
212 }
213
214 public void cancel() {
215 cancel(false);
216 }
217
218 public void cancel(boolean timedOut) {
219 synchronized (lockObject) {
220 LOG.trace("Cancelling model generation: {}", uuid);
221 this.timedOut = timedOut;
222 cancelled = true;
223 if (future != null) {
224 future.cancel(true);
225 future = null;
226 }
227 if (timeoutFuture != null) {
228 timeoutFuture.cancel(true);
229 timeoutFuture = null;
230 }
231 }
232 }
233}