aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-06 00:38:12 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-17 12:41:34 +0100
commit2e0bceb2f25989713f1baf6311d3787c3003d794 (patch)
treebf4ba62516d4328ac82e5eecb5853e2c3ee244af
parentfeat(language-ide): content assist filtering (diff)
downloadrefinery-2e0bceb2f25989713f1baf6311d3787c3003d794.tar.gz
refinery-2e0bceb2f25989713f1baf6311d3787c3003d794.tar.zst
refinery-2e0bceb2f25989713f1baf6311d3787c3003d794.zip
feat: predicates as reference types
Now unary predicates may be used as types for cross-references. This might create circular references between predicate, but no differently than when the user manually creates predicates with circular references. The reference types of containment and container references still have to be classes, because we use the class hierarchy to encode contained types.
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java8
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java10
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java30
3 files changed, 32 insertions, 16 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
index b3c58366..ecaa7e0d 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
@@ -63,6 +63,8 @@ public class ModelInitializer {
63 63
64 private final Map<PartialRelation, RelationInfo> partialRelationInfoMap = new HashMap<>(); 64 private final Map<PartialRelation, RelationInfo> partialRelationInfoMap = new HashMap<>();
65 65
66 private final Set<PartialRelation> targetTypes = new HashSet<>();
67
66 private final MetamodelBuilder metamodelBuilder = Metamodel.builder(); 68 private final MetamodelBuilder metamodelBuilder = Metamodel.builder();
67 69
68 private Metamodel metamodel; 70 private Metamodel metamodel;
@@ -285,6 +287,7 @@ public class ModelInitializer {
285 var relation = getPartialRelation(referenceDeclaration); 287 var relation = getPartialRelation(referenceDeclaration);
286 var source = getPartialRelation(classDeclaration); 288 var source = getPartialRelation(classDeclaration);
287 var target = getPartialRelation(referenceDeclaration.getReferenceType()); 289 var target = getPartialRelation(referenceDeclaration.getReferenceType());
290 targetTypes.add(target);
288 boolean containment = referenceDeclaration.getKind() == ReferenceKind.CONTAINMENT; 291 boolean containment = referenceDeclaration.getKind() == ReferenceKind.CONTAINMENT;
289 var opposite = referenceDeclaration.getOpposite(); 292 var opposite = referenceDeclaration.getOpposite();
290 PartialRelation oppositeRelation = null; 293 PartialRelation oppositeRelation = null;
@@ -473,17 +476,16 @@ public class ModelInitializer {
473 private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) { 476 private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) {
474 var partialRelation = getPartialRelation(predicateDefinition); 477 var partialRelation = getPartialRelation(predicateDefinition);
475 var query = toQuery(partialRelation.name(), predicateDefinition); 478 var query = toQuery(partialRelation.name(), predicateDefinition);
476 boolean mutable; 479 boolean mutable = targetTypes.contains(partialRelation);
477 TruthValue defaultValue; 480 TruthValue defaultValue;
478 if (predicateDefinition.isError()) { 481 if (predicateDefinition.isError()) {
479 mutable = false;
480 defaultValue = TruthValue.FALSE; 482 defaultValue = TruthValue.FALSE;
481 } else { 483 } else {
482 var seed = modelSeed.getSeed(partialRelation); 484 var seed = modelSeed.getSeed(partialRelation);
483 defaultValue = seed.reducedValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; 485 defaultValue = seed.reducedValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN;
484 var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size()); 486 var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size());
485 // The symbol should be mutable if there is at least one non-default entry in the seed. 487 // The symbol should be mutable if there is at least one non-default entry in the seed.
486 mutable = cursor.move(); 488 mutable = mutable || cursor.move();
487 } 489 }
488 var translator = new PredicateTranslator(partialRelation, query, mutable, defaultValue); 490 var translator = new PredicateTranslator(partialRelation, query, mutable, defaultValue);
489 storeBuilder.with(translator); 491 storeBuilder.with(translator);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
index 0700f9f7..2e804b44 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
@@ -15,15 +15,17 @@ import tools.refinery.store.representation.TruthValue;
15import tools.refinery.store.tuple.Tuple; 15import tools.refinery.store.tuple.Tuple;
16 16
17class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> { 17class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> {
18 private final PartialRelation targetType;
18 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner; 19 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner;
19 private final PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner; 20 private PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner;
20 21
21 public DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 22 public DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
22 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType, 23 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType,
23 PartialRelation targetType) { 24 PartialRelation targetType) {
24 super(adapter, partialSymbol, concreteSymbol); 25 super(adapter, partialSymbol, concreteSymbol);
26 this.targetType = targetType;
27 // Source is always a class, so we can rely on the fact that it is always constructed before this refiner.
25 sourceRefiner = adapter.getRefiner(sourceType); 28 sourceRefiner = adapter.getRefiner(sourceType);
26 targetRefiner = adapter.getRefiner(targetType);
27 } 29 }
28 30
29 @Override 31 @Override
@@ -32,6 +34,10 @@ class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Bo
32 return false; 34 return false;
33 } 35 }
34 if (value.must()) { 36 if (value.must()) {
37 if (targetRefiner == null) {
38 // Access the target refinery lazily, since it may be constructed after this refiner.
39 targetRefiner = getAdapter().getRefiner(targetType);
40 }
35 return sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && 41 return sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
36 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); 42 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
37 } 43 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java
index ad0288ed..74022fc6 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java
@@ -153,15 +153,11 @@ public class MetamodelBuilder {
153 return; 153 return;
154 } 154 }
155 var sourceType = info.sourceType(); 155 var sourceType = info.sourceType();
156 var targetType = info.targetType();
157 if (typeHierarchyBuilder.isInvalidType(sourceType)) { 156 if (typeHierarchyBuilder.isInvalidType(sourceType)) {
158 throw new TranslationException(linkType, "Source type %s of %s is not in type hierarchy" 157 throw new TranslationException(linkType, "Source type %s of %s is not in type hierarchy"
159 .formatted(sourceType, linkType)); 158 .formatted(sourceType, linkType));
160 } 159 }
161 if (typeHierarchyBuilder.isInvalidType(targetType)) { 160 var targetType = info.targetType();
162 throw new TranslationException(linkType, "Target type %s of %s is not in type hierarchy"
163 .formatted(targetType, linkType));
164 }
165 var opposite = info.opposite(); 161 var opposite = info.opposite();
166 Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE; 162 Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE;
167 if (opposite != null) { 163 if (opposite != null) {
@@ -185,18 +181,30 @@ public class MetamodelBuilder {
185 oppositeReferences.put(opposite, linkType); 181 oppositeReferences.put(opposite, linkType);
186 } 182 }
187 if (info.containment()) { 183 if (info.containment()) {
188 if (!UnconstrainedMultiplicity.INSTANCE.equals(targetMultiplicity)) { 184 processContainmentInfo(linkType, info, targetMultiplicity);
189 throw new TranslationException(opposite, "Invalid opposite %s with multiplicity %s of containment %s"
190 .formatted(opposite, targetMultiplicity, linkType));
191 }
192 containedTypes.add(targetType);
193 containmentHierarchy.put(linkType, new ContainmentInfo(sourceType, info.multiplicity(), targetType));
194 return; 185 return;
195 } 186 }
196 directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(), 187 directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(),
197 targetType, targetMultiplicity)); 188 targetType, targetMultiplicity));
198 } 189 }
199 190
191 private void processContainmentInfo(PartialRelation linkType, ReferenceInfo info,
192 Multiplicity targetMultiplicity) {
193 var sourceType = info.sourceType();
194 var targetType = info.targetType();
195 var opposite = info.opposite();
196 if (typeHierarchyBuilder.isInvalidType(targetType)) {
197 throw new TranslationException(linkType, "Target type %s of %s is not in type hierarchy"
198 .formatted(targetType, linkType));
199 }
200 if (!UnconstrainedMultiplicity.INSTANCE.equals(targetMultiplicity)) {
201 throw new TranslationException(opposite, "Invalid opposite %s with multiplicity %s of containment %s"
202 .formatted(opposite, targetMultiplicity, linkType));
203 }
204 containedTypes.add(targetType);
205 containmentHierarchy.put(linkType, new ContainmentInfo(sourceType, info.multiplicity(), targetType));
206 }
207
200 private static void validateOpposite(PartialRelation linkType, ReferenceInfo info, PartialRelation opposite, 208 private static void validateOpposite(PartialRelation linkType, ReferenceInfo info, PartialRelation opposite,
201 ReferenceInfo oppositeInfo) { 209 ReferenceInfo oppositeInfo) {
202 var sourceType = info.sourceType(); 210 var sourceType = info.sourceType();