diff options
Diffstat (limited to 'subprojects/store-reasoning')
13 files changed, 425 insertions, 135 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java index 8b1c3bb3..3b78db02 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java | |||
@@ -12,19 +12,19 @@ import tools.refinery.store.tuple.Tuple; | |||
12 | import java.util.Map; | 12 | import java.util.Map; |
13 | import java.util.Objects; | 13 | import java.util.Objects; |
14 | 14 | ||
15 | record MapBasedSeed<T>(int arity, Class<T> valueType, T reducedValue, Map<Tuple, T> map) implements Seed<T> { | 15 | record MapBasedSeed<T>(int arity, Class<T> valueType, T majorityValue, Map<Tuple, T> map) implements Seed<T> { |
16 | @Override | 16 | @Override |
17 | public T get(Tuple key) { | 17 | public T get(Tuple key) { |
18 | var value = map.get(key); | 18 | var value = map.get(key); |
19 | return value == null ? reducedValue : value; | 19 | return value == null ? majorityValue : value; |
20 | } | 20 | } |
21 | 21 | ||
22 | @Override | 22 | @Override |
23 | public Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount) { | 23 | public Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount) { |
24 | if (Objects.equals(defaultValue, reducedValue)) { | 24 | if (Objects.equals(defaultValue, majorityValue)) { |
25 | return Cursors.of(map); | 25 | return Cursors.of(map); |
26 | } | 26 | } |
27 | return new CartesianProductCursor<>(arity, nodeCount, reducedValue, defaultValue, map); | 27 | return new CartesianProductCursor<>(arity, nodeCount, majorityValue, defaultValue, map); |
28 | } | 28 | } |
29 | 29 | ||
30 | private static class CartesianProductCursor<T> implements Cursor<Tuple, T> { | 30 | private static class CartesianProductCursor<T> implements Cursor<Tuple, T> { |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java index 732efbcc..d9bad866 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java | |||
@@ -19,7 +19,7 @@ public interface Seed<T> { | |||
19 | 19 | ||
20 | Class<T> valueType(); | 20 | Class<T> valueType(); |
21 | 21 | ||
22 | T reducedValue(); | 22 | T majorityValue(); |
23 | 23 | ||
24 | T get(Tuple key); | 24 | T get(Tuple key); |
25 | 25 | ||
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInfo.java index d8c6a5ea..7241b032 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInfo.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInfo.java | |||
@@ -7,9 +7,11 @@ package tools.refinery.store.reasoning.translator.crossreference; | |||
7 | 7 | ||
8 | import tools.refinery.store.reasoning.representation.PartialRelation; | 8 | import tools.refinery.store.reasoning.representation.PartialRelation; |
9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
10 | import tools.refinery.store.representation.TruthValue; | ||
10 | 11 | ||
11 | public record DirectedCrossReferenceInfo(PartialRelation sourceType, Multiplicity sourceMultiplicity, | 12 | public record DirectedCrossReferenceInfo(PartialRelation sourceType, Multiplicity sourceMultiplicity, |
12 | PartialRelation targetType, Multiplicity targetMultiplicity) { | 13 | PartialRelation targetType, Multiplicity targetMultiplicity, |
14 | TruthValue defaultValue) { | ||
13 | public boolean isConstrained() { | 15 | public boolean isConstrained() { |
14 | return sourceMultiplicity.isConstrained() || targetMultiplicity.isConstrained(); | 16 | return sourceMultiplicity.isConstrained() || targetMultiplicity.isConstrained(); |
15 | } | 17 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java new file mode 100644 index 00000000..9347e91e --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.reasoning.translator.crossreference; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
10 | import tools.refinery.store.reasoning.refinement.PartialModelInitializer; | ||
11 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
12 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | import tools.refinery.store.representation.TruthValue; | ||
15 | import tools.refinery.store.tuple.Tuple; | ||
16 | |||
17 | class DirectedCrossReferenceInitializer implements PartialModelInitializer { | ||
18 | private final PartialRelation linkType; | ||
19 | private final PartialRelation sourceType; | ||
20 | private final PartialRelation targetType; | ||
21 | private final Symbol<TruthValue> symbol; | ||
22 | |||
23 | public DirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType, | ||
24 | PartialRelation targetType, Symbol<TruthValue> symbol) { | ||
25 | this.linkType = linkType; | ||
26 | this.sourceType = sourceType; | ||
27 | this.targetType = targetType; | ||
28 | this.symbol = symbol; | ||
29 | } | ||
30 | |||
31 | @Override | ||
32 | public void initialize(Model model, ModelSeed modelSeed) { | ||
33 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
34 | var sourceRefiner = reasoningAdapter.getRefiner(sourceType); | ||
35 | var targetRefiner = reasoningAdapter.getRefiner(targetType); | ||
36 | var interpretation = model.getInterpretation(symbol); | ||
37 | var cursor = modelSeed.getCursor(linkType, symbol.defaultValue()); | ||
38 | while (cursor.move()) { | ||
39 | var key = cursor.getKey(); | ||
40 | var value = cursor.getValue(); | ||
41 | interpretation.put(key, value); | ||
42 | if (value.must()) { | ||
43 | boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && | ||
44 | targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); | ||
45 | if (!merged) { | ||
46 | throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" | ||
47 | .formatted(linkType, key)); | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java index 9028337c..fc7477f1 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.translator.crossreference; | 6 | package tools.refinery.store.reasoning.translator.crossreference; |
7 | 7 | ||
8 | import tools.refinery.store.dse.propagation.PropagationBuilder; | ||
8 | import tools.refinery.store.dse.transition.Rule; | 9 | import tools.refinery.store.dse.transition.Rule; |
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
10 | import tools.refinery.store.model.ModelStoreConfiguration; | 11 | import tools.refinery.store.model.ModelStoreConfiguration; |
@@ -14,9 +15,9 @@ import tools.refinery.store.query.view.ForbiddenView; | |||
14 | import tools.refinery.store.reasoning.lifting.DnfLifter; | 15 | import tools.refinery.store.reasoning.lifting.DnfLifter; |
15 | import tools.refinery.store.reasoning.literal.Concreteness; | 16 | import tools.refinery.store.reasoning.literal.Concreteness; |
16 | import tools.refinery.store.reasoning.literal.Modality; | 17 | import tools.refinery.store.reasoning.literal.Modality; |
17 | import tools.refinery.store.reasoning.refinement.RefinementBasedInitializer; | ||
18 | import tools.refinery.store.reasoning.representation.PartialRelation; | 18 | import tools.refinery.store.reasoning.representation.PartialRelation; |
19 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | 19 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; |
20 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
20 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; | 21 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; |
21 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 22 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
22 | import tools.refinery.store.representation.Symbol; | 23 | import tools.refinery.store.representation.Symbol; |
@@ -24,6 +25,7 @@ import tools.refinery.store.representation.TruthValue; | |||
24 | 25 | ||
25 | import static tools.refinery.store.query.literal.Literals.not; | 26 | import static tools.refinery.store.query.literal.Literals.not; |
26 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; | 27 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
28 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.merge; | ||
27 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; | 29 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; |
28 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; | 30 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; |
29 | 31 | ||
@@ -35,7 +37,7 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration | |||
35 | public DirectedCrossReferenceTranslator(PartialRelation linkType, DirectedCrossReferenceInfo info) { | 37 | public DirectedCrossReferenceTranslator(PartialRelation linkType, DirectedCrossReferenceInfo info) { |
36 | this.linkType = linkType; | 38 | this.linkType = linkType; |
37 | this.info = info; | 39 | this.info = info; |
38 | symbol = Symbol.of(linkType.name(), 2, TruthValue.class, TruthValue.UNKNOWN); | 40 | symbol = Symbol.of(linkType.name(), 2, TruthValue.class, info.defaultValue()); |
39 | } | 41 | } |
40 | 42 | ||
41 | @Override | 43 | @Override |
@@ -45,41 +47,77 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration | |||
45 | var targetType = info.targetType(); | 47 | var targetType = info.targetType(); |
46 | var mayNewSource = createMayHelper(sourceType, info.sourceMultiplicity(), false); | 48 | var mayNewSource = createMayHelper(sourceType, info.sourceMultiplicity(), false); |
47 | var mayNewTarget = createMayHelper(targetType, info.targetMultiplicity(), true); | 49 | var mayNewTarget = createMayHelper(targetType, info.targetMultiplicity(), true); |
48 | var forbiddenView = new ForbiddenView(symbol); | ||
49 | var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL); | 50 | var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL); |
50 | 51 | ||
51 | storeBuilder.with(PartialRelationTranslator.of(linkType) | 52 | var defaultValue = info.defaultValue(); |
52 | .symbol(symbol) | 53 | if (defaultValue.must()) { |
53 | .may(Query.of(mayName, (builder, source, target) -> { | 54 | throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" |
55 | .formatted(defaultValue, linkType)); | ||
56 | } | ||
57 | |||
58 | var translator = PartialRelationTranslator.of(linkType); | ||
59 | translator.symbol(symbol); | ||
60 | if (defaultValue.may()) { | ||
61 | var forbiddenView = new ForbiddenView(symbol); | ||
62 | translator.may(Query.of(mayName, (builder, source, target) -> { | ||
63 | builder.clause( | ||
64 | mayNewSource.call(source), | ||
65 | mayNewTarget.call(target), | ||
66 | not(forbiddenView.call(source, target)) | ||
67 | ); | ||
68 | if (info.isConstrained()) { | ||
69 | // Violation of monotonicity: | ||
70 | // Edges violating upper multiplicity will not be marked as {@code ERROR}, but the | ||
71 | // corresponding error pattern will already mark the node as invalid. | ||
72 | builder.clause( | ||
73 | must(linkType.call(source, target)), | ||
74 | not(forbiddenView.call(source, target)), | ||
75 | may(sourceType.call(source)), | ||
76 | may(targetType.call(target)) | ||
77 | ); | ||
78 | } | ||
79 | })); | ||
80 | } else { | ||
81 | var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class); | ||
82 | propagationBuilder.rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { | ||
83 | builder.clause( | ||
84 | may(linkType.call(p1, p2)), | ||
85 | not(may(sourceType.call(p1))) | ||
86 | ); | ||
87 | builder.clause( | ||
88 | may(linkType.call(p1, p2)), | ||
89 | not(may(targetType.call(p2))) | ||
90 | ); | ||
91 | if (info.isConstrained()) { | ||
92 | builder.clause( | ||
93 | may(linkType.call(p1, p2)), | ||
94 | not(must(linkType.call(p1, p2))), | ||
95 | not(mayNewSource.call(p1)) | ||
96 | ); | ||
54 | builder.clause( | 97 | builder.clause( |
55 | mayNewSource.call(source), | 98 | may(linkType.call(p1, p2)), |
56 | mayNewTarget.call(target), | 99 | not(must(linkType.call(p1, p2))), |
57 | not(forbiddenView.call(source, target)) | 100 | not(mayNewTarget.call(p2)) |
58 | ); | 101 | ); |
59 | if (info.isConstrained()) { | 102 | } |
60 | // Violation of monotonicity: | 103 | builder.action( |
61 | // Edges violating upper multiplicity will not be marked as {@code ERROR}, but the | 104 | merge(linkType, TruthValue.FALSE, p1, p2) |
62 | // corresponding error pattern will already mark the node as invalid. | 105 | ); |
63 | builder.clause( | 106 | })); |
64 | must(linkType.call(source, target)), | 107 | } |
65 | not(forbiddenView.call(source, target)), | 108 | translator.refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType)); |
66 | may(sourceType.call(source)), | 109 | translator.initializer(new DirectedCrossReferenceInitializer(linkType, sourceType, targetType, symbol)); |
67 | may(targetType.call(target)) | 110 | translator.decision(Rule.of(linkType.name(), (builder, source, target) -> builder |
68 | ); | 111 | .clause( |
69 | } | 112 | may(linkType.call(source, target)), |
70 | })) | 113 | not(candidateMust(linkType.call(source, target))), |
71 | .refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType)) | 114 | not(MULTI_VIEW.call(source)), |
72 | .initializer(new RefinementBasedInitializer<>(linkType)) | 115 | not(MULTI_VIEW.call(target)) |
73 | .decision(Rule.of(linkType.name(), (builder, source, target) -> builder | 116 | ) |
74 | .clause( | 117 | .action( |
75 | may(linkType.call(source, target)), | 118 | add(linkType, source, target) |
76 | not(candidateMust(linkType.call(source, target))), | 119 | ))); |
77 | not(MULTI_VIEW.call(source)), | 120 | storeBuilder.with(translator); |
78 | not(MULTI_VIEW.call(target)) | ||
79 | ) | ||
80 | .action( | ||
81 | add(linkType, source, target) | ||
82 | )))); | ||
83 | 121 | ||
84 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(sourceType, linkType, false, | 122 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(sourceType, linkType, false, |
85 | info.sourceMultiplicity())); | 123 | info.sourceMultiplicity())); |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInfo.java index fe99bc54..34e9032a 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInfo.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInfo.java | |||
@@ -7,8 +7,9 @@ package tools.refinery.store.reasoning.translator.crossreference; | |||
7 | 7 | ||
8 | import tools.refinery.store.reasoning.representation.PartialRelation; | 8 | import tools.refinery.store.reasoning.representation.PartialRelation; |
9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
10 | import tools.refinery.store.representation.TruthValue; | ||
10 | 11 | ||
11 | public record UndirectedCrossReferenceInfo(PartialRelation type, Multiplicity multiplicity) { | 12 | public record UndirectedCrossReferenceInfo(PartialRelation type, Multiplicity multiplicity, TruthValue defaultValue) { |
12 | public boolean isConstrained() { | 13 | public boolean isConstrained() { |
13 | return multiplicity.isConstrained(); | 14 | return multiplicity.isConstrained(); |
14 | } | 15 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java new file mode 100644 index 00000000..77339aa0 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.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 | */ | ||
6 | package tools.refinery.store.reasoning.translator.crossreference; | ||
7 | |||
8 | import org.jetbrains.annotations.NotNull; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
11 | import tools.refinery.store.reasoning.refinement.PartialModelInitializer; | ||
12 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
13 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
14 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
15 | import tools.refinery.store.representation.Symbol; | ||
16 | import tools.refinery.store.representation.TruthValue; | ||
17 | import tools.refinery.store.tuple.Tuple; | ||
18 | |||
19 | import java.util.LinkedHashMap; | ||
20 | |||
21 | class UndirectedCrossReferenceInitializer implements PartialModelInitializer { | ||
22 | private final PartialRelation linkType; | ||
23 | private final PartialRelation sourceType; | ||
24 | private final Symbol<TruthValue> symbol; | ||
25 | |||
26 | UndirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType, | ||
27 | Symbol<TruthValue> symbol) { | ||
28 | this.linkType = linkType; | ||
29 | this.sourceType = sourceType; | ||
30 | this.symbol = symbol; | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public void initialize(Model model, ModelSeed modelSeed) { | ||
35 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
36 | var mergedMap = getMergedMap(modelSeed); | ||
37 | var sourceRefiner = reasoningAdapter.getRefiner(sourceType); | ||
38 | var interpretation = model.getInterpretation(symbol); | ||
39 | for (var entry : mergedMap.entrySet()) { | ||
40 | var key = entry.getKey(); | ||
41 | var value = entry.getValue(); | ||
42 | interpretation.put(key, value); | ||
43 | if (value.must()) { | ||
44 | boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && | ||
45 | sourceRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); | ||
46 | if (!merged) { | ||
47 | throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" | ||
48 | .formatted(linkType, key)); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | @NotNull | ||
55 | private LinkedHashMap<Tuple, TruthValue> getMergedMap(ModelSeed modelSeed) { | ||
56 | var defaultValue = symbol.defaultValue(); | ||
57 | var originalMap = new LinkedHashMap<Tuple, TruthValue>(); | ||
58 | var cursor = modelSeed.getCursor(linkType, defaultValue); | ||
59 | while (cursor.move()) { | ||
60 | if (originalMap.put(cursor.getKey(), cursor.getValue()) != null) { | ||
61 | throw new TranslationException(linkType, "Duplicate value for key " + cursor.getKey()); | ||
62 | } | ||
63 | } | ||
64 | var mergedMap = LinkedHashMap.<Tuple, TruthValue>newLinkedHashMap(originalMap.size()); | ||
65 | for (var entry : originalMap.entrySet()) { | ||
66 | var key = entry.getKey(); | ||
67 | var value = entry.getValue(); | ||
68 | int first = key.get(0); | ||
69 | int second = key.get(1); | ||
70 | var oppositeKey = Tuple.of(second, first); | ||
71 | var oppositeValue = originalMap.get(oppositeKey); | ||
72 | if (oppositeValue != null && second < first) { | ||
73 | // Already processed entry. | ||
74 | continue; | ||
75 | } | ||
76 | var mergedValue = value.merge(oppositeValue == null ? defaultValue : oppositeValue); | ||
77 | mergedMap.put(key, mergedValue); | ||
78 | if (first != second) { | ||
79 | mergedMap.put(oppositeKey, mergedValue); | ||
80 | } | ||
81 | } | ||
82 | return mergedMap; | ||
83 | } | ||
84 | } | ||
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java index c554e2a4..b76838b3 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.translator.crossreference; | 6 | package tools.refinery.store.reasoning.translator.crossreference; |
7 | 7 | ||
8 | import tools.refinery.store.dse.propagation.PropagationBuilder; | ||
8 | import tools.refinery.store.dse.transition.Rule; | 9 | import tools.refinery.store.dse.transition.Rule; |
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
10 | import tools.refinery.store.model.ModelStoreConfiguration; | 11 | import tools.refinery.store.model.ModelStoreConfiguration; |
@@ -13,15 +14,16 @@ import tools.refinery.store.query.view.ForbiddenView; | |||
13 | import tools.refinery.store.reasoning.lifting.DnfLifter; | 14 | import tools.refinery.store.reasoning.lifting.DnfLifter; |
14 | import tools.refinery.store.reasoning.literal.Concreteness; | 15 | import tools.refinery.store.reasoning.literal.Concreteness; |
15 | import tools.refinery.store.reasoning.literal.Modality; | 16 | import tools.refinery.store.reasoning.literal.Modality; |
16 | import tools.refinery.store.reasoning.refinement.RefinementBasedInitializer; | ||
17 | import tools.refinery.store.reasoning.representation.PartialRelation; | 17 | import tools.refinery.store.reasoning.representation.PartialRelation; |
18 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | 18 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; |
19 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
19 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; | 20 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; |
20 | import tools.refinery.store.representation.Symbol; | 21 | import tools.refinery.store.representation.Symbol; |
21 | import tools.refinery.store.representation.TruthValue; | 22 | import tools.refinery.store.representation.TruthValue; |
22 | 23 | ||
23 | import static tools.refinery.store.query.literal.Literals.not; | 24 | import static tools.refinery.store.query.literal.Literals.not; |
24 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; | 25 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
26 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.merge; | ||
25 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; | 27 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; |
26 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; | 28 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; |
27 | 29 | ||
@@ -33,50 +35,77 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati | |||
33 | public UndirectedCrossReferenceTranslator(PartialRelation linkType, UndirectedCrossReferenceInfo info) { | 35 | public UndirectedCrossReferenceTranslator(PartialRelation linkType, UndirectedCrossReferenceInfo info) { |
34 | this.linkType = linkType; | 36 | this.linkType = linkType; |
35 | this.info = info; | 37 | this.info = info; |
36 | symbol = Symbol.of(linkType.name(), 2, TruthValue.class, TruthValue.UNKNOWN); | 38 | symbol = Symbol.of(linkType.name(), 2, TruthValue.class, info.defaultValue()); |
37 | } | 39 | } |
38 | 40 | ||
39 | @Override | 41 | @Override |
40 | public void apply(ModelStoreBuilder storeBuilder) { | 42 | public void apply(ModelStoreBuilder storeBuilder) { |
41 | var name = linkType.name(); | 43 | var name = linkType.name(); |
42 | var type = info.type(); | 44 | var type = info.type(); |
43 | var forbiddenView = new ForbiddenView(symbol); | ||
44 | var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL); | 45 | var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL); |
45 | 46 | ||
47 | var defaultValue = info.defaultValue(); | ||
48 | if (defaultValue.must()) { | ||
49 | throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" | ||
50 | .formatted(defaultValue, linkType)); | ||
51 | } | ||
52 | |||
46 | var mayNewSource = CrossReferenceUtils.createMayHelper(linkType, type, info.multiplicity(), false); | 53 | var mayNewSource = CrossReferenceUtils.createMayHelper(linkType, type, info.multiplicity(), false); |
47 | 54 | ||
48 | storeBuilder.with(PartialRelationTranslator.of(linkType) | 55 | var translator = PartialRelationTranslator.of(linkType); |
49 | .symbol(symbol) | 56 | translator.symbol(symbol); |
50 | .may(Query.of(mayName, (builder, source, target) -> { | 57 | if (defaultValue.may()) { |
58 | var forbiddenView = new ForbiddenView(symbol); | ||
59 | translator.may(Query.of(mayName, (builder, source, target) -> { | ||
60 | builder.clause( | ||
61 | mayNewSource.call(source), | ||
62 | mayNewSource.call(target), | ||
63 | not(forbiddenView.call(source, target)) | ||
64 | ); | ||
65 | if (info.isConstrained()) { | ||
66 | // Violation of monotonicity: | ||
67 | // Edges violating upper multiplicity will not be marked as {@code ERROR}, but the | ||
68 | // corresponding error pattern will already mark the node as invalid. | ||
69 | builder.clause( | ||
70 | must(linkType.call(source, target)), | ||
71 | not(forbiddenView.call(source, target)), | ||
72 | may(type.call(source)), | ||
73 | may(type.call(target)) | ||
74 | ); | ||
75 | } | ||
76 | })); | ||
77 | } else { | ||
78 | var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class); | ||
79 | propagationBuilder.rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { | ||
80 | builder.clause( | ||
81 | may(linkType.call(p1, p2)), | ||
82 | not(may(type.call(p1))) | ||
83 | ); | ||
84 | if (info.isConstrained()) { | ||
51 | builder.clause( | 85 | builder.clause( |
52 | mayNewSource.call(source), | 86 | may(linkType.call(p1, p2)), |
53 | mayNewSource.call(target), | 87 | not(must(linkType.call(p1, p2))), |
54 | not(forbiddenView.call(source, target)) | 88 | not(mayNewSource.call(p1)) |
55 | ); | 89 | ); |
56 | if (info.isConstrained()) { | 90 | } |
57 | // Violation of monotonicity: | 91 | builder.action( |
58 | // Edges violating upper multiplicity will not be marked as {@code ERROR}, but the | 92 | merge(linkType, TruthValue.FALSE, p1, p2) |
59 | // corresponding error pattern will already mark the node as invalid. | 93 | ); |
60 | builder.clause( | 94 | })); |
61 | must(linkType.call(source, target)), | 95 | } |
62 | not(forbiddenView.call(source, target)), | 96 | translator.refiner(UndirectedCrossReferenceRefiner.of(symbol, type)); |
63 | may(type.call(source)), | 97 | translator.initializer(new UndirectedCrossReferenceInitializer(linkType, type, symbol)); |
64 | may(type.call(target)) | 98 | translator.decision(Rule.of(linkType.name(), (builder, source, target) -> builder |
65 | ); | 99 | .clause( |
66 | } | 100 | may(linkType.call(source, target)), |
67 | })) | 101 | not(candidateMust(linkType.call(source, target))), |
68 | .refiner(UndirectedCrossReferenceRefiner.of(symbol, type)) | 102 | not(MULTI_VIEW.call(source)), |
69 | .initializer(new RefinementBasedInitializer<>(linkType)) | 103 | not(MULTI_VIEW.call(target)) |
70 | .decision(Rule.of(linkType.name(), (builder, source, target) -> builder | 104 | ) |
71 | .clause( | 105 | .action( |
72 | may(linkType.call(source, target)), | 106 | add(linkType, source, target) |
73 | not(candidateMust(linkType.call(source, target))), | 107 | ))); |
74 | not(MULTI_VIEW.call(source)), | 108 | storeBuilder.with(translator); |
75 | not(MULTI_VIEW.call(target)) | ||
76 | ) | ||
77 | .action( | ||
78 | add(linkType, source, target) | ||
79 | )))); | ||
80 | 109 | ||
81 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity())); | 110 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity())); |
82 | } | 111 | } |
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 74022fc6..a5047768 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 | |||
@@ -16,6 +16,7 @@ import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMulti | |||
16 | import tools.refinery.store.reasoning.translator.typehierarchy.TypeInfo; | 16 | import tools.refinery.store.reasoning.translator.typehierarchy.TypeInfo; |
17 | 17 | ||
18 | import java.util.*; | 18 | import java.util.*; |
19 | import java.util.function.Consumer; | ||
19 | 20 | ||
20 | public class MetamodelBuilder { | 21 | public class MetamodelBuilder { |
21 | private final ContainedTypeHierarchyBuilder typeHierarchyBuilder = new ContainedTypeHierarchyBuilder(); | 22 | private final ContainedTypeHierarchyBuilder typeHierarchyBuilder = new ContainedTypeHierarchyBuilder(); |
@@ -68,6 +69,12 @@ public class MetamodelBuilder { | |||
68 | return this; | 69 | return this; |
69 | } | 70 | } |
70 | 71 | ||
72 | public MetamodelBuilder reference(PartialRelation linkType, Consumer<ReferenceInfoBuilder> callback) { | ||
73 | var builder = ReferenceInfo.builder(); | ||
74 | callback.accept(builder); | ||
75 | return reference(linkType, builder.build()); | ||
76 | } | ||
77 | |||
71 | public MetamodelBuilder reference(PartialRelation linkType, ReferenceInfo info) { | 78 | public MetamodelBuilder reference(PartialRelation linkType, ReferenceInfo info) { |
72 | if (linkType.arity() != 2) { | 79 | if (linkType.arity() != 2) { |
73 | throw new TranslationException(linkType, | 80 | throw new TranslationException(linkType, |
@@ -81,47 +88,6 @@ public class MetamodelBuilder { | |||
81 | return this; | 88 | return this; |
82 | } | 89 | } |
83 | 90 | ||
84 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
85 | Multiplicity multiplicity, PartialRelation targetType, | ||
86 | PartialRelation opposite) { | ||
87 | return reference(linkType, new ReferenceInfo(containment, sourceType, multiplicity, targetType, opposite)); | ||
88 | } | ||
89 | |||
90 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity, | ||
91 | PartialRelation targetType, PartialRelation opposite) { | ||
92 | return reference(linkType, sourceType, false, multiplicity, targetType, opposite); | ||
93 | } | ||
94 | |||
95 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, | ||
96 | boolean containment, PartialRelation targetType, PartialRelation opposite) { | ||
97 | return reference(linkType, sourceType, containment, UnconstrainedMultiplicity.INSTANCE, targetType, opposite); | ||
98 | } | ||
99 | |||
100 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, PartialRelation targetType, | ||
101 | PartialRelation opposite) { | ||
102 | return reference(linkType, sourceType, UnconstrainedMultiplicity.INSTANCE, targetType, opposite); | ||
103 | } | ||
104 | |||
105 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
106 | Multiplicity multiplicity, PartialRelation targetType) { | ||
107 | return reference(linkType, sourceType, containment, multiplicity, targetType, null); | ||
108 | } | ||
109 | |||
110 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity, | ||
111 | PartialRelation targetType) { | ||
112 | return reference(linkType, sourceType, multiplicity, targetType, null); | ||
113 | } | ||
114 | |||
115 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
116 | PartialRelation targetType) { | ||
117 | return reference(linkType, sourceType, containment, targetType, null); | ||
118 | } | ||
119 | |||
120 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, | ||
121 | PartialRelation targetType) { | ||
122 | return reference(linkType, sourceType, targetType, null); | ||
123 | } | ||
124 | |||
125 | public MetamodelBuilder references(Collection<Map.Entry<PartialRelation, ReferenceInfo>> entries) { | 91 | public MetamodelBuilder references(Collection<Map.Entry<PartialRelation, ReferenceInfo>> entries) { |
126 | for (var entry : entries) { | 92 | for (var entry : entries) { |
127 | reference(entry.getKey(), entry.getValue()); | 93 | reference(entry.getKey(), entry.getValue()); |
@@ -160,10 +126,12 @@ public class MetamodelBuilder { | |||
160 | var targetType = info.targetType(); | 126 | var targetType = info.targetType(); |
161 | var opposite = info.opposite(); | 127 | var opposite = info.opposite(); |
162 | Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE; | 128 | Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE; |
129 | var defaultValue = info.defaultValue(); | ||
163 | if (opposite != null) { | 130 | if (opposite != null) { |
164 | var oppositeInfo = referenceInfoMap.get(opposite); | 131 | var oppositeInfo = referenceInfoMap.get(opposite); |
165 | validateOpposite(linkType, info, opposite, oppositeInfo); | 132 | validateOpposite(linkType, info, opposite, oppositeInfo); |
166 | targetMultiplicity = oppositeInfo.multiplicity(); | 133 | targetMultiplicity = oppositeInfo.multiplicity(); |
134 | defaultValue = defaultValue.merge(oppositeInfo.defaultValue()); | ||
167 | if (oppositeInfo.containment()) { | 135 | if (oppositeInfo.containment()) { |
168 | // Skip processing this reference and process it once we encounter its containment opposite. | 136 | // Skip processing this reference and process it once we encounter its containment opposite. |
169 | return; | 137 | return; |
@@ -175,7 +143,7 @@ public class MetamodelBuilder { | |||
175 | targetType, linkType, sourceType)); | 143 | targetType, linkType, sourceType)); |
176 | } | 144 | } |
177 | undirectedCrossReferences.put(linkType, new UndirectedCrossReferenceInfo(sourceType, | 145 | undirectedCrossReferences.put(linkType, new UndirectedCrossReferenceInfo(sourceType, |
178 | info.multiplicity())); | 146 | info.multiplicity(), defaultValue)); |
179 | return; | 147 | return; |
180 | } | 148 | } |
181 | oppositeReferences.put(opposite, linkType); | 149 | oppositeReferences.put(opposite, linkType); |
@@ -185,7 +153,7 @@ public class MetamodelBuilder { | |||
185 | return; | 153 | return; |
186 | } | 154 | } |
187 | directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(), | 155 | directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(), |
188 | targetType, targetMultiplicity)); | 156 | targetType, targetMultiplicity, defaultValue)); |
189 | } | 157 | } |
190 | 158 | ||
191 | private void processContainmentInfo(PartialRelation linkType, ReferenceInfo info, | 159 | private void processContainmentInfo(PartialRelation linkType, ReferenceInfo info, |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java index 9a6b4012..9d7fc9c3 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java | |||
@@ -7,7 +7,11 @@ package tools.refinery.store.reasoning.translator.metamodel; | |||
7 | 7 | ||
8 | import tools.refinery.store.reasoning.representation.PartialRelation; | 8 | import tools.refinery.store.reasoning.representation.PartialRelation; |
9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 9 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
10 | import tools.refinery.store.representation.TruthValue; | ||
10 | 11 | ||
11 | public record ReferenceInfo(boolean containment, PartialRelation sourceType, Multiplicity multiplicity, | 12 | public record ReferenceInfo(boolean containment, PartialRelation sourceType, Multiplicity multiplicity, |
12 | PartialRelation targetType, PartialRelation opposite) { | 13 | PartialRelation targetType, PartialRelation opposite, TruthValue defaultValue) { |
14 | public static ReferenceInfoBuilder builder() { | ||
15 | return new ReferenceInfoBuilder(); | ||
16 | } | ||
13 | } | 17 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfoBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfoBuilder.java new file mode 100644 index 00000000..43d01503 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfoBuilder.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 | */ | ||
6 | package tools.refinery.store.reasoning.translator.metamodel; | ||
7 | |||
8 | import org.jetbrains.annotations.NotNull; | ||
9 | import org.jetbrains.annotations.Nullable; | ||
10 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
11 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | ||
12 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | ||
13 | import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity; | ||
14 | import tools.refinery.store.representation.TruthValue; | ||
15 | import tools.refinery.store.representation.cardinality.CardinalityInterval; | ||
16 | |||
17 | public final class ReferenceInfoBuilder { | ||
18 | private boolean containment; | ||
19 | private PartialRelation sourceType; | ||
20 | private Multiplicity multiplicity = UnconstrainedMultiplicity.INSTANCE; | ||
21 | private PartialRelation targetType; | ||
22 | private PartialRelation opposite; | ||
23 | private TruthValue defaultValue = TruthValue.UNKNOWN; | ||
24 | |||
25 | ReferenceInfoBuilder() { | ||
26 | } | ||
27 | |||
28 | public ReferenceInfoBuilder source(@NotNull PartialRelation sourceType) { | ||
29 | if (sourceType.arity() != 1) { | ||
30 | throw new IllegalArgumentException("Source type %s must be of arity 1".formatted(sourceType)); | ||
31 | } | ||
32 | this.sourceType = sourceType; | ||
33 | return this; | ||
34 | } | ||
35 | |||
36 | public ReferenceInfoBuilder target(@NotNull PartialRelation targetType) { | ||
37 | if (targetType.arity() != 1) { | ||
38 | throw new IllegalArgumentException("Target type %s must be of arity 1".formatted(targetType)); | ||
39 | } | ||
40 | this.targetType = targetType; | ||
41 | return this; | ||
42 | } | ||
43 | |||
44 | public ReferenceInfoBuilder containment(boolean containment) { | ||
45 | this.containment = containment; | ||
46 | return this; | ||
47 | } | ||
48 | |||
49 | public ReferenceInfoBuilder multiplicity(@NotNull Multiplicity multiplicity) { | ||
50 | this.multiplicity = multiplicity; | ||
51 | return this; | ||
52 | } | ||
53 | |||
54 | public ReferenceInfoBuilder multiplicity(@NotNull CardinalityInterval multiplicityInterval, | ||
55 | @NotNull PartialRelation errorSymbol) { | ||
56 | return multiplicity(ConstrainedMultiplicity.of(multiplicityInterval, errorSymbol)); | ||
57 | } | ||
58 | |||
59 | public ReferenceInfoBuilder opposite(@Nullable PartialRelation opposite) { | ||
60 | if (opposite != null && opposite.arity() != 2) { | ||
61 | throw new IllegalArgumentException("Opposite %s must be of arity 2".formatted(targetType)); | ||
62 | } | ||
63 | this.opposite = opposite; | ||
64 | return this; | ||
65 | } | ||
66 | |||
67 | public ReferenceInfoBuilder defaultValue(@NotNull TruthValue defaultValue) { | ||
68 | if (defaultValue.must()) { | ||
69 | throw new IllegalArgumentException("Unsupported default value"); | ||
70 | } | ||
71 | this.defaultValue = defaultValue; | ||
72 | return this; | ||
73 | } | ||
74 | |||
75 | public ReferenceInfo build() { | ||
76 | if (sourceType == null) { | ||
77 | throw new IllegalStateException("Source type is required"); | ||
78 | } | ||
79 | if (targetType == null) { | ||
80 | throw new IllegalStateException("Target type is required"); | ||
81 | } | ||
82 | return new ReferenceInfo(containment, sourceType, multiplicity, targetType, opposite, defaultValue); | ||
83 | } | ||
84 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilderTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilderTest.java index 0f1a1006..ba6ba6da 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilderTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilderTest.java | |||
@@ -8,7 +8,6 @@ package tools.refinery.store.reasoning.translator.metamodel; | |||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.reasoning.representation.PartialRelation; | 9 | import tools.refinery.store.reasoning.representation.PartialRelation; |
10 | import tools.refinery.store.reasoning.translator.TranslationException; | 10 | import tools.refinery.store.reasoning.translator.TranslationException; |
11 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | ||
12 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | 11 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; |
13 | 12 | ||
14 | import static org.junit.jupiter.api.Assertions.assertThrows; | 13 | import static org.junit.jupiter.api.Assertions.assertThrows; |
@@ -24,8 +23,13 @@ class MetamodelBuilderTest { | |||
24 | var builder = Metamodel.builder() | 23 | var builder = Metamodel.builder() |
25 | .type(university) | 24 | .type(university) |
26 | .type(course) | 25 | .type(course) |
27 | .reference(courses, university, course, location) | 26 | .reference(courses, referenceBuilder -> referenceBuilder |
28 | .reference(location, course, university); | 27 | .source(university) |
28 | .target(course) | ||
29 | .opposite(location)) | ||
30 | .reference(location, referenceBuilder -> referenceBuilder | ||
31 | .source(course) | ||
32 | .target(university)); | ||
29 | 33 | ||
30 | assertThrows(TranslationException.class, builder::build); | 34 | assertThrows(TranslationException.class, builder::build); |
31 | } | 35 | } |
@@ -35,8 +39,14 @@ class MetamodelBuilderTest { | |||
35 | var builder = Metamodel.builder() | 39 | var builder = Metamodel.builder() |
36 | .type(university) | 40 | .type(university) |
37 | .type(course) | 41 | .type(course) |
38 | .reference(courses, university, course, location) | 42 | .reference(courses, referenceBuilder -> referenceBuilder |
39 | .reference(location, course, course, courses); | 43 | .source(university) |
44 | .target(course) | ||
45 | .opposite(location)) | ||
46 | .reference(location, referenceBuilder -> referenceBuilder | ||
47 | .source(course) | ||
48 | .target(course) | ||
49 | .opposite(courses)); | ||
40 | 50 | ||
41 | assertThrows(TranslationException.class, builder::build); | 51 | assertThrows(TranslationException.class, builder::build); |
42 | } | 52 | } |
@@ -48,10 +58,16 @@ class MetamodelBuilderTest { | |||
48 | var builder = Metamodel.builder() | 58 | var builder = Metamodel.builder() |
49 | .type(university) | 59 | .type(university) |
50 | .type(course) | 60 | .type(course) |
51 | .reference(courses, university, true, course, location) | 61 | .reference(courses, referenceBuilder -> referenceBuilder |
52 | .reference(location, course, | 62 | .containment(true) |
53 | ConstrainedMultiplicity.of(CardinalityIntervals.atLeast(2), invalidMultiplicity), | 63 | .source(university) |
54 | university, courses); | 64 | .target(course) |
65 | .opposite(location)) | ||
66 | .reference(location, referenceBuilder -> referenceBuilder | ||
67 | .source(course) | ||
68 | .multiplicity(CardinalityIntervals.atLeast(2), invalidMultiplicity) | ||
69 | .target(university) | ||
70 | .opposite(courses)); | ||
55 | 71 | ||
56 | assertThrows(TranslationException.class, builder::build); | 72 | assertThrows(TranslationException.class, builder::build); |
57 | } | 73 | } |
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTest.java index 6c2f55af..88e6a4d7 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTest.java | |||
@@ -16,7 +16,6 @@ import tools.refinery.store.reasoning.representation.PartialRelation; | |||
16 | import tools.refinery.store.reasoning.seed.ModelSeed; | 16 | import tools.refinery.store.reasoning.seed.ModelSeed; |
17 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; | 17 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; |
18 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; | 18 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; |
19 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | ||
20 | import tools.refinery.store.representation.TruthValue; | 19 | import tools.refinery.store.representation.TruthValue; |
21 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | 20 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; |
22 | import tools.refinery.store.tuple.Tuple; | 21 | import tools.refinery.store.tuple.Tuple; |
@@ -45,12 +44,23 @@ class MetamodelTest { | |||
45 | .type(teacher, person) | 44 | .type(teacher, person) |
46 | .type(university) | 45 | .type(university) |
47 | .type(course) | 46 | .type(course) |
48 | .reference(courses, university, true, course, location) | 47 | .reference(courses, builder -> builder |
49 | .reference(location, course, university, courses) | 48 | .containment(true) |
50 | .reference(lecturer, course, | 49 | .source(university) |
51 | ConstrainedMultiplicity.of(CardinalityIntervals.ONE, invalidLecturerCount), teacher) | 50 | .target(course) |
52 | .reference(enrolledStudents, course, | 51 | .opposite(location)) |
53 | ConstrainedMultiplicity.of(CardinalityIntervals.SOME, invalidStudentCount), student) | 52 | .reference(location, builder -> builder |
53 | .source(course) | ||
54 | .target(university) | ||
55 | .opposite(courses)) | ||
56 | .reference(lecturer, builder -> builder | ||
57 | .source(course) | ||
58 | .multiplicity(CardinalityIntervals.ONE, invalidLecturerCount) | ||
59 | .target(teacher)) | ||
60 | .reference(enrolledStudents, builder -> builder | ||
61 | .source(course) | ||
62 | .multiplicity(CardinalityIntervals.SOME, invalidStudentCount) | ||
63 | .target(student)) | ||
54 | .build(); | 64 | .build(); |
55 | 65 | ||
56 | var seed = ModelSeed.builder(5) | 66 | var seed = ModelSeed.builder(5) |
@@ -105,10 +115,12 @@ class MetamodelTest { | |||
105 | var metamodel = Metamodel.builder() | 115 | var metamodel = Metamodel.builder() |
106 | .type(university) | 116 | .type(university) |
107 | .type(course) | 117 | .type(course) |
108 | .reference(courses, university, true, course) | 118 | .reference(courses, builder -> builder |
119 | .containment(true) | ||
120 | .source(university) | ||
121 | .target(course)) | ||
109 | .build(); | 122 | .build(); |
110 | 123 | ||
111 | |||
112 | var seed = ModelSeed.builder(4) | 124 | var seed = ModelSeed.builder(4) |
113 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | 125 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder |
114 | .reducedValue(CardinalityIntervals.ONE) | 126 | .reducedValue(CardinalityIntervals.ONE) |