aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/generator
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-03 02:03:56 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-03 02:03:56 +0100
commiteddf21f4b583fecb982c2c2f4ee733ee156371d7 (patch)
treeb22730c84e63e6c32fc498edae6d565b7cadced9 /subprojects/generator
parentrefactor(interpreter): aggreagator batching (diff)
downloadrefinery-eddf21f4b583fecb982c2c2f4ee733ee156371d7.tar.gz
refinery-eddf21f4b583fecb982c2c2f4ee733ee156371d7.tar.zst
refinery-eddf21f4b583fecb982c2c2f4ee733ee156371d7.zip
feat: model generator facade
Diffstat (limited to 'subprojects/generator')
-rw-r--r--subprojects/generator/build.gradle.kts15
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java104
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorBuilder.java167
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ProblemTrace.java25
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/StandaloneInjectorHolder.java27
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/UnsatisfiableProblemException.java12
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ValidationErrorsException.java64
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/impl/ProblemTraceImpl.java84
8 files changed, 498 insertions, 0 deletions
diff --git a/subprojects/generator/build.gradle.kts b/subprojects/generator/build.gradle.kts
new file mode 100644
index 00000000..f1a4ed54
--- /dev/null
+++ b/subprojects/generator/build.gradle.kts
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 api(project(":refinery-language-semantics"))
13 implementation(project(":refinery-store-query-interpreter"))
14 implementation(project(":refinery-store-reasoning-scope"))
15}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java
new file mode 100644
index 00000000..4c3e52f3
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java
@@ -0,0 +1,104 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import org.eclipse.xtext.naming.QualifiedName;
9import tools.refinery.language.model.problem.Relation;
10import tools.refinery.store.dse.strategy.BestFirstStoreManager;
11import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
12import tools.refinery.store.map.Version;
13import tools.refinery.store.model.Model;
14import tools.refinery.store.model.ModelStore;
15import tools.refinery.store.reasoning.ReasoningAdapter;
16import tools.refinery.store.reasoning.ReasoningStoreAdapter;
17import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
18import tools.refinery.store.reasoning.literal.Concreteness;
19import tools.refinery.store.reasoning.representation.PartialSymbol;
20import tools.refinery.store.reasoning.seed.ModelSeed;
21import tools.refinery.store.representation.TruthValue;
22
23import java.util.Collection;
24
25public class ModelGenerator {
26 private final ProblemTrace problemTrace;
27 private final ModelStore store;
28 private final Model model;
29 private final ReasoningAdapter reasoningAdapter;
30 private final Version initialVersion;
31
32 private int randomSeed = 1;
33
34 public ModelGenerator(ProblemTrace problemTrace, ModelStore store, ModelSeed modelSeed) {
35 this.problemTrace = problemTrace;
36 this.store = store;
37 model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed);
38 reasoningAdapter = model.getAdapter(ReasoningAdapter.class);
39 initialVersion = model.commit();
40 }
41
42 public ProblemTrace getProblemTrace() {
43 return problemTrace;
44 }
45
46 public ModelStore getModelStore() {
47 return store;
48 }
49
50 public Model getModel() {
51 return model;
52 }
53
54 public int getRandomSeed() {
55 return randomSeed;
56 }
57
58 public void setRandomSeed(int randomSeed) {
59 this.randomSeed = randomSeed;
60 }
61
62 public Collection<Version> run(int maxNumberOfSolutions) {
63 var bestFirst = new BestFirstStoreManager(store, maxNumberOfSolutions);
64 int currentRandomSeed = randomSeed;
65 // Increment random seed even if generation is unsuccessful.
66 randomSeed++;
67 bestFirst.startExploration(initialVersion, currentRandomSeed);
68 return bestFirst.getSolutionStore()
69 .getSolutions()
70 .stream()
71 .map(VersionWithObjectiveValue::version)
72 .toList();
73 }
74
75 public boolean tryRun() {
76 var iterator = run(1).iterator();
77 if (!iterator.hasNext()) {
78 return false;
79 }
80 model.restore(iterator.next());
81 return true;
82 }
83
84 public <A, C> PartialInterpretation<A, C> getCandidateInterpretation(PartialSymbol<A, C> partialSymbol) {
85 return reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, partialSymbol);
86 }
87
88 public PartialInterpretation<TruthValue, Boolean> getCandidateInterpretation(Relation relation) {
89 return getCandidateInterpretation(problemTrace.getPartialRelation(relation));
90 }
91
92 public PartialInterpretation<TruthValue, Boolean> getCandidateInterpretation(QualifiedName qualifiedName) {
93 return getCandidateInterpretation(problemTrace.getPartialRelation(qualifiedName));
94 }
95
96 public PartialInterpretation<TruthValue, Boolean> getCandidateInterpretation(String qualifiedName) {
97 return getCandidateInterpretation(problemTrace.getPartialRelation(qualifiedName));
98 }
99
100 public static ModelGeneratorBuilder standaloneBuilder() {
101 var injector = StandaloneInjectorHolder.getInjector();
102 return injector.getInstance(ModelGeneratorBuilder.class);
103 }
104}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorBuilder.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorBuilder.java
new file mode 100644
index 00000000..98b6653d
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorBuilder.java
@@ -0,0 +1,167 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import org.eclipse.emf.common.util.URI;
11import org.eclipse.emf.ecore.resource.Resource;
12import org.eclipse.xtext.diagnostics.Severity;
13import org.eclipse.xtext.resource.IResourceFactory;
14import org.eclipse.xtext.resource.XtextResourceSet;
15import org.eclipse.xtext.util.LazyStringInputStream;
16import org.eclipse.xtext.validation.CheckMode;
17import org.eclipse.xtext.validation.IResourceValidator;
18import tools.refinery.generator.impl.ProblemTraceImpl;
19import tools.refinery.language.model.problem.Problem;
20import tools.refinery.language.semantics.model.ModelInitializer;
21import tools.refinery.store.dse.propagation.PropagationAdapter;
22import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
23import tools.refinery.store.model.ModelStore;
24import tools.refinery.store.query.ModelQueryBuilder;
25import tools.refinery.store.query.interpreter.QueryInterpreterAdapter;
26import tools.refinery.store.reasoning.ReasoningAdapter;
27import tools.refinery.store.reasoning.literal.Concreteness;
28import tools.refinery.store.statecoding.StateCoderAdapter;
29import tools.refinery.store.util.CancellationToken;
30
31import java.io.File;
32import java.io.IOException;
33import java.io.InputStream;
34import java.util.Collection;
35import java.util.Map;
36import java.util.Set;
37
38public abstract class ModelGeneratorBuilder {
39 @Inject
40 private Provider<XtextResourceSet> resourceSetProvider;
41
42 @Inject
43 private IResourceFactory resourceFactory;
44
45 @Inject
46 private IResourceValidator resourceValidator;
47
48 @Inject
49 private ModelInitializer initializer;
50
51 @Inject
52 private ProblemTraceImpl problemTrace;
53
54 private CancellationToken cancellationToken = CancellationToken.NONE;
55 private boolean problemLoaded;
56 private ModelQueryBuilder queryEngineBuilder;
57 private Collection<Concreteness> requiredInterpretations = Set.of(Concreteness.CANDIDATE);
58
59 public ModelGeneratorBuilder cancellationToken(CancellationToken cancellationToken) {
60 this.cancellationToken = cancellationToken;
61 return this;
62 }
63
64 public ModelGeneratorBuilder fromString(String problemString) throws IOException {
65 try (var stream = new LazyStringInputStream(problemString)) {
66 return fromStream(stream);
67 }
68 }
69
70 public ModelGeneratorBuilder fromStream(InputStream inputStream) throws IOException {
71 var resourceSet = resourceSetProvider.get();
72 var resource = resourceFactory.createResource(URI.createFileURI("__synthetic.problem"));
73 resourceSet.getResources().add(resource);
74 resource.load(inputStream, Map.of());
75 return fromResource(resource);
76 }
77
78 public ModelGeneratorBuilder fromFile(File file) throws IOException {
79 return fromFile(file.getAbsolutePath());
80 }
81
82 public ModelGeneratorBuilder fromFile(String filePath) throws IOException {
83 return fromUri(URI.createFileURI(filePath));
84 }
85
86 public ModelGeneratorBuilder fromUri(URI uri) throws IOException {
87 var resourceSet = resourceSetProvider.get();
88 var resource = resourceFactory.createResource(uri);
89 resourceSet.getResources().add(resource);
90 resource.load(Map.of());
91 return fromResource(resource);
92 }
93
94 public ModelGeneratorBuilder fromResource(Resource resource) {
95 var issues = resourceValidator.validate(resource, CheckMode.ALL, () -> {
96 cancellationToken.checkCancelled();
97 return Thread.interrupted();
98 });
99 cancellationToken.checkCancelled();
100 var errors = issues.stream()
101 .filter(issue -> issue.getSeverity() == Severity.ERROR)
102 .toList();
103 if (!errors.isEmpty()) {
104 throw new ValidationErrorsException(resource.getURI(), errors);
105 }
106 if (resource.getContents().isEmpty() || !(resource.getContents().get(0) instanceof Problem problem)) {
107 throw new IllegalArgumentException("Model generation problem not found in resource " + resource.getURI());
108 }
109 return problem(problem);
110 }
111
112 public ModelGeneratorBuilder problem(Problem problem) {
113 if (problemLoaded) {
114 throw new IllegalStateException("Problem was already set");
115 }
116 initializer.readProblem(problem);
117 problemTrace.setInitializer(initializer);
118 problemLoaded = true;
119 return this;
120 }
121
122 public ProblemTrace getProblemTrace() {
123 checkProblem();
124 return problemTrace;
125 }
126
127 public ModelGeneratorBuilder queryEngine(ModelQueryBuilder queryEngineBuilder) {
128 if (this.queryEngineBuilder != null) {
129 throw new IllegalStateException("Query engine was already set");
130 }
131 this.queryEngineBuilder = queryEngineBuilder;
132 return this;
133 }
134
135 public ModelGeneratorBuilder requiredInterpretations(Collection<Concreteness> requiredInterpretations) {
136 this.requiredInterpretations = requiredInterpretations;
137 return this;
138 }
139
140 public ModelGenerator build() {
141 checkProblem();
142 var storeBuilder = ModelStore.builder()
143 .cancellationToken(cancellationToken)
144 .with(getQueryEngineBuilder())
145 .with(PropagationAdapter.builder())
146 .with(StateCoderAdapter.builder())
147 .with(DesignSpaceExplorationAdapter.builder())
148 .with(ReasoningAdapter.builder()
149 .requiredInterpretations(requiredInterpretations));
150 initializer.configureStoreBuilder(storeBuilder);
151 var store = storeBuilder.build();
152 return new ModelGenerator(problemTrace, store, initializer.getModelSeed());
153 }
154
155 private void checkProblem() {
156 if (!problemLoaded) {
157 throw new IllegalStateException("Problem was not loaded");
158 }
159 }
160
161 private ModelQueryBuilder getQueryEngineBuilder() {
162 if (queryEngineBuilder == null) {
163 return QueryInterpreterAdapter.builder();
164 }
165 return queryEngineBuilder;
166 }
167}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ProblemTrace.java b/subprojects/generator/src/main/java/tools/refinery/generator/ProblemTrace.java
new file mode 100644
index 00000000..7be2dc00
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ProblemTrace.java
@@ -0,0 +1,25 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import org.eclipse.xtext.naming.QualifiedName;
9import tools.refinery.language.model.problem.Problem;
10import tools.refinery.language.model.problem.Relation;
11import tools.refinery.store.reasoning.representation.PartialRelation;
12
13import java.util.Map;
14
15public interface ProblemTrace {
16 Problem getProblem();
17
18 Map<Relation, PartialRelation> getRelationTrace();
19
20 PartialRelation getPartialRelation(Relation relation);
21
22 PartialRelation getPartialRelation(QualifiedName qualifiedName);
23
24 PartialRelation getPartialRelation(String qualifiedName);
25}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/StandaloneInjectorHolder.java b/subprojects/generator/src/main/java/tools/refinery/generator/StandaloneInjectorHolder.java
new file mode 100644
index 00000000..7db96163
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/StandaloneInjectorHolder.java
@@ -0,0 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import com.google.inject.Injector;
9import tools.refinery.language.ProblemStandaloneSetup;
10
11public final class StandaloneInjectorHolder {
12 private StandaloneInjectorHolder() {
13 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
14 }
15
16 public static Injector getInjector() {
17 return LazyHolder.INJECTOR;
18 }
19
20 private static final class LazyHolder {
21 private static final Injector INJECTOR = createInjector();
22
23 private static Injector createInjector() {
24 return new ProblemStandaloneSetup().createInjectorAndDoEMFRegistration();
25 }
26 }
27}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/UnsatisfiableProblemException.java b/subprojects/generator/src/main/java/tools/refinery/generator/UnsatisfiableProblemException.java
new file mode 100644
index 00000000..4fb18b90
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/UnsatisfiableProblemException.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8public class UnsatisfiableProblemException extends RuntimeException {
9 public UnsatisfiableProblemException() {
10 super("Model generation problem was unsatisfiable");
11 }
12}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ValidationErrorsException.java b/subprojects/generator/src/main/java/tools/refinery/generator/ValidationErrorsException.java
new file mode 100644
index 00000000..d668e51d
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ValidationErrorsException.java
@@ -0,0 +1,64 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import org.eclipse.emf.common.util.URI;
9import org.eclipse.xtext.validation.Issue;
10
11import java.util.List;
12
13public class ValidationErrorsException extends IllegalArgumentException {
14 private final transient URI resourceUri;
15
16 private final String resourceUriString;
17
18 private final transient List<Issue> errors;
19
20 private final List<String> errorStrings;
21
22 public ValidationErrorsException(URI resourceUri, List<Issue> errors) {
23 this.resourceUri = resourceUri;
24 resourceUriString = resourceUri.toString();
25 this.errors = errors;
26 errorStrings = errors.stream()
27 .map(Issue::toString)
28 .toList();
29 }
30
31 public URI getResourceUri() {
32 return resourceUri;
33 }
34
35 public String getResourceUriString() {
36 return resourceUriString;
37 }
38
39 public List<Issue> getErrors() {
40 return errors;
41 }
42
43 public List<String> getErrorStrings() {
44 return errorStrings;
45 }
46
47 @Override
48 public String getMessage() {
49 var builder = new StringBuilder();
50 builder.append("Validation errors in resource ");
51 builder.append(resourceUriString);
52 builder.append(": ");
53 var iterator = errorStrings.iterator();
54 if (!iterator.hasNext()) {
55 return builder.toString();
56 }
57 builder.append(iterator.next());
58 while (iterator.hasNext()) {
59 builder.append(",\n");
60 builder.append(iterator.next());
61 }
62 return builder.toString();
63 }
64}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/impl/ProblemTraceImpl.java b/subprojects/generator/src/main/java/tools/refinery/generator/impl/ProblemTraceImpl.java
new file mode 100644
index 00000000..109e34af
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/impl/ProblemTraceImpl.java
@@ -0,0 +1,84 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.impl;
7
8import com.google.inject.Inject;
9import org.eclipse.emf.ecore.util.EcoreUtil;
10import org.eclipse.xtext.naming.IQualifiedNameConverter;
11import org.eclipse.xtext.naming.IQualifiedNameProvider;
12import org.eclipse.xtext.naming.QualifiedName;
13import org.eclipse.xtext.scoping.IScopeProvider;
14import tools.refinery.generator.ProblemTrace;
15import tools.refinery.language.model.problem.Problem;
16import tools.refinery.language.model.problem.ProblemPackage;
17import tools.refinery.language.model.problem.Relation;
18import tools.refinery.language.semantics.model.ModelInitializer;
19import tools.refinery.store.reasoning.representation.PartialRelation;
20
21import java.util.Collections;
22import java.util.Map;
23
24public final class ProblemTraceImpl implements ProblemTrace {
25 @Inject
26 private IQualifiedNameConverter qualifiedNameConverter;
27
28 @Inject
29 private IQualifiedNameProvider qualifiedNameProvider;
30
31 @Inject
32 private IScopeProvider scopeProvider;
33
34 private Problem problem;
35 private Map<Relation, PartialRelation> relationTrace;
36
37 public void setInitializer(ModelInitializer initializer) {
38 problem = initializer.getProblem();
39 relationTrace = Collections.unmodifiableMap(initializer.getRelationTrace());
40 }
41
42 public Problem getProblem() {
43 return problem;
44 }
45
46 public Map<Relation, PartialRelation> getRelationTrace() {
47 return relationTrace;
48 }
49
50 public PartialRelation getPartialRelation(Relation relation) {
51 var partialRelation = relationTrace.get(relation);
52 if (partialRelation == null) {
53 var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(relation);
54 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
55 throw new IllegalArgumentException("No partial relation for relation " + qualifiedNameString);
56 }
57 return partialRelation;
58 }
59
60 public PartialRelation getPartialRelation(QualifiedName qualifiedName) {
61 var scope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION);
62 var iterator = scope.getElements(qualifiedName).iterator();
63 if (!iterator.hasNext()) {
64 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
65 throw new IllegalArgumentException("No such relation: " + qualifiedNameString);
66 }
67 var eObjectDescription = iterator.next();
68 if (iterator.hasNext()) {
69 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
70 throw new IllegalArgumentException("Ambiguous relation: " + qualifiedNameString);
71 }
72 var eObject = EcoreUtil.resolve(eObjectDescription.getEObjectOrProxy(), problem);
73 if (!(eObject instanceof Relation relation)) {
74 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
75 throw new IllegalArgumentException("Not a relation: " + qualifiedNameString);
76 }
77 return getPartialRelation(relation);
78 }
79
80 public PartialRelation getPartialRelation(String qualifiedName) {
81 var convertedName = qualifiedNameConverter.toQualifiedName(qualifiedName);
82 return getPartialRelation(convertedName);
83 }
84}