aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-11-19 14:58:55 +0100
committerLibravatar GitHub <noreply@github.com>2023-11-19 14:58:55 +0100
commitdf0f7cbf05558ce8691759256caa64ab01dd5d9c (patch)
tree0a842960e27ad25d458c18f7bd9f8b4bf5b89b6c /subprojects/store-reasoning/src
parentbuild: prepare for Maven publication (diff)
parentfeat(langauge): validate exists and equals (diff)
downloadrefinery-df0f7cbf05558ce8691759256caa64ab01dd5d9c.tar.gz
refinery-df0f7cbf05558ce8691759256caa64ab01dd5d9c.tar.zst
refinery-df0f7cbf05558ce8691759256caa64ab01dd5d9c.zip
Merge pull request #48 from kris7t/validator
Improve content assist and validator
Diffstat (limited to 'subprojects/store-reasoning/src')
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java38
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java71
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/InferredContainment.java2
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/MustAnyContainmentLinkView.java21
-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
7 files changed, 145 insertions, 31 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
index 61037be3..c85bd8b7 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
@@ -52,9 +52,10 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
52 52
53 private final Symbol<InferredContainment> containsStorage = Symbol.of("CONTAINS", 2, InferredContainment.class, 53 private final Symbol<InferredContainment> containsStorage = Symbol.of("CONTAINS", 2, InferredContainment.class,
54 InferredContainment.UNKNOWN); 54 InferredContainment.UNKNOWN);
55 private final AnySymbolView mustAnyContainmentLinkView = new MustAnyContainmentLinkView(containsStorage);
55 private final AnySymbolView forbiddenContainsView = new ForbiddenContainsView(containsStorage); 56 private final AnySymbolView forbiddenContainsView = new ForbiddenContainsView(containsStorage);
56 private final RelationalQuery containsMayNewTargetHelper; 57 private final RelationalQuery containsMayNewTargetHelper;
57 private final RelationalQuery containsMayExistingHelper; 58 private final RelationalQuery containsWithoutLink;
58 private final RelationalQuery weakComponents; 59 private final RelationalQuery weakComponents;
59 private final RelationalQuery strongComponents; 60 private final RelationalQuery strongComponents;
60 private final Map<PartialRelation, ContainmentInfo> containmentInfoMap; 61 private final Map<PartialRelation, ContainmentInfo> containmentInfoMap;
@@ -67,18 +68,15 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
67 containsMayNewTargetHelper = Query.of(name + "#mayNewTargetHelper", (builder, child) -> builder 68 containsMayNewTargetHelper = Query.of(name + "#mayNewTargetHelper", (builder, child) -> builder
68 .clause(Integer.class, existingContainers -> List.of( 69 .clause(Integer.class, existingContainers -> List.of(
69 may(CONTAINED_SYMBOL.call(child)), 70 may(CONTAINED_SYMBOL.call(child)),
70 new CountLowerBoundLiteral(existingContainers, CONTAINS_SYMBOL, List.of(Variable.of(), child)), 71 new CountLowerBoundLiteral(existingContainers, CONTAINS_SYMBOL,
72 List.of(Variable.of(), child)),
71 check(less(existingContainers, constant(1))) 73 check(less(existingContainers, constant(1)))
72 ))); 74 )));
73 75
74 containsMayExistingHelper = Query.of(name + "#mayExistingHelper", (builder, parent, child) -> builder 76 containsWithoutLink = Query.of(name + "#withoutLink", (builder, parent, child) -> builder.clause(
75 .clause(Integer.class, existingContainers -> List.of( 77 must(CONTAINS_SYMBOL.call(parent, child)),
76 must(CONTAINS_SYMBOL.call(parent, child)), 78 not(mustAnyContainmentLinkView.call(parent, child))
77 not(forbiddenContainsView.call(parent, child)) 79 ));
78 // Violation of monotonicity:
79 // Containment edges violating upper multiplicity will not be marked as {@code ERROR}, but the
80 // {@code invalidNumberOfContainers} error pattern will already mark the node as invalid.
81 )));
82 80
83 var mustExistBothContains = Query.of(name + "#mustExistBoth", (builder, parent, child) -> builder.clause( 81 var mustExistBothContains = Query.of(name + "#mustExistBoth", (builder, parent, child) -> builder.clause(
84 must(CONTAINS_SYMBOL.call(parent, child)), 82 must(CONTAINS_SYMBOL.call(parent, child)),
@@ -139,13 +137,21 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
139 var mayNewHelper = Query.of(name + "#mayNewHelper", (builder, parent, child) -> builder.clause( 137 var mayNewHelper = Query.of(name + "#mayNewHelper", (builder, parent, child) -> builder.clause(
140 mayNewSourceHelper.call(parent), 138 mayNewSourceHelper.call(parent),
141 mayNewTargetHelper.call(child), 139 mayNewTargetHelper.call(child),
142 not(must(CONTAINS_SYMBOL.call(parent, child))), 140 not(mustAnyContainmentLinkView.call(parent, child)),
143 not(forbiddenLinkView.call(parent, child)) 141 not(forbiddenLinkView.call(parent, child))
144 )); 142 ));
145 143
144 var existingContainsLink = Query.of(name + "#existingContaints", (builder, parent, child) -> builder
145 .clause(
146 must(linkType.call(parent, child))
147 )
148 .clause(
149 containsWithoutLink.call(parent, child)
150 ));
151
146 var mayExistingHelper = Query.of(name + "#mayExistingHelper", (builder, parent, child) -> builder.clause( 152 var mayExistingHelper = Query.of(name + "#mayExistingHelper", (builder, parent, child) -> builder.clause(
147 must(linkType.call(parent, child)), 153 existingContainsLink.call(parent, child),
148 containsMayExistingHelper.call(parent, child), 154 not(forbiddenContainsView.call(parent, child)),
149 may(sourceType.call(parent)), 155 may(sourceType.call(parent)),
150 may(targetType.call(child)), 156 may(targetType.call(child)),
151 not(forbiddenLinkView.call(parent, child)) 157 not(forbiddenLinkView.call(parent, child))
@@ -224,7 +230,9 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
224 })) 230 }))
225 .must(Query.of(mustName, (builder, parent, child) -> builder.clause( 231 .must(Query.of(mustName, (builder, parent, child) -> builder.clause(
226 new MustContainsView(containsStorage).call(parent, child) 232 new MustContainsView(containsStorage).call(parent, child)
227 )))); 233 )))
234 .refiner(ContainsRefiner.of(containsStorage))
235 .initializer(new RefinementBasedInitializer<>(CONTAINS_SYMBOL)));
228 } 236 }
229 237
230 private void translateInvalidContainer(ModelStoreBuilder storeBuilder) { 238 private void translateInvalidContainer(ModelStoreBuilder storeBuilder) {
@@ -245,7 +253,7 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
245 ) 253 )
246 .clause(container -> List.of( 254 .clause(container -> List.of(
247 MultiObjectTranslator.MULTI_VIEW.call(multi), 255 MultiObjectTranslator.MULTI_VIEW.call(multi),
248 must(CONTAINS_SYMBOL.call(container, multi)), 256 mustAnyContainmentLinkView.call(container, multi),
249 not(MultiObjectTranslator.MULTI_VIEW.call(container)) 257 not(MultiObjectTranslator.MULTI_VIEW.call(container))
250 )) 258 ))
251 .action( 259 .action(
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
index 497ed98f..e44fcffd 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
@@ -24,8 +24,8 @@ class ContainmentLinkRefiner extends AbstractPartialInterpretationRefiner<TruthV
24 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner; 24 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner;
25 private final PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner; 25 private final PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner;
26 26
27 public ContainmentLinkRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 27 private ContainmentLinkRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
28 Factory factory) { 28 Factory factory) {
29 super(adapter, partialSymbol); 29 super(adapter, partialSymbol);
30 this.factory = factory; 30 this.factory = factory;
31 interpretation = adapter.getModel().getInterpretation(factory.symbol); 31 interpretation = adapter.getModel().getInterpretation(factory.symbol);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java
new file mode 100644
index 00000000..a7196a1c
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java
@@ -0,0 +1,71 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.containment;
7
8import tools.refinery.store.model.Interpretation;
9import tools.refinery.store.reasoning.ReasoningAdapter;
10import tools.refinery.store.reasoning.refinement.AbstractPartialInterpretationRefiner;
11import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
12import tools.refinery.store.reasoning.representation.PartialSymbol;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.representation.TruthValue;
15import tools.refinery.store.tuple.Tuple;
16
17import java.util.LinkedHashMap;
18import java.util.Map;
19import java.util.Set;
20
21class ContainsRefiner extends AbstractPartialInterpretationRefiner<TruthValue, Boolean> {
22 private static final Map<TruthValue, InferredContainment> EMPTY_VALUES;
23
24 static {
25 var values = TruthValue.values();
26 EMPTY_VALUES = new LinkedHashMap<>(values.length);
27 for (var value : values) {
28 EMPTY_VALUES.put(value, new InferredContainment(value, Set.of(), Set.of()));
29 }
30 }
31
32 private final Interpretation<InferredContainment> interpretation;
33 private final PartialInterpretationRefiner<TruthValue, Boolean> containedRefiner;
34
35 private ContainsRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
36 Symbol<InferredContainment> containsStorage) {
37 super(adapter, partialSymbol);
38 interpretation = adapter.getModel().getInterpretation(containsStorage);
39 containedRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINED_SYMBOL);
40 }
41
42 @Override
43 public boolean merge(Tuple key, TruthValue value) {
44 var oldValue = interpretation.get(key);
45 var newValue = mergeLink(oldValue, value);
46 if (oldValue != newValue) {
47 interpretation.put(key, newValue);
48 }
49 if (value.must()) {
50 return containedRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
51 }
52 return true;
53 }
54
55 public InferredContainment mergeLink(InferredContainment oldValue, TruthValue toMerge) {
56 var newContains = oldValue.contains().merge(toMerge);
57 if (newContains.equals(oldValue.contains())) {
58 return oldValue;
59 }
60 var mustLinks = oldValue.mustLinks();
61 var forbiddenLinks = oldValue.forbiddenLinks();
62 if (mustLinks.isEmpty() && forbiddenLinks.isEmpty()) {
63 return EMPTY_VALUES.get(newContains);
64 }
65 return new InferredContainment(newContains, mustLinks, forbiddenLinks);
66 }
67
68 public static PartialInterpretationRefiner.Factory<TruthValue, Boolean> of(Symbol<InferredContainment> symbol) {
69 return (adapter, partialSymbol) -> new ContainsRefiner(adapter, partialSymbol, symbol);
70 }
71}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/InferredContainment.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/InferredContainment.java
index 8df23d9a..8a757ed2 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/InferredContainment.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/InferredContainment.java
@@ -24,7 +24,7 @@ final class InferredContainment {
24 this.contains = adjustContains(contains, mustLinks, forbiddenLinks); 24 this.contains = adjustContains(contains, mustLinks, forbiddenLinks);
25 this.mustLinks = mustLinks; 25 this.mustLinks = mustLinks;
26 this.forbiddenLinks = forbiddenLinks; 26 this.forbiddenLinks = forbiddenLinks;
27 hashCode = Objects.hash(contains, mustLinks, forbiddenLinks); 27 hashCode = Objects.hash(this.contains, mustLinks, forbiddenLinks);
28 } 28 }
29 29
30 private static TruthValue adjustContains(TruthValue contains, Set<PartialRelation> mustLinks, 30 private static TruthValue adjustContains(TruthValue contains, Set<PartialRelation> mustLinks,
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/MustAnyContainmentLinkView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/MustAnyContainmentLinkView.java
new file mode 100644
index 00000000..1cc537c6
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/MustAnyContainmentLinkView.java
@@ -0,0 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.containment;
7
8import tools.refinery.store.query.view.TuplePreservingView;
9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple;
11
12class MustAnyContainmentLinkView extends TuplePreservingView<InferredContainment> {
13 public MustAnyContainmentLinkView(Symbol<InferredContainment> symbol) {
14 super(symbol, "contains#mustAnyLink");
15 }
16
17 @Override
18 protected boolean doFilter(Tuple key, InferredContainment value) {
19 return !value.mustLinks().isEmpty();
20 }
21}
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();