diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-07-02 19:29:31 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-07-02 19:29:31 +0200 |
commit | bcd0b7aee57d4a13b541e8be5a8100e568c81aac (patch) | |
tree | 6ab7391df7f0aca43b8f42be14031e2c8fb555f2 | |
parent | refactor(language): rename definition to computed (diff) | |
download | refinery-bcd0b7aee57d4a13b541e8be5a8100e568c81aac.tar.gz refinery-bcd0b7aee57d4a13b541e8be5a8100e568c81aac.tar.zst refinery-bcd0b7aee57d4a13b541e8be5a8100e568c81aac.zip |
feat(reasoning): lower bound propagationrules
4 files changed, 218 insertions, 52 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 1183d456..c862bc33 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 | |||
@@ -5,14 +5,18 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.translator.containment; | 6 | package tools.refinery.store.reasoning.translator.containment; |
7 | 7 | ||
8 | import tools.refinery.logic.dnf.Dnf; | ||
8 | import tools.refinery.logic.dnf.Query; | 9 | import tools.refinery.logic.dnf.Query; |
9 | import tools.refinery.logic.dnf.RelationalQuery; | 10 | import tools.refinery.logic.dnf.RelationalQuery; |
10 | import tools.refinery.logic.literal.Connectivity; | 11 | import tools.refinery.logic.literal.Connectivity; |
11 | import tools.refinery.logic.literal.Literal; | 12 | import tools.refinery.logic.literal.Literal; |
12 | import tools.refinery.logic.literal.RepresentativeElectionLiteral; | 13 | import tools.refinery.logic.literal.RepresentativeElectionLiteral; |
14 | import tools.refinery.logic.term.ConstantTerm; | ||
13 | import tools.refinery.logic.term.Variable; | 15 | import tools.refinery.logic.term.Variable; |
14 | import tools.refinery.logic.term.cardinalityinterval.CardinalityIntervals; | 16 | import tools.refinery.logic.term.cardinalityinterval.CardinalityIntervals; |
17 | import tools.refinery.logic.term.int_.IntTerms; | ||
15 | import tools.refinery.logic.term.uppercardinality.FiniteUpperCardinality; | 18 | import tools.refinery.logic.term.uppercardinality.FiniteUpperCardinality; |
19 | import tools.refinery.store.dse.propagation.PropagationBuilder; | ||
16 | import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder; | 20 | import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder; |
17 | import tools.refinery.store.dse.transition.Rule; | 21 | import tools.refinery.store.dse.transition.Rule; |
18 | import tools.refinery.store.model.ModelStoreBuilder; | 22 | import tools.refinery.store.model.ModelStoreBuilder; |
@@ -26,6 +30,7 @@ import tools.refinery.store.reasoning.refinement.RefinementBasedInitializer; | |||
26 | import tools.refinery.store.reasoning.representation.PartialRelation; | 30 | import tools.refinery.store.reasoning.representation.PartialRelation; |
27 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | 31 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; |
28 | import tools.refinery.store.reasoning.translator.RoundingMode; | 32 | import tools.refinery.store.reasoning.translator.RoundingMode; |
33 | import tools.refinery.store.reasoning.translator.crossreference.CrossReferenceUtils; | ||
29 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; | 34 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; |
30 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | 35 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; |
31 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; | 36 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; |
@@ -35,10 +40,10 @@ import java.util.ArrayList; | |||
35 | import java.util.List; | 40 | import java.util.List; |
36 | import java.util.Map; | 41 | import java.util.Map; |
37 | 42 | ||
38 | import static tools.refinery.logic.term.int_.IntTerms.constant; | ||
39 | import static tools.refinery.logic.term.int_.IntTerms.less; | ||
40 | import static tools.refinery.logic.literal.Literals.check; | 43 | import static tools.refinery.logic.literal.Literals.check; |
41 | import static tools.refinery.logic.literal.Literals.not; | 44 | import static tools.refinery.logic.literal.Literals.not; |
45 | import static tools.refinery.logic.term.int_.IntTerms.constant; | ||
46 | import static tools.refinery.logic.term.int_.IntTerms.less; | ||
42 | import static tools.refinery.store.reasoning.ReasoningAdapter.EXISTS_SYMBOL; | 47 | import static tools.refinery.store.reasoning.ReasoningAdapter.EXISTS_SYMBOL; |
43 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; | 48 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
44 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.focus; | 49 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.focus; |
@@ -107,6 +112,7 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration { | |||
107 | translateInvalidMultiplicity(storeBuilder, linkType, info); | 112 | translateInvalidMultiplicity(storeBuilder, linkType, info); |
108 | } | 113 | } |
109 | translateFocusNotContained(storeBuilder); | 114 | translateFocusNotContained(storeBuilder); |
115 | storeBuilder.tryGetAdapter(PropagationBuilder.class).ifPresent(this::configurePropagationBuilder); | ||
110 | } | 116 | } |
111 | 117 | ||
112 | private void translateContainmentLinkType(ModelStoreBuilder storeBuilder, PartialRelation linkType, | 118 | private void translateContainmentLinkType(ModelStoreBuilder storeBuilder, PartialRelation linkType, |
@@ -119,10 +125,10 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration { | |||
119 | var mayNewSourceHelper = Query.of(name + "#mayNewSourceHelper", (builder, parent) -> { | 125 | var mayNewSourceHelper = Query.of(name + "#mayNewSourceHelper", (builder, parent) -> { |
120 | var literals = new ArrayList<Literal>(); | 126 | var literals = new ArrayList<Literal>(); |
121 | literals.add(may(sourceType.call(parent))); | 127 | literals.add(may(sourceType.call(parent))); |
122 | if (upperCardinality instanceof FiniteUpperCardinality finiteUpperCardinality) { | 128 | if (upperCardinality instanceof FiniteUpperCardinality(var finiteUpperBound)) { |
123 | var existingCount = Variable.of("existingCount", Integer.class); | 129 | var existingCount = Variable.of("existingCount", Integer.class); |
124 | literals.add(new CountLowerBoundLiteral(existingCount, linkType, List.of(parent, Variable.of()))); | 130 | literals.add(new CountLowerBoundLiteral(existingCount, linkType, List.of(parent, Variable.of()))); |
125 | literals.add(check(less(existingCount, constant(finiteUpperCardinality.finiteUpperBound())))); | 131 | literals.add(check(less(existingCount, constant(finiteUpperBound)))); |
126 | } | 132 | } |
127 | builder.clause(literals); | 133 | builder.clause(literals); |
128 | }); | 134 | }); |
@@ -260,4 +266,55 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration { | |||
260 | focus(multi, Variable.of()) | 266 | focus(multi, Variable.of()) |
261 | ))); | 267 | ))); |
262 | } | 268 | } |
269 | |||
270 | private void configurePropagationBuilder(PropagationBuilder propagationBuilder) { | ||
271 | configureLowerMultiplicityPropagator(propagationBuilder); | ||
272 | configureSingleContainerPropagator(propagationBuilder); | ||
273 | } | ||
274 | |||
275 | private void configureLowerMultiplicityPropagator(PropagationBuilder propagationBuilder) { | ||
276 | for (var entry : containmentInfoMap.entrySet()) { | ||
277 | var info = entry.getValue(); | ||
278 | if (info.multiplicity() instanceof ConstrainedMultiplicity constrainedMultiplicity) { | ||
279 | int lowerBound = constrainedMultiplicity.multiplicity().lowerBound(); | ||
280 | if (lowerBound >= 1) { | ||
281 | var linkType = entry.getKey(); | ||
282 | var sourceType = info.sourceType(); | ||
283 | CrossReferenceUtils.configureSourceLowerBound(linkType, sourceType, lowerBound, | ||
284 | propagationBuilder); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | CrossReferenceUtils.configureTargetLowerBound(CONTAINS_SYMBOL, CONTAINED_SYMBOL, 1, propagationBuilder); | ||
289 | } | ||
290 | |||
291 | private void configureSingleContainerPropagator(PropagationBuilder propagationBuilder) { | ||
292 | var possibleContainment = Dnf.of(CONTAINS_SYMBOL.name() + "#possible", builder -> { | ||
293 | var p1 = builder.parameter("source"); | ||
294 | var p2 = builder.parameter("target"); | ||
295 | var output = builder.parameter("containmentLink", PartialRelation.class); | ||
296 | for (var containmentLink : containmentInfoMap.keySet()) { | ||
297 | builder.clause( | ||
298 | must(CONTAINS_SYMBOL.call(p1, p2)), | ||
299 | may(containmentLink.call(p1, p2)), | ||
300 | output.assign(new ConstantTerm<>(PartialRelation.class, containmentLink)) | ||
301 | ); | ||
302 | } | ||
303 | }); | ||
304 | for (var containmentLink : containmentInfoMap.keySet()) { | ||
305 | propagationBuilder.rule(Rule.of(containmentLink.name() + "#single", (builder, p1, p2) -> builder | ||
306 | .clause(Integer.class, containmentCount -> List.of( | ||
307 | must(CONTAINS_SYMBOL.call(p1, p2)), | ||
308 | may(containmentLink.call(p1, p2)), | ||
309 | not(must(containmentLink.call(p1, p2))), | ||
310 | containmentCount.assign(possibleContainment.count(p1, p2, | ||
311 | Variable.of(PartialRelation.class))), | ||
312 | check(IntTerms.eq(containmentCount, constant(1))) | ||
313 | )) | ||
314 | .action( | ||
315 | add(containmentLink, p1, p2) | ||
316 | ) | ||
317 | )); | ||
318 | } | ||
319 | } | ||
263 | } | 320 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/CrossReferenceUtils.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/CrossReferenceUtils.java index 56c9d682..be9fcb9d 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/CrossReferenceUtils.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/CrossReferenceUtils.java | |||
@@ -12,8 +12,14 @@ import tools.refinery.logic.literal.Literal; | |||
12 | import tools.refinery.logic.term.NodeVariable; | 12 | import tools.refinery.logic.term.NodeVariable; |
13 | import tools.refinery.logic.term.Variable; | 13 | import tools.refinery.logic.term.Variable; |
14 | import tools.refinery.logic.term.uppercardinality.FiniteUpperCardinality; | 14 | import tools.refinery.logic.term.uppercardinality.FiniteUpperCardinality; |
15 | import tools.refinery.logic.term.uppercardinality.UpperCardinalities; | ||
16 | import tools.refinery.logic.term.uppercardinality.UpperCardinality; | ||
17 | import tools.refinery.logic.term.uppercardinality.UpperCardinalityTerms; | ||
18 | import tools.refinery.store.dse.propagation.PropagationBuilder; | ||
19 | import tools.refinery.store.dse.transition.Rule; | ||
15 | import tools.refinery.store.reasoning.literal.CountCandidateLowerBoundLiteral; | 20 | import tools.refinery.store.reasoning.literal.CountCandidateLowerBoundLiteral; |
16 | import tools.refinery.store.reasoning.literal.CountLowerBoundLiteral; | 21 | import tools.refinery.store.reasoning.literal.CountLowerBoundLiteral; |
22 | import tools.refinery.store.reasoning.literal.CountUpperBoundLiteral; | ||
17 | import tools.refinery.store.reasoning.representation.PartialRelation; | 23 | import tools.refinery.store.reasoning.representation.PartialRelation; |
18 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 24 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
19 | 25 | ||
@@ -21,12 +27,15 @@ import java.util.ArrayList; | |||
21 | import java.util.List; | 27 | import java.util.List; |
22 | 28 | ||
23 | import static tools.refinery.logic.literal.Literals.check; | 29 | import static tools.refinery.logic.literal.Literals.check; |
30 | import static tools.refinery.logic.literal.Literals.not; | ||
24 | import static tools.refinery.logic.term.int_.IntTerms.constant; | 31 | import static tools.refinery.logic.term.int_.IntTerms.constant; |
25 | import static tools.refinery.logic.term.int_.IntTerms.less; | 32 | import static tools.refinery.logic.term.int_.IntTerms.less; |
26 | import static tools.refinery.store.reasoning.literal.PartialLiterals.candidateMay; | 33 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
27 | import static tools.refinery.store.reasoning.literal.PartialLiterals.may; | 34 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.remove; |
35 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; | ||
36 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; | ||
28 | 37 | ||
29 | class CrossReferenceUtils { | 38 | public class CrossReferenceUtils { |
30 | private CrossReferenceUtils() { | 39 | private CrossReferenceUtils() { |
31 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | 40 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); |
32 | } | 41 | } |
@@ -77,4 +86,72 @@ class CrossReferenceUtils { | |||
77 | builder.parameter(variable); | 86 | builder.parameter(variable); |
78 | return new PreparedBuilder(builder, variable, arguments); | 87 | return new PreparedBuilder(builder, variable, arguments); |
79 | } | 88 | } |
89 | |||
90 | public static void configureSourceLowerBound(PartialRelation linkType, PartialRelation sourceType, | ||
91 | int lowerBound, PropagationBuilder propagationBuilder) { | ||
92 | var name = linkType.name(); | ||
93 | var lowerBoundCardinality = UpperCardinalities.atMost(lowerBound); | ||
94 | propagationBuilder.rule(Rule.of(name + "#lowerSource", (builder, p1, p2) -> builder | ||
95 | .clause(UpperCardinality.class, upperBound -> List.of( | ||
96 | not(MULTI_VIEW.call(p1)), | ||
97 | must(sourceType.call(p1)), | ||
98 | new CountUpperBoundLiteral(upperBound, linkType, List.of(p1, Variable.of())), | ||
99 | check(UpperCardinalityTerms.lessEq(upperBound, | ||
100 | UpperCardinalityTerms.constant(lowerBoundCardinality))), | ||
101 | may(linkType.call(p1, p2)), | ||
102 | not(must(linkType.call(p1, p2))) | ||
103 | )) | ||
104 | .action( | ||
105 | add(linkType, p1, p2) | ||
106 | ) | ||
107 | )); | ||
108 | propagationBuilder.rule(Rule.of(name + "#missingTarget", (builder, p1) -> builder | ||
109 | .clause(UpperCardinality.class, upperBound -> List.of( | ||
110 | may(sourceType.call(p1)), | ||
111 | // Violation of monotonicity: stop the propagation of inconsistencies, since the | ||
112 | // {@code invalidMultiplicity} pattern will already mark the model as invalid. | ||
113 | not(must(sourceType.call(p1))), | ||
114 | new CountUpperBoundLiteral(upperBound, linkType, List.of(p1, Variable.of())), | ||
115 | check(UpperCardinalityTerms.less(upperBound, | ||
116 | UpperCardinalityTerms.constant(lowerBoundCardinality))) | ||
117 | )) | ||
118 | .action( | ||
119 | remove(sourceType, p1) | ||
120 | ) | ||
121 | )); | ||
122 | } | ||
123 | |||
124 | public static void configureTargetLowerBound(PartialRelation linkType, PartialRelation targetType, | ||
125 | int lowerBound, PropagationBuilder propagationBuilder) { | ||
126 | var name = linkType.name(); | ||
127 | var lowerBoundCardinality = UpperCardinalities.atMost(lowerBound); | ||
128 | propagationBuilder.rule(Rule.of(name + "#lowerTarget", (builder, p1, p2) -> builder | ||
129 | .clause(UpperCardinality.class, upperBound -> List.of( | ||
130 | not(MULTI_VIEW.call(p2)), | ||
131 | must(targetType.call(p2)), | ||
132 | new CountUpperBoundLiteral(upperBound, linkType, List.of(Variable.of(), p2)), | ||
133 | check(UpperCardinalityTerms.lessEq(upperBound, | ||
134 | UpperCardinalityTerms.constant(lowerBoundCardinality))), | ||
135 | may(linkType.call(p1, p2)), | ||
136 | not(must(linkType.call(p1, p2))) | ||
137 | )) | ||
138 | .action( | ||
139 | add(linkType, p1, p2) | ||
140 | ) | ||
141 | )); | ||
142 | propagationBuilder.rule(Rule.of(name + "#missingSource", (builder, p1) -> builder | ||
143 | .clause(UpperCardinality.class, upperBound -> List.of( | ||
144 | may(targetType.call(p1)), | ||
145 | // Violation of monotonicity: stop the propagation of inconsistencies, since the | ||
146 | // {@code invalidMultiplicity} pattern will already mark the model as invalid. | ||
147 | not(must(targetType.call(p1))), | ||
148 | new CountUpperBoundLiteral(upperBound, linkType, List.of(Variable.of(), p1)), | ||
149 | check(UpperCardinalityTerms.less(upperBound, | ||
150 | UpperCardinalityTerms.constant(lowerBoundCardinality))) | ||
151 | )) | ||
152 | .action( | ||
153 | remove(targetType, p1) | ||
154 | ) | ||
155 | )); | ||
156 | } | ||
80 | } | 157 | } |
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 1985a43f..2facb56d 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 | |||
@@ -20,13 +20,14 @@ import tools.refinery.store.reasoning.representation.PartialRelation; | |||
20 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | 20 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; |
21 | import tools.refinery.store.reasoning.translator.RoundingMode; | 21 | import tools.refinery.store.reasoning.translator.RoundingMode; |
22 | import tools.refinery.store.reasoning.translator.TranslationException; | 22 | import tools.refinery.store.reasoning.translator.TranslationException; |
23 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | ||
23 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; | 24 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; |
24 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | 25 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; |
25 | import tools.refinery.store.representation.Symbol; | 26 | import tools.refinery.store.representation.Symbol; |
26 | 27 | ||
27 | import static tools.refinery.logic.literal.Literals.not; | 28 | import static tools.refinery.logic.literal.Literals.not; |
28 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; | 29 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
29 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.merge; | 30 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.remove; |
30 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; | 31 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; |
31 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; | 32 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; |
32 | 33 | ||
@@ -78,6 +79,7 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration | |||
78 | info.sourceMultiplicity())); | 79 | info.sourceMultiplicity())); |
79 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(targetType, linkType, true, | 80 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(targetType, linkType, true, |
80 | info.targetMultiplicity())); | 81 | info.targetMultiplicity())); |
82 | storeBuilder.tryGetAdapter(PropagationBuilder.class).ifPresent(this::configureLowerMultiplicityPropagator); | ||
81 | } | 83 | } |
82 | 84 | ||
83 | private void configureWithDefaultUnknown(PartialRelationTranslator translator) { | 85 | private void configureWithDefaultUnknown(PartialRelationTranslator translator) { |
@@ -135,7 +137,8 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration | |||
135 | return CrossReferenceUtils.createMayHelper(linkType, type, multiplicity, inverse); | 137 | return CrossReferenceUtils.createMayHelper(linkType, type, multiplicity, inverse); |
136 | } | 138 | } |
137 | 139 | ||
138 | private RelationalQuery createCandidateMayHelper(PartialRelation type, Multiplicity multiplicity, boolean inverse) { | 140 | private RelationalQuery createCandidateMayHelper(PartialRelation type, Multiplicity multiplicity, |
141 | boolean inverse) { | ||
139 | return CrossReferenceUtils.createCandidateMayHelper(linkType, type, multiplicity, inverse); | 142 | return CrossReferenceUtils.createCandidateMayHelper(linkType, type, multiplicity, inverse); |
140 | } | 143 | } |
141 | 144 | ||
@@ -145,32 +148,48 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration | |||
145 | var targetType = info.targetType(); | 148 | var targetType = info.targetType(); |
146 | var mayNewSource = createMayHelper(sourceType, info.sourceMultiplicity(), false); | 149 | var mayNewSource = createMayHelper(sourceType, info.sourceMultiplicity(), false); |
147 | var mayNewTarget = createMayHelper(targetType, info.targetMultiplicity(), true); | 150 | var mayNewTarget = createMayHelper(targetType, info.targetMultiplicity(), true); |
148 | var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class); | 151 | storeBuilder.tryGetAdapter(PropagationBuilder.class).ifPresent(propagationBuilder -> propagationBuilder |
149 | propagationBuilder.rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { | 152 | .rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { |
150 | builder.clause( | 153 | builder.clause( |
151 | may(linkType.call(p1, p2)), | 154 | may(linkType.call(p1, p2)), |
152 | not(may(sourceType.call(p1))) | 155 | not(may(sourceType.call(p1))) |
153 | ); | 156 | ); |
154 | builder.clause( | 157 | builder.clause( |
155 | may(linkType.call(p1, p2)), | 158 | may(linkType.call(p1, p2)), |
156 | not(may(targetType.call(p2))) | 159 | not(may(targetType.call(p2))) |
157 | ); | 160 | ); |
158 | if (info.isConstrained()) { | 161 | if (info.isConstrained()) { |
159 | builder.clause( | 162 | builder.clause( |
160 | may(linkType.call(p1, p2)), | 163 | may(linkType.call(p1, p2)), |
161 | not(must(linkType.call(p1, p2))), | 164 | not(must(linkType.call(p1, p2))), |
162 | not(mayNewSource.call(p1)) | 165 | not(mayNewSource.call(p1)) |
163 | ); | 166 | ); |
164 | builder.clause( | 167 | builder.clause( |
165 | may(linkType.call(p1, p2)), | 168 | may(linkType.call(p1, p2)), |
166 | not(must(linkType.call(p1, p2))), | 169 | not(must(linkType.call(p1, p2))), |
167 | not(mayNewTarget.call(p2)) | 170 | not(mayNewTarget.call(p2)) |
168 | ); | 171 | ); |
169 | } | 172 | } |
170 | builder.action( | 173 | builder.action( |
171 | merge(linkType, TruthValue.FALSE, p1, p2) | 174 | remove(linkType, p1, p2) |
172 | ); | 175 | ); |
173 | })); | 176 | }))); |
174 | } | 177 | } |
175 | 178 | ||
179 | private void configureLowerMultiplicityPropagator(PropagationBuilder propagationBuilder) { | ||
180 | if (info.sourceMultiplicity() instanceof ConstrainedMultiplicity constrainedMultiplicity) { | ||
181 | int lowerBound = constrainedMultiplicity.multiplicity().lowerBound(); | ||
182 | if (lowerBound >= 1) { | ||
183 | var sourceType = info.sourceType(); | ||
184 | CrossReferenceUtils.configureSourceLowerBound(linkType, sourceType, lowerBound, propagationBuilder); | ||
185 | } | ||
186 | } | ||
187 | if (info.targetMultiplicity() instanceof ConstrainedMultiplicity constrainedMultiplicity) { | ||
188 | int lowerBound = constrainedMultiplicity.multiplicity().lowerBound(); | ||
189 | if (lowerBound >= 1) { | ||
190 | var targetType = info.targetType(); | ||
191 | CrossReferenceUtils.configureTargetLowerBound(linkType, targetType, lowerBound, propagationBuilder); | ||
192 | } | ||
193 | } | ||
194 | } | ||
176 | } | 195 | } |
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 af0ddd2e..0a718033 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 | |||
@@ -19,12 +19,13 @@ 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.RoundingMode; | 20 | import tools.refinery.store.reasoning.translator.RoundingMode; |
21 | import tools.refinery.store.reasoning.translator.TranslationException; | 21 | import tools.refinery.store.reasoning.translator.TranslationException; |
22 | import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; | ||
22 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; | 23 | import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; |
23 | import tools.refinery.store.representation.Symbol; | 24 | import tools.refinery.store.representation.Symbol; |
24 | 25 | ||
25 | import static tools.refinery.logic.literal.Literals.not; | 26 | import static tools.refinery.logic.literal.Literals.not; |
26 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; | 27 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; |
27 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.merge; | 28 | import static tools.refinery.store.reasoning.actions.PartialActionLiterals.remove; |
28 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; | 29 | import static tools.refinery.store.reasoning.literal.PartialLiterals.*; |
29 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; | 30 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; |
30 | 31 | ||
@@ -72,6 +73,7 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati | |||
72 | } | 73 | } |
73 | storeBuilder.with(translator); | 74 | storeBuilder.with(translator); |
74 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity())); | 75 | storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity())); |
76 | storeBuilder.tryGetAdapter(PropagationBuilder.class).ifPresent(this::configureLowerMultiplicityPropagator); | ||
75 | } | 77 | } |
76 | 78 | ||
77 | private void configureWithDefaultUnknown(PartialRelationTranslator translator) { | 79 | private void configureWithDefaultUnknown(PartialRelationTranslator translator) { |
@@ -125,22 +127,33 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati | |||
125 | var name = linkType.name(); | 127 | var name = linkType.name(); |
126 | var type = info.type(); | 128 | var type = info.type(); |
127 | var mayNewSource = CrossReferenceUtils.createMayHelper(linkType, type, info.multiplicity(), false); | 129 | var mayNewSource = CrossReferenceUtils.createMayHelper(linkType, type, info.multiplicity(), false); |
128 | var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class); | 130 | storeBuilder.tryGetAdapter(PropagationBuilder.class).ifPresent(propagationBuilder -> propagationBuilder |
129 | propagationBuilder.rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { | 131 | .rule(Rule.of(name + "#invalidLink", (builder, p1, p2) -> { |
130 | builder.clause( | 132 | builder.clause( |
131 | may(linkType.call(p1, p2)), | 133 | may(linkType.call(p1, p2)), |
132 | not(may(type.call(p1))) | 134 | not(may(type.call(p1))) |
133 | ); | 135 | ); |
134 | if (info.isConstrained()) { | 136 | if (info.isConstrained()) { |
135 | builder.clause( | 137 | builder.clause( |
136 | may(linkType.call(p1, p2)), | 138 | may(linkType.call(p1, p2)), |
137 | not(must(linkType.call(p1, p2))), | 139 | not(must(linkType.call(p1, p2))), |
138 | not(mayNewSource.call(p1)) | 140 | not(mayNewSource.call(p1)) |
139 | ); | 141 | ); |
142 | } | ||
143 | builder.action( | ||
144 | remove(linkType, p1, p2) | ||
145 | ); | ||
146 | }))); | ||
147 | } | ||
148 | |||
149 | private void configureLowerMultiplicityPropagator(PropagationBuilder propagationBuilder) { | ||
150 | var name = linkType.name(); | ||
151 | if (info.multiplicity() instanceof ConstrainedMultiplicity constrainedMultiplicity) { | ||
152 | int lowerBound = constrainedMultiplicity.multiplicity().lowerBound(); | ||
153 | if (lowerBound >= 1) { | ||
154 | var type = info.type(); | ||
155 | CrossReferenceUtils.configureSourceLowerBound(linkType, type, lowerBound, propagationBuilder); | ||
140 | } | 156 | } |
141 | builder.action( | 157 | } |
142 | merge(linkType, TruthValue.FALSE, p1, p2) | ||
143 | ); | ||
144 | })); | ||
145 | } | 158 | } |
146 | } | 159 | } |