diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-11-06 00:38:12 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-11-17 12:41:34 +0100 |
commit | 2e0bceb2f25989713f1baf6311d3787c3003d794 (patch) | |
tree | bf4ba62516d4328ac82e5eecb5853e2c3ee244af | |
parent | feat(language-ide): content assist filtering (diff) | |
download | refinery-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.
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; | |||
15 | import tools.refinery.store.tuple.Tuple; | 15 | import tools.refinery.store.tuple.Tuple; |
16 | 16 | ||
17 | class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> { | 17 | class 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(); |