diff options
Diffstat (limited to 'subprojects/store-reasoning/src/test')
12 files changed, 1776 insertions, 265 deletions
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/PartialModelTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/PartialModelTest.java new file mode 100644 index 00000000..77560a68 --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/PartialModelTest.java | |||
@@ -0,0 +1,108 @@ | |||
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; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.ModelQueryAdapter; | ||
11 | import tools.refinery.store.query.dnf.Query; | ||
12 | import tools.refinery.store.query.term.Variable; | ||
13 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
14 | import tools.refinery.store.query.view.ForbiddenView; | ||
15 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
16 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
17 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
18 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | ||
19 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; | ||
20 | import tools.refinery.store.representation.Symbol; | ||
21 | import tools.refinery.store.representation.TruthValue; | ||
22 | import tools.refinery.store.tuple.Tuple; | ||
23 | |||
24 | import static org.hamcrest.MatcherAssert.assertThat; | ||
25 | import static org.hamcrest.Matchers.is; | ||
26 | import static org.hamcrest.Matchers.not; | ||
27 | import static org.hamcrest.Matchers.nullValue; | ||
28 | import static tools.refinery.store.query.literal.Literals.not; | ||
29 | import static tools.refinery.store.reasoning.ReasoningAdapter.EQUALS_SYMBOL; | ||
30 | import static tools.refinery.store.reasoning.ReasoningAdapter.EXISTS_SYMBOL; | ||
31 | import static tools.refinery.store.reasoning.literal.PartialLiterals.may; | ||
32 | import static tools.refinery.store.reasoning.literal.PartialLiterals.must; | ||
33 | |||
34 | class PartialModelTest { | ||
35 | @Test | ||
36 | void partialModelTest() { | ||
37 | var person = new PartialRelation("Person", 1); | ||
38 | var friend = new PartialRelation("friend", 2); | ||
39 | var lonely = new PartialRelation("lonely", 1); | ||
40 | |||
41 | var personStorage = Symbol.of("Person", 1, TruthValue.class, TruthValue.FALSE); | ||
42 | var friendStorage = Symbol.of("friend", 2, TruthValue.class, TruthValue.UNKNOWN); | ||
43 | |||
44 | var store = ModelStore.builder() | ||
45 | .with(ViatraModelQueryAdapter.builder()) | ||
46 | .with(ReasoningAdapter.builder()) | ||
47 | .with(new MultiObjectTranslator()) | ||
48 | .with(PartialRelationTranslator.of(person) | ||
49 | .symbol(personStorage)) | ||
50 | .with(PartialRelationTranslator.of(friend) | ||
51 | .symbol(friendStorage) | ||
52 | .may(Query.of("mayFriend", (builder, p1, p2) -> builder.clause( | ||
53 | may(person.call(p1)), | ||
54 | may(person.call(p2)), | ||
55 | not(must(EQUALS_SYMBOL.call(p1, p2))), | ||
56 | not(new ForbiddenView(friendStorage).call(p1, p2)) | ||
57 | )))) | ||
58 | .with(PartialRelationTranslator.of(lonely) | ||
59 | .query(Query.of("lonely", (builder, p1) -> builder.clause( | ||
60 | person.call(p1), | ||
61 | not(friend.call(p1, Variable.of()))) | ||
62 | ))) | ||
63 | .build(); | ||
64 | |||
65 | var modelSeed = ModelSeed.builder(4) | ||
66 | .seed(EXISTS_SYMBOL, builder -> builder | ||
67 | .put(Tuple.of(0), TruthValue.TRUE) | ||
68 | .put(Tuple.of(1), TruthValue.UNKNOWN) | ||
69 | .put(Tuple.of(2), TruthValue.TRUE) | ||
70 | .put(Tuple.of(3), TruthValue.TRUE)) | ||
71 | .seed(EQUALS_SYMBOL, builder -> builder | ||
72 | .put(Tuple.of(0, 0), TruthValue.TRUE) | ||
73 | .put(Tuple.of(1, 1), TruthValue.UNKNOWN) | ||
74 | .put(Tuple.of(2, 2), TruthValue.UNKNOWN) | ||
75 | .put(Tuple.of(3, 3), TruthValue.TRUE)) | ||
76 | .seed(person, builder -> builder | ||
77 | .put(Tuple.of(0), TruthValue.TRUE) | ||
78 | .put(Tuple.of(1), TruthValue.TRUE) | ||
79 | .put(Tuple.of(2), TruthValue.UNKNOWN)) | ||
80 | .seed(friend, builder -> builder | ||
81 | .reducedValue(TruthValue.UNKNOWN) | ||
82 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
83 | .put(Tuple.of(1, 2), TruthValue.FALSE)) | ||
84 | .build(); | ||
85 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); | ||
86 | |||
87 | var queryAdapter = model.getAdapter(ModelQueryAdapter.class); | ||
88 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
89 | var friendInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, friend); | ||
90 | var friendRefiner = reasoningAdapter.getRefiner(friend); | ||
91 | |||
92 | assertThat(friendInterpretation.get(Tuple.of(0, 1)), is(TruthValue.TRUE)); | ||
93 | assertThat(friendInterpretation.get(Tuple.of(1, 0)), is(TruthValue.UNKNOWN)); | ||
94 | assertThat(friendInterpretation.get(Tuple.of(3, 0)), is(TruthValue.FALSE)); | ||
95 | |||
96 | assertThat(friendRefiner.merge(Tuple.of(0, 1), TruthValue.FALSE), is(true)); | ||
97 | assertThat(friendRefiner.merge(Tuple.of(1, 0), TruthValue.TRUE), is(true)); | ||
98 | var splitResult = reasoningAdapter.split(1); | ||
99 | assertThat(splitResult, not(nullValue())); | ||
100 | var newPerson = splitResult.get(0); | ||
101 | queryAdapter.flushChanges(); | ||
102 | |||
103 | assertThat(friendInterpretation.get(Tuple.of(0, 1)), is(TruthValue.ERROR)); | ||
104 | assertThat(friendInterpretation.get(Tuple.of(1, 0)), is(TruthValue.TRUE)); | ||
105 | assertThat(friendInterpretation.get(Tuple.of(0, newPerson)), is(TruthValue.ERROR)); | ||
106 | assertThat(friendInterpretation.get(Tuple.of(newPerson, 0)), is(TruthValue.TRUE)); | ||
107 | } | ||
108 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/lifting/DnfLifterTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/lifting/DnfLifterTest.java new file mode 100644 index 00000000..793d1cec --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/lifting/DnfLifterTest.java | |||
@@ -0,0 +1,395 @@ | |||
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.lifting; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.query.dnf.Dnf; | ||
11 | import tools.refinery.store.query.dnf.Query; | ||
12 | import tools.refinery.store.query.term.ParameterDirection; | ||
13 | import tools.refinery.store.query.view.AnySymbolView; | ||
14 | import tools.refinery.store.query.view.FunctionView; | ||
15 | import tools.refinery.store.query.view.MustView; | ||
16 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
17 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
18 | import tools.refinery.store.reasoning.literal.ModalConstraint; | ||
19 | import tools.refinery.store.reasoning.literal.Modality; | ||
20 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
21 | import tools.refinery.store.reasoning.representation.PartialSymbol; | ||
22 | import tools.refinery.store.representation.Symbol; | ||
23 | import tools.refinery.store.representation.TruthValue; | ||
24 | |||
25 | import java.util.List; | ||
26 | |||
27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
28 | import static tools.refinery.store.query.literal.Literals.check; | ||
29 | import static tools.refinery.store.query.literal.Literals.not; | ||
30 | import static tools.refinery.store.query.term.int_.IntTerms.*; | ||
31 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | ||
32 | |||
33 | class DnfLifterTest { | ||
34 | private static final Symbol<TruthValue> friendSymbol = Symbol.of("friend", 2, TruthValue.class, | ||
35 | TruthValue.UNKNOWN); | ||
36 | private static final AnySymbolView friendMustView = new MustView(friendSymbol); | ||
37 | private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class); | ||
38 | private static final FunctionView<Integer> ageView = new FunctionView<>(age); | ||
39 | private static final PartialRelation person = PartialSymbol.of("Person", 1); | ||
40 | private static final PartialRelation friend = PartialSymbol.of("friend", 2); | ||
41 | |||
42 | private DnfLifter sut; | ||
43 | |||
44 | @BeforeEach | ||
45 | void beforeEach() { | ||
46 | sut = new DnfLifter(); | ||
47 | } | ||
48 | |||
49 | @Test | ||
50 | void liftPartialRelationCallTest() { | ||
51 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
52 | friend.call(p1, v1) | ||
53 | ))).getDnf(); | ||
54 | var actual = sut.lift(Modality.MUST, Concreteness.PARTIAL, input); | ||
55 | |||
56 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
57 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, friend).call(p1, v1), | ||
58 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(v1) | ||
59 | ))).getDnf(); | ||
60 | |||
61 | assertThat(actual, structurallyEqualTo(expected)); | ||
62 | } | ||
63 | |||
64 | @Test | ||
65 | void liftPartialDnfCallTest() { | ||
66 | var called = Query.of("Called", (builder, p1, p2) -> builder.clause( | ||
67 | friend.call(p1, p2), | ||
68 | friend.call(p2, p1) | ||
69 | )); | ||
70 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
71 | called.call(p1, v1) | ||
72 | ))).getDnf(); | ||
73 | var actual = sut.lift(Modality.MUST, Concreteness.PARTIAL, input); | ||
74 | |||
75 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
76 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, called.getDnf()).call(p1, v1), | ||
77 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(v1) | ||
78 | ))).getDnf(); | ||
79 | |||
80 | assertThat(actual, structurallyEqualTo(expected)); | ||
81 | } | ||
82 | |||
83 | @Test | ||
84 | void liftSymbolViewCallTest() { | ||
85 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
86 | friendMustView.call(p1, v1) | ||
87 | ))).getDnf(); | ||
88 | var actual = sut.lift(Modality.MUST, Concreteness.PARTIAL, input); | ||
89 | |||
90 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
91 | friendMustView.call(p1, v1), | ||
92 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(v1) | ||
93 | ))).getDnf(); | ||
94 | |||
95 | assertThat(actual, structurallyEqualTo(expected)); | ||
96 | } | ||
97 | |||
98 | @Test | ||
99 | void liftPartialRelationNegativeCallTest() { | ||
100 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
101 | not(friend.call(p1, v1)), | ||
102 | friend.call(v1, p1) | ||
103 | ))).getDnf(); | ||
104 | var actual = sut.lift(Modality.MUST, Concreteness.PARTIAL, input); | ||
105 | |||
106 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
107 | not(ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, v1)), | ||
108 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, friend).call(v1, p1), | ||
109 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(v1) | ||
110 | ))).getDnf(); | ||
111 | |||
112 | assertThat(actual, structurallyEqualTo(expected)); | ||
113 | } | ||
114 | |||
115 | @Test | ||
116 | void liftPartialRelationQuantifiedNegativeCallTest() { | ||
117 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
118 | person.call(p1), | ||
119 | not(friend.call(p1, v1)) | ||
120 | ))).getDnf(); | ||
121 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
122 | |||
123 | var helper = Query.of("Helper", (builder, p1, p2) -> builder.clause( | ||
124 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, friend).call(p1, p2), | ||
125 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
126 | )); | ||
127 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
128 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, person).call(p1), | ||
129 | not(helper.call(p1, v1)) | ||
130 | ))).getDnf(); | ||
131 | |||
132 | assertThat(actual, structurallyEqualTo(expected)); | ||
133 | } | ||
134 | |||
135 | @Test | ||
136 | void liftSymbolViewQuantifiedNegativeCallTest() { | ||
137 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
138 | person.call(p1), | ||
139 | not(friendMustView.call(p1, v1)) | ||
140 | ))).getDnf(); | ||
141 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
142 | |||
143 | var helper = Query.of("Helper", (builder, p1, p2) -> builder.clause( | ||
144 | friendMustView.call(p1, p2), | ||
145 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
146 | )); | ||
147 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
148 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, person).call(p1), | ||
149 | not(helper.call(p1, v1)) | ||
150 | ))).getDnf(); | ||
151 | |||
152 | assertThat(actual, structurallyEqualTo(expected)); | ||
153 | } | ||
154 | |||
155 | @Test | ||
156 | void liftPartialRelationQuantifiedNegativeDiagonalCallTest() { | ||
157 | var input = Query.of("Actual", (builder) -> builder.clause((v1) -> List.of( | ||
158 | not(friend.call(v1, v1)) | ||
159 | ))).getDnf(); | ||
160 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
161 | |||
162 | var helper = Query.of("Helper", (builder, p1) -> builder.clause( | ||
163 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, friend).call(p1, p1), | ||
164 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p1) | ||
165 | )); | ||
166 | var expected = Query.of("Expected", (builder) -> builder.clause((v1) -> List.of( | ||
167 | not(helper.call(v1)) | ||
168 | ))).getDnf(); | ||
169 | |||
170 | assertThat(actual, structurallyEqualTo(expected)); | ||
171 | } | ||
172 | |||
173 | @Test | ||
174 | void liftPartialDnfQuantifiedNegativeInputCallTest() { | ||
175 | var called = Dnf.of("Called", builder -> { | ||
176 | var p1 = builder.parameter("p1", ParameterDirection.IN); | ||
177 | var p2 = builder.parameter("p2", ParameterDirection.OUT); | ||
178 | builder.clause( | ||
179 | friend.call(p1, p2), | ||
180 | friend.call(p2, p1) | ||
181 | ); | ||
182 | }); | ||
183 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
184 | person.call(p1), | ||
185 | not(called.call(p1, v1)) | ||
186 | ))).getDnf(); | ||
187 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
188 | |||
189 | var helper = Dnf.of("Helper", builder -> { | ||
190 | var p1 = builder.parameter("p1", ParameterDirection.IN); | ||
191 | var p2 = builder.parameter("p2", ParameterDirection.OUT); | ||
192 | builder.clause( | ||
193 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, called).call(p1, p2), | ||
194 | ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
195 | ); | ||
196 | }); | ||
197 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
198 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, person).call(p1), | ||
199 | not(helper.call(p1, v1)) | ||
200 | ))).getDnf(); | ||
201 | |||
202 | assertThat(actual, structurallyEqualTo(expected)); | ||
203 | } | ||
204 | |||
205 | @Test | ||
206 | void liftPartialRelationTransitiveCallTest() { | ||
207 | var input = Query.of("Actual", (builder, p1, p2)-> builder.clause( | ||
208 | friend.callTransitive(p1, p2), | ||
209 | not(person.call(p2)) | ||
210 | )).getDnf(); | ||
211 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
212 | |||
213 | var helper = Query.of("Helper", (builder, p1, p2) -> builder.clause( | ||
214 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, p2), | ||
215 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
216 | )); | ||
217 | var helper2 = Query.of("Helper2", (builder, p1, p2) -> { | ||
218 | builder.clause( | ||
219 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, p2) | ||
220 | ); | ||
221 | builder.clause((v1) -> List.of( | ||
222 | helper.callTransitive(p1, v1), | ||
223 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(v1, p2) | ||
224 | )); | ||
225 | }); | ||
226 | var expected = Query.of("Expected", (builder, p1, p2) -> builder.clause( | ||
227 | helper2.call(p1, p2), | ||
228 | not(ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, person).call(p2)) | ||
229 | )).getDnf(); | ||
230 | |||
231 | assertThat(actual, structurallyEqualTo(expected)); | ||
232 | } | ||
233 | |||
234 | @Test | ||
235 | void liftPartialSymbolTransitiveCallTest() { | ||
236 | var input = Query.of("Actual", (builder, p1, p2)-> builder.clause( | ||
237 | friendMustView.callTransitive(p1, p2), | ||
238 | not(person.call(p2)) | ||
239 | )).getDnf(); | ||
240 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
241 | |||
242 | var endExistsHelper = Query.of("EndExistsHelper", (builder, p1, p2) -> builder.clause( | ||
243 | friendMustView.call(p1, p2), | ||
244 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
245 | )); | ||
246 | var transitiveHelper = Query.of("TransitiveHelper", (builder, p1, p2) -> { | ||
247 | builder.clause( | ||
248 | friendMustView.call(p1, p2) | ||
249 | ); | ||
250 | builder.clause((v1) -> List.of( | ||
251 | endExistsHelper.callTransitive(p1, v1), | ||
252 | friendMustView.call(v1, p2) | ||
253 | )); | ||
254 | }); | ||
255 | var expected = Query.of("Expected", (builder, p1, p2) -> builder.clause( | ||
256 | transitiveHelper.call(p1, p2), | ||
257 | not(ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, person).call(p2)) | ||
258 | )).getDnf(); | ||
259 | |||
260 | assertThat(actual, structurallyEqualTo(expected)); | ||
261 | } | ||
262 | |||
263 | @Test | ||
264 | void liftPartialRelationTransitiveCallExistsTest() { | ||
265 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
266 | friend.callTransitive(p1, v1), | ||
267 | not(person.call(v1)) | ||
268 | ))).getDnf(); | ||
269 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
270 | |||
271 | var helper = Query.of("Helper", (builder, p1, p2) -> builder.clause( | ||
272 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, p2), | ||
273 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
274 | )); | ||
275 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
276 | helper.callTransitive(p1, v1), | ||
277 | not(ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, person).call(v1)) | ||
278 | ))).getDnf(); | ||
279 | |||
280 | assertThat(actual, structurallyEqualTo(expected)); | ||
281 | } | ||
282 | |||
283 | @Test | ||
284 | void liftMultipleTransitiveCallExistsTest() { | ||
285 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
286 | friend.callTransitive(p1, v1), | ||
287 | friendMustView.callTransitive(p1, v1), | ||
288 | not(person.call(v1)) | ||
289 | ))).getDnf(); | ||
290 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
291 | |||
292 | var helper = Query.of("Helper", (builder, p1, p2) -> builder.clause( | ||
293 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, p2), | ||
294 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
295 | )); | ||
296 | var helper2 = Query.of("Helper2", (builder, p1, p2) -> builder.clause( | ||
297 | friendMustView.call(p1, p2), | ||
298 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(p2) | ||
299 | )); | ||
300 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
301 | helper.callTransitive(p1, v1), | ||
302 | helper2.callTransitive(p1, v1), | ||
303 | not(ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, person).call(v1)) | ||
304 | ))).getDnf(); | ||
305 | |||
306 | assertThat(actual, structurallyEqualTo(expected)); | ||
307 | } | ||
308 | |||
309 | @Test | ||
310 | void liftEquivalentTest() { | ||
311 | var input = Query.of("Actual", (builder, p1, p2) -> builder.clause( | ||
312 | p1.isEquivalent(p2), | ||
313 | person.call(p1) | ||
314 | )).getDnf(); | ||
315 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
316 | |||
317 | var expected = Query.of("Expected", (builder, p1, p2) -> builder.clause( | ||
318 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, person).call(p1), | ||
319 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EQUALS_SYMBOL).call(p2, p1) | ||
320 | )).getDnf(); | ||
321 | |||
322 | assertThat(actual, structurallyEqualTo(expected)); | ||
323 | } | ||
324 | |||
325 | @Test | ||
326 | void liftNotEquivalentTest() { | ||
327 | var input = Query.of("Actual", (builder, p1, p2) -> builder.clause( | ||
328 | not(p1.isEquivalent(p2)), | ||
329 | friend.call(p1, p2) | ||
330 | )).getDnf(); | ||
331 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
332 | |||
333 | var expected = Query.of("Expected", (builder, p1, p2) -> builder.clause( | ||
334 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(p1, p2), | ||
335 | not(ModalConstraint.of(Modality.MUST, Concreteness.PARTIAL, ReasoningAdapter.EQUALS_SYMBOL).call(p1, p2)) | ||
336 | )).getDnf(); | ||
337 | |||
338 | assertThat(actual, structurallyEqualTo(expected)); | ||
339 | } | ||
340 | |||
341 | @Test | ||
342 | void liftConstantTest() { | ||
343 | var input = Query.of("Actual", (builder, p1) -> builder.clause((v1) -> List.of( | ||
344 | v1.isConstant(0), | ||
345 | friend.call(v1, p1) | ||
346 | ))).getDnf(); | ||
347 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
348 | |||
349 | var expected = Query.of("Expected", (builder, p1) -> builder.clause((v1) -> List.of( | ||
350 | v1.isConstant(0), | ||
351 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, friend).call(v1, p1), | ||
352 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, ReasoningAdapter.EXISTS_SYMBOL).call(v1) | ||
353 | ))).getDnf(); | ||
354 | |||
355 | assertThat(actual, structurallyEqualTo(expected)); | ||
356 | } | ||
357 | |||
358 | @Test | ||
359 | void liftAssignTest() { | ||
360 | var input = Query.of("Actual", Integer.class, (builder, p1, output) -> builder | ||
361 | .clause(Integer.class, (d1) -> List.of( | ||
362 | person.call(p1), | ||
363 | ageView.call(p1, d1), | ||
364 | output.assign(mul(constant(2), d1)) | ||
365 | ))).getDnf(); | ||
366 | var actual = sut.lift(Modality.MAY, Concreteness.PARTIAL, input); | ||
367 | |||
368 | var expected = Query.of("Expected", Integer.class, (builder, p1, output) -> builder | ||
369 | .clause(Integer.class, (d1) -> List.of( | ||
370 | ModalConstraint.of(Modality.MAY, Concreteness.PARTIAL, person).call(p1), | ||
371 | ageView.call(p1, d1), | ||
372 | output.assign(mul(constant(2), d1)) | ||
373 | ))).getDnf(); | ||
374 | |||
375 | assertThat(actual, structurallyEqualTo(expected)); | ||
376 | } | ||
377 | |||
378 | @Test | ||
379 | void liftCheckTest() { | ||
380 | var input = Query.of("Actual", (builder, p1) -> builder.clause(Integer.class, (d1) -> List.of( | ||
381 | person.call(p1), | ||
382 | ageView.call(p1, d1), | ||
383 | check(greaterEq(d1, constant(21))) | ||
384 | ))).getDnf(); | ||
385 | var actual = sut.lift(Modality.MAY, Concreteness.CANDIDATE, input); | ||
386 | |||
387 | var expected = Query.of("Expected", (builder, p1) -> builder.clause(Integer.class, (d1) -> List.of( | ||
388 | ModalConstraint.of(Modality.MAY, Concreteness.CANDIDATE, person).call(p1), | ||
389 | ageView.call(p1, d1), | ||
390 | check(greaterEq(d1, constant(21))) | ||
391 | ))).getDnf(); | ||
392 | |||
393 | assertThat(actual, structurallyEqualTo(expected)); | ||
394 | } | ||
395 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslatorTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslatorTest.java new file mode 100644 index 00000000..bbfaff84 --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslatorTest.java | |||
@@ -0,0 +1,128 @@ | |||
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.containment; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
12 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
13 | import tools.refinery.store.reasoning.ReasoningStoreAdapter; | ||
14 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
15 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
16 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
17 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; | ||
18 | import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity; | ||
19 | import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchy; | ||
20 | import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyTranslator; | ||
21 | import tools.refinery.store.representation.TruthValue; | ||
22 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
23 | import tools.refinery.store.tuple.Tuple; | ||
24 | |||
25 | import java.util.Map; | ||
26 | |||
27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
28 | import static org.hamcrest.Matchers.is; | ||
29 | import static tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator.CONTAINED_SYMBOL; | ||
30 | import static tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator.CONTAINS_SYMBOL; | ||
31 | import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.COUNT_SYMBOL; | ||
32 | |||
33 | class ContainmentHierarchyTranslatorTest { | ||
34 | private final PartialRelation c1 = new PartialRelation("C1", 1); | ||
35 | private final PartialRelation c2 = new PartialRelation("C2", 1); | ||
36 | private final PartialRelation entry = new PartialRelation("entry", 2); | ||
37 | |||
38 | private ModelStore store; | ||
39 | |||
40 | @BeforeEach | ||
41 | void beforeEach() { | ||
42 | |||
43 | var typeHierarchy = TypeHierarchy.builder() | ||
44 | .type(CONTAINED_SYMBOL, true) | ||
45 | .type(c1) | ||
46 | .type(c2, c1, CONTAINED_SYMBOL) | ||
47 | .build(); | ||
48 | |||
49 | var containmentHierarchy = Map.of( | ||
50 | entry, | ||
51 | new ContainmentInfo(c1, UnconstrainedMultiplicity.INSTANCE, c2) | ||
52 | ); | ||
53 | |||
54 | store = ModelStore.builder() | ||
55 | .with(ViatraModelQueryAdapter.builder()) | ||
56 | .with(ReasoningAdapter.builder()) | ||
57 | .with(new MultiObjectTranslator()) | ||
58 | .with(new TypeHierarchyTranslator(typeHierarchy)) | ||
59 | .with(new ContainmentHierarchyTranslator(containmentHierarchy)) | ||
60 | .build(); | ||
61 | } | ||
62 | |||
63 | @Test | ||
64 | void treeTest() { | ||
65 | var modelSeed = ModelSeed.builder(3) | ||
66 | .seed(COUNT_SYMBOL, builder -> builder.reducedValue(CardinalityIntervals.ONE)) | ||
67 | .seed(CONTAINED_SYMBOL, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
68 | .seed(CONTAINS_SYMBOL, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
69 | .seed(c1, builder -> builder | ||
70 | .reducedValue(TruthValue.UNKNOWN) | ||
71 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
72 | .seed(c2, builder -> builder | ||
73 | .put(Tuple.of(1), TruthValue.TRUE) | ||
74 | .put(Tuple.of(2), TruthValue.TRUE)) | ||
75 | .seed(entry, builder -> builder | ||
76 | .reducedValue(TruthValue.UNKNOWN) | ||
77 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
78 | .put(Tuple.of(0, 2), TruthValue.TRUE)) | ||
79 | .build(); | ||
80 | |||
81 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); | ||
82 | var interpretation = model.getAdapter(ReasoningAdapter.class).getPartialInterpretation(Concreteness.PARTIAL, | ||
83 | entry); | ||
84 | |||
85 | assertThat(interpretation.get(Tuple.of(0, 0)), is(TruthValue.FALSE)); | ||
86 | assertThat(interpretation.get(Tuple.of(0, 1)), is(TruthValue.TRUE)); | ||
87 | assertThat(interpretation.get(Tuple.of(0, 2)), is(TruthValue.TRUE)); | ||
88 | assertThat(interpretation.get(Tuple.of(1, 0)), is(TruthValue.FALSE)); | ||
89 | assertThat(interpretation.get(Tuple.of(1, 1)), is(TruthValue.FALSE)); | ||
90 | assertThat(interpretation.get(Tuple.of(1, 2)), is(TruthValue.FALSE)); | ||
91 | assertThat(interpretation.get(Tuple.of(2, 0)), is(TruthValue.FALSE)); | ||
92 | assertThat(interpretation.get(Tuple.of(2, 1)), is(TruthValue.FALSE)); | ||
93 | assertThat(interpretation.get(Tuple.of(2, 2)), is(TruthValue.FALSE)); | ||
94 | } | ||
95 | |||
96 | @Test | ||
97 | void loopTest() { | ||
98 | var modelSeed = ModelSeed.builder(3) | ||
99 | .seed(COUNT_SYMBOL, builder -> builder.reducedValue(CardinalityIntervals.ONE)) | ||
100 | .seed(CONTAINED_SYMBOL, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
101 | .seed(CONTAINS_SYMBOL, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
102 | .seed(c1, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
103 | .seed(c2, builder -> builder | ||
104 | .put(Tuple.of(0), TruthValue.TRUE) | ||
105 | .put(Tuple.of(1), TruthValue.TRUE) | ||
106 | .put(Tuple.of(2), TruthValue.TRUE)) | ||
107 | .seed(entry, builder -> builder | ||
108 | .reducedValue(TruthValue.UNKNOWN) | ||
109 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
110 | .put(Tuple.of(1, 2), TruthValue.TRUE) | ||
111 | .put(Tuple.of(2, 0), TruthValue.TRUE)) | ||
112 | .build(); | ||
113 | |||
114 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); | ||
115 | var interpretation = model.getAdapter(ReasoningAdapter.class).getPartialInterpretation(Concreteness.PARTIAL, | ||
116 | entry); | ||
117 | |||
118 | assertThat(interpretation.get(Tuple.of(0, 0)), is(TruthValue.FALSE)); | ||
119 | assertThat(interpretation.get(Tuple.of(0, 1)), is(TruthValue.ERROR)); | ||
120 | assertThat(interpretation.get(Tuple.of(0, 2)), is(TruthValue.FALSE)); | ||
121 | assertThat(interpretation.get(Tuple.of(1, 0)), is(TruthValue.FALSE)); | ||
122 | assertThat(interpretation.get(Tuple.of(1, 1)), is(TruthValue.FALSE)); | ||
123 | assertThat(interpretation.get(Tuple.of(1, 2)), is(TruthValue.ERROR)); | ||
124 | assertThat(interpretation.get(Tuple.of(2, 0)), is(TruthValue.ERROR)); | ||
125 | assertThat(interpretation.get(Tuple.of(2, 1)), is(TruthValue.FALSE)); | ||
126 | assertThat(interpretation.get(Tuple.of(2, 2)), is(TruthValue.FALSE)); | ||
127 | } | ||
128 | } | ||
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 new file mode 100644 index 00000000..0f1a1006 --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilderTest.java | |||
@@ -0,0 +1,58 @@ | |||
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.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
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; | ||
13 | |||
14 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
15 | |||
16 | class MetamodelBuilderTest { | ||
17 | private final PartialRelation university = new PartialRelation("University", 1); | ||
18 | private final PartialRelation course = new PartialRelation("Course", 1); | ||
19 | private final PartialRelation courses = new PartialRelation("courses", 2); | ||
20 | private final PartialRelation location = new PartialRelation("location", 2); | ||
21 | |||
22 | @Test | ||
23 | void missingOppositeTest() { | ||
24 | var builder = Metamodel.builder() | ||
25 | .type(university) | ||
26 | .type(course) | ||
27 | .reference(courses, university, course, location) | ||
28 | .reference(location, course, university); | ||
29 | |||
30 | assertThrows(TranslationException.class, builder::build); | ||
31 | } | ||
32 | |||
33 | @Test | ||
34 | void invalidOppositeTypeTest() { | ||
35 | var builder = Metamodel.builder() | ||
36 | .type(university) | ||
37 | .type(course) | ||
38 | .reference(courses, university, course, location) | ||
39 | .reference(location, course, course, courses); | ||
40 | |||
41 | assertThrows(TranslationException.class, builder::build); | ||
42 | } | ||
43 | |||
44 | @Test | ||
45 | void invalidOppositeMultiplicityTest() { | ||
46 | var invalidMultiplicity = new PartialRelation("invalidMultiplicity", 1); | ||
47 | |||
48 | var builder = Metamodel.builder() | ||
49 | .type(university) | ||
50 | .type(course) | ||
51 | .reference(courses, university, true, course, location) | ||
52 | .reference(location, course, | ||
53 | ConstrainedMultiplicity.of(CardinalityIntervals.atLeast(2), invalidMultiplicity), | ||
54 | university, courses); | ||
55 | |||
56 | assertThrows(TranslationException.class, builder::build); | ||
57 | } | ||
58 | } | ||
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 new file mode 100644 index 00000000..eabbdffe --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTest.java | |||
@@ -0,0 +1,152 @@ | |||
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.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
12 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
13 | import tools.refinery.store.reasoning.ReasoningStoreAdapter; | ||
14 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
15 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
16 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
17 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; | ||
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; | ||
21 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
22 | import tools.refinery.store.tuple.Tuple; | ||
23 | |||
24 | import static org.hamcrest.MatcherAssert.assertThat; | ||
25 | import static org.hamcrest.Matchers.is; | ||
26 | |||
27 | class MetamodelTest { | ||
28 | private final PartialRelation person = new PartialRelation("Person", 1); | ||
29 | private final PartialRelation student = new PartialRelation("Student", 1); | ||
30 | private final PartialRelation teacher = new PartialRelation("Teacher", 1); | ||
31 | private final PartialRelation university = new PartialRelation("University", 1); | ||
32 | private final PartialRelation course = new PartialRelation("Course", 1); | ||
33 | private final PartialRelation courses = new PartialRelation("courses", 2); | ||
34 | private final PartialRelation location = new PartialRelation("location", 2); | ||
35 | private final PartialRelation lecturer = new PartialRelation("lecturer", 2); | ||
36 | private final PartialRelation invalidLecturerCount = new PartialRelation("invalidLecturerCount", 1); | ||
37 | private final PartialRelation enrolledStudents = new PartialRelation("enrolledStudents", 2); | ||
38 | private final PartialRelation invalidStudentCount = new PartialRelation("invalidStudentCount", 1); | ||
39 | |||
40 | @Test | ||
41 | void metamodelTest() { | ||
42 | var metamodel = Metamodel.builder() | ||
43 | .type(person, true) | ||
44 | .type(student, person) | ||
45 | .type(teacher, person) | ||
46 | .type(university) | ||
47 | .type(course) | ||
48 | .reference(courses, university, true, course, location) | ||
49 | .reference(location, course, university, courses) | ||
50 | .reference(lecturer, course, | ||
51 | ConstrainedMultiplicity.of(CardinalityIntervals.ONE, invalidLecturerCount), teacher) | ||
52 | .reference(enrolledStudents, course, | ||
53 | ConstrainedMultiplicity.of(CardinalityIntervals.SOME, invalidStudentCount), student) | ||
54 | .build(); | ||
55 | |||
56 | var seed = ModelSeed.builder(5) | ||
57 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
58 | .reducedValue(CardinalityIntervals.ONE) | ||
59 | .put(Tuple.of(1), CardinalityIntervals.SET) | ||
60 | .put(Tuple.of(4), CardinalityIntervals.SET)) | ||
61 | .seed(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, builder -> builder | ||
62 | .reducedValue(TruthValue.UNKNOWN)) | ||
63 | .seed(ContainmentHierarchyTranslator.CONTAINS_SYMBOL, builder -> builder | ||
64 | .reducedValue(TruthValue.UNKNOWN)) | ||
65 | .seed(person, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
66 | .seed(student, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
67 | .seed(teacher, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
68 | .seed(university, builder -> builder | ||
69 | .reducedValue(TruthValue.UNKNOWN) | ||
70 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
71 | .seed(course, builder -> builder | ||
72 | .reducedValue(TruthValue.UNKNOWN) | ||
73 | .put(Tuple.of(2), TruthValue.TRUE)) | ||
74 | .seed(courses, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
75 | .seed(location, builder -> builder | ||
76 | .reducedValue(TruthValue.UNKNOWN) | ||
77 | .put(Tuple.of(1, 0), TruthValue.TRUE)) | ||
78 | .seed(lecturer, builder -> builder | ||
79 | .reducedValue(TruthValue.FALSE) | ||
80 | .put(Tuple.of(1, 3), TruthValue.TRUE)) | ||
81 | .seed(enrolledStudents, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
82 | .build(); | ||
83 | |||
84 | var model = createModel(metamodel, seed); | ||
85 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
86 | |||
87 | var coursesInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, courses); | ||
88 | assertThat(coursesInterpretation.get(Tuple.of(0, 1)), is(TruthValue.TRUE)); | ||
89 | assertThat(coursesInterpretation.get(Tuple.of(0, 2)), is(TruthValue.UNKNOWN)); | ||
90 | assertThat(coursesInterpretation.get(Tuple.of(0, 3)), is(TruthValue.FALSE)); | ||
91 | |||
92 | var invalidLecturerCountInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, | ||
93 | invalidLecturerCount); | ||
94 | assertThat(invalidLecturerCountInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
95 | assertThat(invalidLecturerCountInterpretation.get(Tuple.of(2)), is(TruthValue.ERROR)); | ||
96 | |||
97 | var enrolledStudentsInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, | ||
98 | enrolledStudents); | ||
99 | assertThat(enrolledStudentsInterpretation.get(Tuple.of(1, 3)), is(TruthValue.FALSE)); | ||
100 | assertThat(enrolledStudentsInterpretation.get(Tuple.of(1, 4)), is(TruthValue.UNKNOWN)); | ||
101 | } | ||
102 | |||
103 | @Test | ||
104 | void simpleContainmentTest() { | ||
105 | var metamodel = Metamodel.builder() | ||
106 | .type(university) | ||
107 | .type(course) | ||
108 | .reference(courses, university, true, course) | ||
109 | .build(); | ||
110 | |||
111 | |||
112 | var seed = ModelSeed.builder(4) | ||
113 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
114 | .reducedValue(CardinalityIntervals.ONE) | ||
115 | .put(Tuple.of(0), CardinalityIntervals.SET) | ||
116 | .put(Tuple.of(1), CardinalityIntervals.SET)) | ||
117 | .seed(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, builder -> builder | ||
118 | .reducedValue(TruthValue.UNKNOWN)) | ||
119 | .seed(ContainmentHierarchyTranslator.CONTAINS_SYMBOL, builder -> builder | ||
120 | .reducedValue(TruthValue.UNKNOWN)) | ||
121 | .seed(university, builder -> builder | ||
122 | .reducedValue(TruthValue.UNKNOWN) | ||
123 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
124 | .seed(course, builder -> builder | ||
125 | .reducedValue(TruthValue.UNKNOWN) | ||
126 | .put(Tuple.of(1), TruthValue.TRUE)) | ||
127 | .seed(courses, builder -> builder | ||
128 | .reducedValue(TruthValue.UNKNOWN) | ||
129 | .put(Tuple.of(2, 3), TruthValue.TRUE)) | ||
130 | .build(); | ||
131 | |||
132 | var model = createModel(metamodel, seed); | ||
133 | var coursesInterpretation = model.getAdapter(ReasoningAdapter.class) | ||
134 | .getPartialInterpretation(Concreteness.PARTIAL, courses); | ||
135 | |||
136 | assertThat(coursesInterpretation.get(Tuple.of(0, 1)), is(TruthValue.UNKNOWN)); | ||
137 | assertThat(coursesInterpretation.get(Tuple.of(0, 3)), is(TruthValue.FALSE)); | ||
138 | assertThat(coursesInterpretation.get(Tuple.of(2, 1)), is(TruthValue.UNKNOWN)); | ||
139 | assertThat(coursesInterpretation.get(Tuple.of(2, 3)), is(TruthValue.TRUE)); | ||
140 | } | ||
141 | |||
142 | private static Model createModel(Metamodel metamodel, ModelSeed seed) { | ||
143 | var store = ModelStore.builder() | ||
144 | .with(ViatraModelQueryAdapter.builder()) | ||
145 | .with(ReasoningAdapter.builder()) | ||
146 | .with(new MultiObjectTranslator()) | ||
147 | .with(new MetamodelTranslator(metamodel)) | ||
148 | .build(); | ||
149 | |||
150 | return store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
151 | } | ||
152 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java new file mode 100644 index 00000000..64230cf6 --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java | |||
@@ -0,0 +1,321 @@ | |||
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.multiobject; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.ModelQueryAdapter; | ||
11 | import tools.refinery.store.query.dnf.Query; | ||
12 | import tools.refinery.store.query.resultset.ResultSet; | ||
13 | import tools.refinery.store.query.term.Variable; | ||
14 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
15 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
16 | import tools.refinery.store.reasoning.ReasoningStoreAdapter; | ||
17 | import tools.refinery.store.reasoning.literal.CountLowerBoundLiteral; | ||
18 | import tools.refinery.store.reasoning.literal.CountUpperBoundLiteral; | ||
19 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
20 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
21 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | ||
22 | import tools.refinery.store.representation.Symbol; | ||
23 | import tools.refinery.store.representation.TruthValue; | ||
24 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
25 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
26 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
27 | import tools.refinery.store.tuple.Tuple; | ||
28 | |||
29 | import java.util.List; | ||
30 | |||
31 | import static org.hamcrest.MatcherAssert.assertThat; | ||
32 | import static org.hamcrest.Matchers.is; | ||
33 | import static tools.refinery.store.query.literal.Literals.not; | ||
34 | import static tools.refinery.store.reasoning.literal.PartialLiterals.must; | ||
35 | |||
36 | class PartialCountTest { | ||
37 | private static final PartialRelation person = new PartialRelation("Person", 1); | ||
38 | private static final PartialRelation friend = new PartialRelation("friend", 2); | ||
39 | |||
40 | @Test | ||
41 | void lowerBoundZeroTest() { | ||
42 | var query = Query.of("LowerBound", Integer.class, (builder, p1, p2, output) -> builder.clause( | ||
43 | must(person.call(p1)), | ||
44 | must(person.call(p2)), | ||
45 | new CountLowerBoundLiteral(output, friend, List.of(p1, p2)) | ||
46 | )); | ||
47 | |||
48 | var modelSeed = ModelSeed.builder(2) | ||
49 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
50 | .put(Tuple.of(0), CardinalityIntervals.atLeast(3)) | ||
51 | .put(Tuple.of(1), CardinalityIntervals.atMost(7))) | ||
52 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
53 | .seed(friend, builder -> builder | ||
54 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
55 | .put(Tuple.of(1, 0), TruthValue.UNKNOWN) | ||
56 | .put(Tuple.of(1, 1), TruthValue.ERROR)) | ||
57 | .build(); | ||
58 | |||
59 | var resultSet = getResultSet(query, modelSeed); | ||
60 | assertThat(resultSet.get(Tuple.of(0, 0)), is(0)); | ||
61 | assertThat(resultSet.get(Tuple.of(0, 1)), is(1)); | ||
62 | assertThat(resultSet.get(Tuple.of(1, 0)), is(0)); | ||
63 | assertThat(resultSet.get(Tuple.of(1, 1)), is(1)); | ||
64 | } | ||
65 | |||
66 | @Test | ||
67 | void upperBoundZeroTest() { | ||
68 | var query = Query.of("UpperBound", UpperCardinality.class, (builder, p1, p2, output) -> builder.clause( | ||
69 | must(person.call(p1)), | ||
70 | must(person.call(p2)), | ||
71 | new CountUpperBoundLiteral(output, friend, List.of(p1, p2)) | ||
72 | )); | ||
73 | |||
74 | var modelSeed = ModelSeed.builder(2) | ||
75 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
76 | .put(Tuple.of(0), CardinalityIntervals.atLeast(3)) | ||
77 | .put(Tuple.of(1), CardinalityIntervals.atMost(7))) | ||
78 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
79 | .seed(friend, builder -> builder | ||
80 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
81 | .put(Tuple.of(1, 0), TruthValue.UNKNOWN) | ||
82 | .put(Tuple.of(1, 1), TruthValue.ERROR)) | ||
83 | .build(); | ||
84 | |||
85 | var resultSet = getResultSet(query, modelSeed); | ||
86 | assertThat(resultSet.get(Tuple.of(0, 0)), is(UpperCardinalities.ZERO)); | ||
87 | assertThat(resultSet.get(Tuple.of(0, 1)), is(UpperCardinalities.ONE)); | ||
88 | assertThat(resultSet.get(Tuple.of(1, 0)), is(UpperCardinalities.ONE)); | ||
89 | assertThat(resultSet.get(Tuple.of(1, 1)), is(UpperCardinalities.ZERO)); | ||
90 | } | ||
91 | |||
92 | @Test | ||
93 | void lowerBoundOneTest() { | ||
94 | var query = Query.of("LowerBound", Integer.class, (builder, p1, output) -> builder.clause( | ||
95 | must(person.call(p1)), | ||
96 | new CountLowerBoundLiteral(output, friend, List.of(p1, Variable.of())) | ||
97 | )); | ||
98 | |||
99 | var modelSeed = ModelSeed.builder(4) | ||
100 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
101 | .reducedValue(CardinalityIntervals.ONE) | ||
102 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
103 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
104 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
105 | .seed(friend, builder -> builder | ||
106 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
107 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
108 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
109 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
110 | .put(Tuple.of(1, 2), TruthValue.UNKNOWN) | ||
111 | .put(Tuple.of(1, 3), TruthValue.UNKNOWN) | ||
112 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
113 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
114 | .build(); | ||
115 | |||
116 | var resultSet = getResultSet(query, modelSeed); | ||
117 | assertThat(resultSet.get(Tuple.of(0)), is(4)); | ||
118 | assertThat(resultSet.get(Tuple.of(1)), is(1)); | ||
119 | assertThat(resultSet.get(Tuple.of(2)), is(4)); | ||
120 | assertThat(resultSet.get(Tuple.of(3)), is(0)); | ||
121 | } | ||
122 | |||
123 | @Test | ||
124 | void upperBoundOneTest() { | ||
125 | var query = Query.of("UpperBound", UpperCardinality.class, (builder, p1, output) -> builder.clause( | ||
126 | must(person.call(p1)), | ||
127 | new CountUpperBoundLiteral(output, friend, List.of(p1, Variable.of())) | ||
128 | )); | ||
129 | |||
130 | var modelSeed = ModelSeed.builder(4) | ||
131 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
132 | .reducedValue(CardinalityIntervals.ONE) | ||
133 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
134 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
135 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
136 | .seed(friend, builder -> builder | ||
137 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
138 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
139 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
140 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
141 | .put(Tuple.of(1, 2), TruthValue.UNKNOWN) | ||
142 | .put(Tuple.of(1, 3), TruthValue.UNKNOWN) | ||
143 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
144 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
145 | .build(); | ||
146 | |||
147 | var resultSet = getResultSet(query, modelSeed); | ||
148 | assertThat(resultSet.get(Tuple.of(0)), is(UpperCardinalities.UNBOUNDED)); | ||
149 | assertThat(resultSet.get(Tuple.of(1)), is(UpperCardinalities.atMost(9))); | ||
150 | assertThat(resultSet.get(Tuple.of(2)), is(UpperCardinalities.ONE)); | ||
151 | assertThat(resultSet.get(Tuple.of(3)), is(UpperCardinalities.ZERO)); | ||
152 | } | ||
153 | |||
154 | @Test | ||
155 | void lowerBoundTwoTest() { | ||
156 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3) -> builder.clause( | ||
157 | friend.call(p1, p2), | ||
158 | friend.call(p1, p3), | ||
159 | friend.call(p2, p3) | ||
160 | )); | ||
161 | var query = Query.of("LowerBound", Integer.class, (builder, p1, output) -> builder.clause( | ||
162 | must(person.call(p1)), | ||
163 | new CountLowerBoundLiteral(output, subQuery.getDnf(), List.of(p1, Variable.of(), Variable.of())) | ||
164 | )); | ||
165 | |||
166 | var modelSeed = ModelSeed.builder(4) | ||
167 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
168 | .reducedValue(CardinalityIntervals.ONE) | ||
169 | .put(Tuple.of(0), CardinalityIntervals.between(5, 9)) | ||
170 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
171 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
172 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
173 | .seed(friend, builder -> builder | ||
174 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
175 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
176 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
177 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
178 | .put(Tuple.of(1, 2), TruthValue.TRUE) | ||
179 | .put(Tuple.of(1, 3), TruthValue.TRUE) | ||
180 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
181 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
182 | .build(); | ||
183 | |||
184 | var resultSet = getResultSet(query, modelSeed); | ||
185 | assertThat(resultSet.get(Tuple.of(0)), is(3)); | ||
186 | assertThat(resultSet.get(Tuple.of(1)), is(5)); | ||
187 | assertThat(resultSet.get(Tuple.of(2)), is(30)); | ||
188 | assertThat(resultSet.get(Tuple.of(3)), is(0)); | ||
189 | } | ||
190 | |||
191 | @Test | ||
192 | void upperBoundTwoTest() { | ||
193 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3) -> builder.clause( | ||
194 | friend.call(p1, p2), | ||
195 | friend.call(p1, p3), | ||
196 | friend.call(p2, p3) | ||
197 | )); | ||
198 | var query = Query.of("UpperBound", UpperCardinality.class, (builder, p1, output) -> builder.clause( | ||
199 | must(person.call(p1)), | ||
200 | new CountUpperBoundLiteral(output, subQuery.getDnf(), List.of(p1, Variable.of(), Variable.of())) | ||
201 | )); | ||
202 | |||
203 | var modelSeed = ModelSeed.builder(4) | ||
204 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
205 | .reducedValue(CardinalityIntervals.ONE) | ||
206 | .put(Tuple.of(0), CardinalityIntervals.between(5, 9)) | ||
207 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
208 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
209 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
210 | .seed(friend, builder -> builder | ||
211 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
212 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
213 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
214 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
215 | .put(Tuple.of(1, 2), TruthValue.UNKNOWN) | ||
216 | .put(Tuple.of(1, 3), TruthValue.UNKNOWN) | ||
217 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
218 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
219 | .build(); | ||
220 | |||
221 | var resultSet = getResultSet(query, modelSeed); | ||
222 | assertThat(resultSet.get(Tuple.of(0)), is(UpperCardinalities.UNBOUNDED)); | ||
223 | assertThat(resultSet.get(Tuple.of(1)), is(UpperCardinalities.atMost(135))); | ||
224 | assertThat(resultSet.get(Tuple.of(2)), is(UpperCardinalities.ZERO)); | ||
225 | assertThat(resultSet.get(Tuple.of(3)), is(UpperCardinalities.ZERO)); | ||
226 | } | ||
227 | |||
228 | @Test | ||
229 | void lowerBoundDiagonalTest() { | ||
230 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3) -> builder.clause( | ||
231 | friend.call(p1, p2), | ||
232 | friend.call(p1, p3), | ||
233 | not(friend.call(p2, p3)) | ||
234 | )); | ||
235 | var query = Query.of("LowerBound", Integer.class, (builder, p1, output) -> builder.clause(v1 -> List.of( | ||
236 | must(person.call(p1)), | ||
237 | new CountLowerBoundLiteral(output, subQuery.getDnf(), List.of(p1, v1, v1)) | ||
238 | ))); | ||
239 | |||
240 | var modelSeed = ModelSeed.builder(4) | ||
241 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
242 | .reducedValue(CardinalityIntervals.ONE) | ||
243 | .put(Tuple.of(0), CardinalityIntervals.between(5, 9)) | ||
244 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
245 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
246 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
247 | .seed(friend, builder -> builder | ||
248 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
249 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
250 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
251 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
252 | .put(Tuple.of(1, 2), TruthValue.UNKNOWN) | ||
253 | .put(Tuple.of(1, 3), TruthValue.UNKNOWN) | ||
254 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
255 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
256 | .build(); | ||
257 | |||
258 | var resultSet = getResultSet(query, modelSeed); | ||
259 | assertThat(resultSet.get(Tuple.of(0)), is(4)); | ||
260 | assertThat(resultSet.get(Tuple.of(1)), is(5)); | ||
261 | assertThat(resultSet.get(Tuple.of(2)), is(8)); | ||
262 | assertThat(resultSet.get(Tuple.of(3)), is(0)); | ||
263 | } | ||
264 | |||
265 | @Test | ||
266 | void upperBoundDiagonalTest() { | ||
267 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3) -> builder.clause( | ||
268 | friend.call(p1, p2), | ||
269 | friend.call(p1, p3), | ||
270 | not(friend.call(p2, p3)) | ||
271 | )); | ||
272 | var query = Query.of("UpperBound", UpperCardinality.class, (builder, p1, output) -> builder | ||
273 | .clause(v1 -> List.of( | ||
274 | must(person.call(p1)), | ||
275 | new CountUpperBoundLiteral(output, subQuery.getDnf(), List.of(p1, v1, v1)) | ||
276 | ))); | ||
277 | |||
278 | var modelSeed = ModelSeed.builder(4) | ||
279 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
280 | .reducedValue(CardinalityIntervals.ONE) | ||
281 | .put(Tuple.of(0), CardinalityIntervals.between(5, 9)) | ||
282 | .put(Tuple.of(1), CardinalityIntervals.atLeast(3)) | ||
283 | .put(Tuple.of(2), CardinalityIntervals.atMost(7))) | ||
284 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
285 | .seed(friend, builder -> builder | ||
286 | .put(Tuple.of(0, 1), TruthValue.TRUE) | ||
287 | .put(Tuple.of(0, 2), TruthValue.TRUE) | ||
288 | .put(Tuple.of(0, 3), TruthValue.TRUE) | ||
289 | .put(Tuple.of(1, 0), TruthValue.TRUE) | ||
290 | .put(Tuple.of(1, 2), TruthValue.UNKNOWN) | ||
291 | .put(Tuple.of(1, 3), TruthValue.UNKNOWN) | ||
292 | .put(Tuple.of(2, 0), TruthValue.TRUE) | ||
293 | .put(Tuple.of(2, 1), TruthValue.ERROR)) | ||
294 | .build(); | ||
295 | |||
296 | var resultSet = getResultSet(query, modelSeed); | ||
297 | assertThat(resultSet.get(Tuple.of(0)), is(UpperCardinalities.UNBOUNDED)); | ||
298 | assertThat(resultSet.get(Tuple.of(1)), is(UpperCardinalities.atMost(17))); | ||
299 | assertThat(resultSet.get(Tuple.of(2)), is(UpperCardinalities.atMost(9))); | ||
300 | assertThat(resultSet.get(Tuple.of(3)), is(UpperCardinalities.ZERO)); | ||
301 | } | ||
302 | |||
303 | private static <T> ResultSet<T> getResultSet(Query<T> query, ModelSeed modelSeed) { | ||
304 | var personStorage = Symbol.of("Person", 1, TruthValue.class, TruthValue.FALSE); | ||
305 | var friendStorage = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
306 | |||
307 | var store = ModelStore.builder() | ||
308 | .with(ViatraModelQueryAdapter.builder() | ||
309 | .query(query)) | ||
310 | .with(ReasoningAdapter.builder()) | ||
311 | .with(new MultiObjectTranslator()) | ||
312 | .with(PartialRelationTranslator.of(person) | ||
313 | .symbol(personStorage)) | ||
314 | .with(PartialRelationTranslator.of(friend) | ||
315 | .symbol(friendStorage)) | ||
316 | .build(); | ||
317 | |||
318 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); | ||
319 | return model.getAdapter(ModelQueryAdapter.class).getResultSet(query); | ||
320 | } | ||
321 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/ConcreteSupertypeTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/ConcreteSupertypeTest.java new file mode 100644 index 00000000..3658d603 --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/ConcreteSupertypeTest.java | |||
@@ -0,0 +1,145 @@ | |||
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.typehierarchy; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
12 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
13 | import tools.refinery.store.reasoning.ReasoningStoreAdapter; | ||
14 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
15 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
16 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
17 | import tools.refinery.store.representation.TruthValue; | ||
18 | import tools.refinery.store.tuple.Tuple; | ||
19 | |||
20 | import static org.hamcrest.MatcherAssert.assertThat; | ||
21 | import static org.hamcrest.Matchers.is; | ||
22 | |||
23 | class ConcreteSupertypeTest { | ||
24 | private final PartialRelation c1 = new PartialRelation("C1", 1); | ||
25 | private final PartialRelation c2 = new PartialRelation("C2", 1); | ||
26 | |||
27 | private ModelStore store; | ||
28 | |||
29 | @BeforeEach | ||
30 | void beforeEach() { | ||
31 | var typeHierarchy = TypeHierarchy.builder() | ||
32 | .type(c1) | ||
33 | .type(c2, c1) | ||
34 | .build(); | ||
35 | |||
36 | store = ModelStore.builder() | ||
37 | .with(ViatraModelQueryAdapter.builder()) | ||
38 | .with(ReasoningAdapter.builder()) | ||
39 | .with(new TypeHierarchyTranslator(typeHierarchy)) | ||
40 | .build(); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void inheritedTypeTrueTest() { | ||
45 | var seed = ModelSeed.builder(1) | ||
46 | .seed(c1, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
47 | .seed(c2, builder -> builder | ||
48 | .reducedValue(TruthValue.UNKNOWN) | ||
49 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
50 | .build(); | ||
51 | |||
52 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
53 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
54 | |||
55 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
56 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
57 | } | ||
58 | |||
59 | @Test | ||
60 | void inheritedTypeFalseTest() { | ||
61 | var seed = ModelSeed.builder(1) | ||
62 | .seed(c1, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
63 | .seed(c2, builder -> builder | ||
64 | .reducedValue(TruthValue.UNKNOWN) | ||
65 | .put(Tuple.of(0), TruthValue.FALSE)) | ||
66 | .build(); | ||
67 | |||
68 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
69 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
70 | |||
71 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), | ||
72 | is(TruthValue.UNKNOWN)); | ||
73 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
74 | } | ||
75 | |||
76 | @Test | ||
77 | void supertypeTrueTest() { | ||
78 | var seed = ModelSeed.builder(1) | ||
79 | .seed(c1, builder -> builder | ||
80 | .reducedValue(TruthValue.UNKNOWN) | ||
81 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
82 | .seed(c2, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
83 | .build(); | ||
84 | |||
85 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
86 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
87 | |||
88 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
89 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), | ||
90 | is(TruthValue.UNKNOWN)); | ||
91 | } | ||
92 | |||
93 | @Test | ||
94 | void supertypeFalseTest() { | ||
95 | var seed = ModelSeed.builder(1) | ||
96 | .seed(c1, builder -> builder | ||
97 | .reducedValue(TruthValue.UNKNOWN) | ||
98 | .put(Tuple.of(0), TruthValue.FALSE)) | ||
99 | .seed(c2, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
100 | .build(); | ||
101 | |||
102 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
103 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
104 | |||
105 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
106 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
107 | } | ||
108 | |||
109 | @Test | ||
110 | void supertypeOnlyTest() { | ||
111 | var seed = ModelSeed.builder(1) | ||
112 | .seed(c1, builder -> builder | ||
113 | .reducedValue(TruthValue.UNKNOWN) | ||
114 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
115 | .seed(c2, builder -> builder | ||
116 | .reducedValue(TruthValue.UNKNOWN) | ||
117 | .put(Tuple.of(0), TruthValue.FALSE)) | ||
118 | .build(); | ||
119 | |||
120 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
121 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
122 | |||
123 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
124 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
125 | } | ||
126 | |||
127 | |||
128 | @Test | ||
129 | void inheritedTypeErrorTest() { | ||
130 | var seed = ModelSeed.builder(1) | ||
131 | .seed(c1, builder -> builder | ||
132 | .reducedValue(TruthValue.UNKNOWN) | ||
133 | .put(Tuple.of(0), TruthValue.FALSE)) | ||
134 | .seed(c2, builder -> builder | ||
135 | .reducedValue(TruthValue.UNKNOWN) | ||
136 | .put(Tuple.of(0), TruthValue.TRUE)) | ||
137 | .build(); | ||
138 | |||
139 | var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
140 | var adapter = model.getAdapter(ReasoningAdapter.class); | ||
141 | |||
142 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c1).get(Tuple.of(0)), is(TruthValue.ERROR)); | ||
143 | assertThat(adapter.getPartialInterpretation(Concreteness.PARTIAL, c2).get(Tuple.of(0)), is(TruthValue.ERROR)); | ||
144 | } | ||
145 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisExampleHierarchyTest.java index 05a476c6..d9a5477e 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisExampleHierarchyTest.java | |||
@@ -5,19 +5,19 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.translator.typehierarchy; | 6 | package tools.refinery.store.reasoning.translator.typehierarchy; |
7 | 7 | ||
8 | import org.hamcrest.Matchers; | ||
8 | import org.junit.jupiter.api.BeforeEach; | 9 | import org.junit.jupiter.api.BeforeEach; |
9 | import org.junit.jupiter.api.Test; | 10 | import org.junit.jupiter.api.Test; |
10 | import tools.refinery.store.reasoning.representation.PartialRelation; | 11 | import tools.refinery.store.reasoning.representation.PartialRelation; |
11 | import tools.refinery.store.representation.TruthValue; | 12 | import tools.refinery.store.representation.TruthValue; |
12 | 13 | ||
13 | import java.util.LinkedHashMap; | ||
14 | import java.util.Set; | 14 | import java.util.Set; |
15 | 15 | ||
16 | import static org.hamcrest.MatcherAssert.assertThat; | 16 | import static org.hamcrest.MatcherAssert.assertThat; |
17 | import static org.hamcrest.Matchers.is; | 17 | import static org.hamcrest.Matchers.is; |
18 | import static org.junit.jupiter.api.Assertions.assertAll; | 18 | import static org.junit.jupiter.api.Assertions.assertAll; |
19 | 19 | ||
20 | class TypeAnalyzerExampleHierarchyTest { | 20 | class TypeAnalysisExampleHierarchyTest { |
21 | private final PartialRelation a1 = new PartialRelation("A1", 1); | 21 | private final PartialRelation a1 = new PartialRelation("A1", 1); |
22 | private final PartialRelation a2 = new PartialRelation("A2", 1); | 22 | private final PartialRelation a2 = new PartialRelation("A2", 1); |
23 | private final PartialRelation a3 = new PartialRelation("A3", 1); | 23 | private final PartialRelation a3 = new PartialRelation("A3", 1); |
@@ -28,23 +28,23 @@ class TypeAnalyzerExampleHierarchyTest { | |||
28 | private final PartialRelation c3 = new PartialRelation("C3", 1); | 28 | private final PartialRelation c3 = new PartialRelation("C3", 1); |
29 | private final PartialRelation c4 = new PartialRelation("C4", 1); | 29 | private final PartialRelation c4 = new PartialRelation("C4", 1); |
30 | 30 | ||
31 | private TypeAnalyzer sut; | 31 | private TypeHierarchy sut; |
32 | private TypeAnalyzerTester tester; | 32 | private TypeHierarchyTester tester; |
33 | 33 | ||
34 | @BeforeEach | 34 | @BeforeEach |
35 | void beforeEach() { | 35 | void beforeEach() { |
36 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | 36 | sut = TypeHierarchy.builder() |
37 | typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); | 37 | .type(a1, true) |
38 | typeInfoMap.put(a2, TypeInfo.builder().abstractType().build()); | 38 | .type(a2, true) |
39 | typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); | 39 | .type(a3, true) |
40 | typeInfoMap.put(a4, TypeInfo.builder().abstractType().build()); | 40 | .type(a4, true) |
41 | typeInfoMap.put(a5, TypeInfo.builder().abstractType().build()); | 41 | .type(a5, true) |
42 | typeInfoMap.put(c1, TypeInfo.builder().supertypes(a1, a4).build()); | 42 | .type(c1, a1, a4) |
43 | typeInfoMap.put(c2, TypeInfo.builder().supertypes(a1, a2, a3, a4).build()); | 43 | .type(c2, a1, a2, a3, a4) |
44 | typeInfoMap.put(c3, TypeInfo.builder().supertype(a3).build()); | 44 | .type(c3, a3) |
45 | typeInfoMap.put(c4, TypeInfo.builder().supertype(a4).build()); | 45 | .type(c4, a4) |
46 | sut = new TypeAnalyzer(typeInfoMap); | 46 | .build(); |
47 | tester = new TypeAnalyzerTester(sut); | 47 | tester = new TypeHierarchyTester(sut); |
48 | } | 48 | } |
49 | 49 | ||
50 | @Test | 50 | @Test |
@@ -65,16 +65,16 @@ class TypeAnalyzerExampleHierarchyTest { | |||
65 | @Test | 65 | @Test |
66 | void inferredTypesTest() { | 66 | void inferredTypesTest() { |
67 | assertAll( | 67 | assertAll( |
68 | () -> assertThat(sut.getUnknownType(), is(new InferredType(Set.of(), Set.of(c1, c2, c3, c4), null))), | 68 | () -> assertThat(sut.getUnknownType(), Matchers.is(new InferredType(Set.of(), Set.of(c1, c2, c3, c4), null))), |
69 | () -> assertThat(tester.getInferredType(a1), is(new InferredType(Set.of(a1, a4), Set.of(c1, c2), c1))), | 69 | () -> assertThat(tester.getInferredType(a1), Matchers.is(new InferredType(Set.of(a1, a4), Set.of(c1, c2), c1))), |
70 | () -> assertThat(tester.getInferredType(a3), is(new InferredType(Set.of(a3), Set.of(c2, c3), c2))), | 70 | () -> assertThat(tester.getInferredType(a3), Matchers.is(new InferredType(Set.of(a3), Set.of(c2, c3), c2))), |
71 | () -> assertThat(tester.getInferredType(a4), is(new InferredType(Set.of(a4), Set.of(c1, c2, c4), c1))), | 71 | () -> assertThat(tester.getInferredType(a4), Matchers.is(new InferredType(Set.of(a4), Set.of(c1, c2, c4), c1))), |
72 | () -> assertThat(tester.getInferredType(a5), is(new InferredType(Set.of(a5), Set.of(), null))), | 72 | () -> assertThat(tester.getInferredType(a5), Matchers.is(new InferredType(Set.of(a5), Set.of(), null))), |
73 | () -> assertThat(tester.getInferredType(c1), is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), | 73 | () -> assertThat(tester.getInferredType(c1), Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), |
74 | () -> assertThat(tester.getInferredType(c2), | 74 | () -> assertThat(tester.getInferredType(c2), |
75 | is(new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2))), | 75 | Matchers.is(new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2))), |
76 | () -> assertThat(tester.getInferredType(c3), is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), | 76 | () -> assertThat(tester.getInferredType(c3), Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), |
77 | () -> assertThat(tester.getInferredType(c4), is(new InferredType(Set.of(a4, c4), Set.of(c4), c4))) | 77 | () -> assertThat(tester.getInferredType(c4), Matchers.is(new InferredType(Set.of(a4, c4), Set.of(c4), c4))) |
78 | ); | 78 | ); |
79 | } | 79 | } |
80 | 80 | ||
@@ -84,8 +84,8 @@ class TypeAnalyzerExampleHierarchyTest { | |||
84 | var a3Result = tester.getPreservedType(a3); | 84 | var a3Result = tester.getPreservedType(a3); |
85 | var expected = new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2); | 85 | var expected = new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2); |
86 | assertAll( | 86 | assertAll( |
87 | () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.TRUE), is(expected)), | 87 | () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.TRUE), Matchers.is(expected)), |
88 | () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), is(expected)), | 88 | () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), Matchers.is(expected)), |
89 | () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a1Result.asInferredType())), | 89 | () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a1Result.asInferredType())), |
90 | () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a3Result.asInferredType())), | 90 | () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a3Result.asInferredType())), |
91 | () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.TRUE), | 91 | () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.TRUE), |
@@ -100,19 +100,19 @@ class TypeAnalyzerExampleHierarchyTest { | |||
100 | var a4Result = tester.getPreservedType(a4); | 100 | var a4Result = tester.getPreservedType(a4); |
101 | assertAll( | 101 | assertAll( |
102 | () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.FALSE), | 102 | () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.FALSE), |
103 | is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), | 103 | Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), |
104 | () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | 104 | () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.FALSE), |
105 | is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), | 105 | Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), |
106 | () -> assertThat(a4Result.merge(a3Result.asInferredType(), TruthValue.FALSE), | 106 | () -> assertThat(a4Result.merge(a3Result.asInferredType(), TruthValue.FALSE), |
107 | is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), | 107 | Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), |
108 | () -> assertThat(a3Result.merge(a4Result.asInferredType(), TruthValue.FALSE), | 108 | () -> assertThat(a3Result.merge(a4Result.asInferredType(), TruthValue.FALSE), |
109 | is(new InferredType(Set.of(a4), Set.of(c1, c4), c1))), | 109 | Matchers.is(new InferredType(Set.of(a4), Set.of(c1, c4), c1))), |
110 | () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.FALSE), | 110 | () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.FALSE), |
111 | is(new InferredType(Set.of(), Set.of(c3, c4), null))), | 111 | Matchers.is(new InferredType(Set.of(), Set.of(c3, c4), null))), |
112 | () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.FALSE), | 112 | () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.FALSE), |
113 | is(new InferredType(Set.of(), Set.of(c1, c4), null))), | 113 | Matchers.is(new InferredType(Set.of(), Set.of(c1, c4), null))), |
114 | () -> assertThat(a4Result.merge(sut.getUnknownType(), TruthValue.FALSE), | 114 | () -> assertThat(a4Result.merge(sut.getUnknownType(), TruthValue.FALSE), |
115 | is(new InferredType(Set.of(), Set.of(c3), null))) | 115 | Matchers.is(new InferredType(Set.of(), Set.of(c3), null))) |
116 | ); | 116 | ); |
117 | } | 117 | } |
118 | 118 | ||
@@ -122,8 +122,8 @@ class TypeAnalyzerExampleHierarchyTest { | |||
122 | var a4Result = tester.getPreservedType(a4); | 122 | var a4Result = tester.getPreservedType(a4); |
123 | var expected = new InferredType(Set.of(c1, a1, a4), Set.of(), null); | 123 | var expected = new InferredType(Set.of(c1, a1, a4), Set.of(), null); |
124 | assertAll( | 124 | assertAll( |
125 | () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.ERROR), is(expected)), | 125 | () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.ERROR), Matchers.is(expected)), |
126 | () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.ERROR), is(expected)) | 126 | () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.ERROR), Matchers.is(expected)) |
127 | ); | 127 | ); |
128 | } | 128 | } |
129 | 129 | ||
@@ -145,9 +145,9 @@ class TypeAnalyzerExampleHierarchyTest { | |||
145 | var c3Result = tester.getPreservedType(c3); | 145 | var c3Result = tester.getPreservedType(c3); |
146 | assertAll( | 146 | assertAll( |
147 | () -> assertThat(a1Result.merge(c3Result.asInferredType(), TruthValue.TRUE), | 147 | () -> assertThat(a1Result.merge(c3Result.asInferredType(), TruthValue.TRUE), |
148 | is(new InferredType(Set.of(a1, a3, c3), Set.of(), null))), | 148 | Matchers.is(new InferredType(Set.of(a1, a3, c3), Set.of(), null))), |
149 | () -> assertThat(c3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), | 149 | () -> assertThat(c3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), |
150 | is(new InferredType(Set.of(a1, a3, a4, c3), Set.of(), null))) | 150 | Matchers.is(new InferredType(Set.of(a1, a3, a4, c3), Set.of(), null))) |
151 | ); | 151 | ); |
152 | } | 152 | } |
153 | 153 | ||
@@ -158,13 +158,13 @@ class TypeAnalyzerExampleHierarchyTest { | |||
158 | var c1Result = tester.getPreservedType(c1); | 158 | var c1Result = tester.getPreservedType(c1); |
159 | assertAll( | 159 | assertAll( |
160 | () -> assertThat(a4Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | 160 | () -> assertThat(a4Result.merge(a1Result.asInferredType(), TruthValue.FALSE), |
161 | is(new InferredType(Set.of(a1, a4), Set.of(), null))), | 161 | Matchers.is(new InferredType(Set.of(a1, a4), Set.of(), null))), |
162 | () -> assertThat(a1Result.merge(c1Result.asInferredType(), TruthValue.FALSE), | 162 | () -> assertThat(a1Result.merge(c1Result.asInferredType(), TruthValue.FALSE), |
163 | is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), | 163 | Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), |
164 | () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.FALSE), | 164 | () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.FALSE), |
165 | is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), | 165 | Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), |
166 | () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | 166 | () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), |
167 | is(new InferredType(Set.of(a1, a4), Set.of(), null))) | 167 | Matchers.is(new InferredType(Set.of(a1, a4), Set.of(), null))) |
168 | ); | 168 | ); |
169 | } | 169 | } |
170 | 170 | ||
@@ -174,9 +174,9 @@ class TypeAnalyzerExampleHierarchyTest { | |||
174 | var a5Result = tester.getPreservedType(a5); | 174 | var a5Result = tester.getPreservedType(a5); |
175 | assertAll( | 175 | assertAll( |
176 | () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.TRUE), | 176 | () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.TRUE), |
177 | is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), | 177 | Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), |
178 | () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.TRUE), | 178 | () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.TRUE), |
179 | is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))) | 179 | Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))) |
180 | ); | 180 | ); |
181 | } | 181 | } |
182 | 182 | ||
@@ -198,9 +198,9 @@ class TypeAnalyzerExampleHierarchyTest { | |||
198 | var a5Result = tester.getPreservedType(a5); | 198 | var a5Result = tester.getPreservedType(a5); |
199 | assertAll( | 199 | assertAll( |
200 | () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.ERROR), | 200 | () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.ERROR), |
201 | is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), | 201 | Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), |
202 | () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.ERROR), | 202 | () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.ERROR), |
203 | is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), | 203 | Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), |
204 | () -> assertThat(a5Result.merge(a5Result.asInferredType(), TruthValue.ERROR), | 204 | () -> assertThat(a5Result.merge(a5Result.asInferredType(), TruthValue.ERROR), |
205 | is(a5Result.asInferredType())) | 205 | is(a5Result.asInferredType())) |
206 | ); | 206 | ); |
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java deleted file mode 100644 index d0ef9d57..00000000 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.reasoning.translator.typehierarchy; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
10 | import tools.refinery.store.representation.TruthValue; | ||
11 | |||
12 | import java.util.LinkedHashMap; | ||
13 | import java.util.Set; | ||
14 | |||
15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
16 | import static org.hamcrest.Matchers.is; | ||
17 | import static org.junit.jupiter.api.Assertions.assertAll; | ||
18 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
19 | |||
20 | class TypeAnalyzerTest { | ||
21 | @Test | ||
22 | void directSupertypesTest() { | ||
23 | var c1 = new PartialRelation("C1", 1); | ||
24 | var c2 = new PartialRelation("C2", 1); | ||
25 | var c3 = new PartialRelation("C3", 1); | ||
26 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
27 | typeInfoMap.put(c1, TypeInfo.builder().supertypes(c2, c3).build()); | ||
28 | typeInfoMap.put(c2, TypeInfo.builder().supertype(c3).build()); | ||
29 | typeInfoMap.put(c3, TypeInfo.builder().build()); | ||
30 | |||
31 | var sut = new TypeAnalyzer(typeInfoMap); | ||
32 | var tester = new TypeAnalyzerTester(sut); | ||
33 | |||
34 | assertAll( | ||
35 | () -> tester.assertConcreteType(c1), | ||
36 | () -> tester.assertConcreteType(c2, c1), | ||
37 | () -> tester.assertConcreteType(c3, c2) | ||
38 | ); | ||
39 | } | ||
40 | |||
41 | @Test | ||
42 | void typeEliminationAbstractToConcreteTest() { | ||
43 | var c1 = new PartialRelation("C1", 1); | ||
44 | var c2 = new PartialRelation("C2", 1); | ||
45 | var a11 = new PartialRelation("A11", 1); | ||
46 | var a12 = new PartialRelation("A12", 1); | ||
47 | var a21 = new PartialRelation("A21", 1); | ||
48 | var a22 = new PartialRelation("A22", 1); | ||
49 | var a3 = new PartialRelation("A3", 1); | ||
50 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
51 | typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); | ||
52 | typeInfoMap.put(a21, TypeInfo.builder().abstractType().supertype(a3).build()); | ||
53 | typeInfoMap.put(a22, TypeInfo.builder().abstractType().supertype(a3).build()); | ||
54 | typeInfoMap.put(a11, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); | ||
55 | typeInfoMap.put(a12, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); | ||
56 | typeInfoMap.put(c1, TypeInfo.builder().supertypes(a11, a12).build()); | ||
57 | typeInfoMap.put(c2, TypeInfo.builder().supertype(a3).build()); | ||
58 | |||
59 | var sut = new TypeAnalyzer(typeInfoMap); | ||
60 | var tester = new TypeAnalyzerTester(sut); | ||
61 | |||
62 | assertAll( | ||
63 | () -> tester.assertConcreteType(c1), | ||
64 | () -> tester.assertConcreteType(c2), | ||
65 | () -> tester.assertEliminatedType(a11, c1), | ||
66 | () -> tester.assertEliminatedType(a12, c1), | ||
67 | () -> tester.assertEliminatedType(a21, c1), | ||
68 | () -> tester.assertEliminatedType(a22, c1), | ||
69 | () -> tester.assertAbstractType(a3, c1, c2) | ||
70 | ); | ||
71 | } | ||
72 | |||
73 | @Test | ||
74 | void typeEliminationConcreteToAbstractTest() { | ||
75 | var c1 = new PartialRelation("C1", 1); | ||
76 | var c2 = new PartialRelation("C2", 1); | ||
77 | var a11 = new PartialRelation("A11", 1); | ||
78 | var a12 = new PartialRelation("A12", 1); | ||
79 | var a21 = new PartialRelation("A21", 1); | ||
80 | var a22 = new PartialRelation("A22", 1); | ||
81 | var a3 = new PartialRelation("A3", 1); | ||
82 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
83 | typeInfoMap.put(c1, TypeInfo.builder().supertypes(a11, a12).build()); | ||
84 | typeInfoMap.put(c2, TypeInfo.builder().supertype(a3).build()); | ||
85 | typeInfoMap.put(a11, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); | ||
86 | typeInfoMap.put(a12, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); | ||
87 | typeInfoMap.put(a21, TypeInfo.builder().abstractType().supertype(a3).build()); | ||
88 | typeInfoMap.put(a22, TypeInfo.builder().abstractType().supertype(a3).build()); | ||
89 | typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); | ||
90 | |||
91 | var sut = new TypeAnalyzer(typeInfoMap); | ||
92 | var tester = new TypeAnalyzerTester(sut); | ||
93 | |||
94 | assertAll( | ||
95 | () -> tester.assertConcreteType(c1), | ||
96 | () -> tester.assertConcreteType(c2), | ||
97 | () -> tester.assertEliminatedType(a11, c1), | ||
98 | () -> tester.assertEliminatedType(a12, c1), | ||
99 | () -> tester.assertEliminatedType(a21, c1), | ||
100 | () -> tester.assertEliminatedType(a22, c1), | ||
101 | () -> tester.assertAbstractType(a3, c1, c2) | ||
102 | ); | ||
103 | } | ||
104 | |||
105 | @Test | ||
106 | void preserveConcreteTypeTest() { | ||
107 | var c1 = new PartialRelation("C1", 1); | ||
108 | var a1 = new PartialRelation("A1", 1); | ||
109 | var c2 = new PartialRelation("C2", 1); | ||
110 | var a2 = new PartialRelation("A2", 1); | ||
111 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
112 | typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); | ||
113 | typeInfoMap.put(a1, TypeInfo.builder().abstractType().supertype(c2).build()); | ||
114 | typeInfoMap.put(c2, TypeInfo.builder().supertype(a2).build()); | ||
115 | typeInfoMap.put(a2, TypeInfo.builder().abstractType().build()); | ||
116 | |||
117 | var sut = new TypeAnalyzer(typeInfoMap); | ||
118 | var tester = new TypeAnalyzerTester(sut); | ||
119 | |||
120 | assertAll( | ||
121 | () -> tester.assertConcreteType(c1), | ||
122 | () -> tester.assertEliminatedType(a1, c1), | ||
123 | () -> tester.assertConcreteType(c2, c1), | ||
124 | () -> tester.assertEliminatedType(a2, c2) | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | @Test | ||
129 | void mostGeneralCurrentTypeTest() { | ||
130 | var c1 = new PartialRelation("C1", 1); | ||
131 | var c2 = new PartialRelation("C2", 1); | ||
132 | var c3 = new PartialRelation("C3", 1); | ||
133 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
134 | typeInfoMap.put(c1, TypeInfo.builder().supertype(c3).build()); | ||
135 | typeInfoMap.put(c2, TypeInfo.builder().supertype(c3).build()); | ||
136 | typeInfoMap.put(c3, TypeInfo.builder().build()); | ||
137 | |||
138 | var sut = new TypeAnalyzer(typeInfoMap); | ||
139 | var tester = new TypeAnalyzerTester(sut); | ||
140 | var c3Result = tester.getPreservedType(c3); | ||
141 | |||
142 | var expected = new InferredType(Set.of(c3), Set.of(c1, c2, c3), c3); | ||
143 | assertAll( | ||
144 | () -> assertThat(tester.getInferredType(c3), is(expected)), | ||
145 | () -> assertThat(c3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(expected)) | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | @Test | ||
150 | void preferFirstConcreteTypeTest() { | ||
151 | var a1 = new PartialRelation("A1", 1); | ||
152 | var c1 = new PartialRelation("C1", 1); | ||
153 | var c2 = new PartialRelation("C2", 1); | ||
154 | var c3 = new PartialRelation("C3", 1); | ||
155 | var c4 = new PartialRelation("C4", 1); | ||
156 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
157 | typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); | ||
158 | typeInfoMap.put(c2, TypeInfo.builder().supertype(a1).build()); | ||
159 | typeInfoMap.put(c3, TypeInfo.builder().supertype(a1).build()); | ||
160 | typeInfoMap.put(c4, TypeInfo.builder().supertype(c3).build()); | ||
161 | typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); | ||
162 | |||
163 | var sut = new TypeAnalyzer(typeInfoMap); | ||
164 | var tester = new TypeAnalyzerTester(sut); | ||
165 | var c1Result = tester.getPreservedType(c1); | ||
166 | var a1Result = tester.getPreservedType(a1); | ||
167 | |||
168 | assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | ||
169 | is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c2))); | ||
170 | } | ||
171 | |||
172 | @Test | ||
173 | void preferFirstMostGeneralConcreteTypeTest() { | ||
174 | var a1 = new PartialRelation("A1", 1); | ||
175 | var c1 = new PartialRelation("C1", 1); | ||
176 | var c2 = new PartialRelation("C2", 1); | ||
177 | var c3 = new PartialRelation("C3", 1); | ||
178 | var c4 = new PartialRelation("C4", 1); | ||
179 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
180 | typeInfoMap.put(c4, TypeInfo.builder().supertype(c3).build()); | ||
181 | typeInfoMap.put(c3, TypeInfo.builder().supertype(a1).build()); | ||
182 | typeInfoMap.put(c2, TypeInfo.builder().supertype(a1).build()); | ||
183 | typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); | ||
184 | typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); | ||
185 | |||
186 | var sut = new TypeAnalyzer(typeInfoMap); | ||
187 | var tester = new TypeAnalyzerTester(sut); | ||
188 | var c1Result = tester.getPreservedType(c1); | ||
189 | var a1Result = tester.getPreservedType(a1); | ||
190 | |||
191 | assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | ||
192 | is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c3))); | ||
193 | } | ||
194 | |||
195 | @Test | ||
196 | void circularTypeHierarchyTest() { | ||
197 | var c1 = new PartialRelation("C1", 1); | ||
198 | var c2 = new PartialRelation("C2", 1); | ||
199 | var typeInfoMap = new LinkedHashMap<PartialRelation, TypeInfo>(); | ||
200 | typeInfoMap.put(c1, TypeInfo.builder().supertype(c2).build()); | ||
201 | typeInfoMap.put(c2, TypeInfo.builder().supertype(c1).build()); | ||
202 | |||
203 | assertThrows(IllegalArgumentException.class, () -> new TypeAnalyzer(typeInfoMap)); | ||
204 | } | ||
205 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyPartialModelTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyPartialModelTest.java new file mode 100644 index 00000000..cd9df19a --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyPartialModelTest.java | |||
@@ -0,0 +1,186 @@ | |||
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.typehierarchy; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.model.Model; | ||
11 | import tools.refinery.store.model.ModelStore; | ||
12 | import tools.refinery.store.query.ModelQueryAdapter; | ||
13 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | ||
14 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
15 | import tools.refinery.store.reasoning.ReasoningStoreAdapter; | ||
16 | import tools.refinery.store.reasoning.literal.Concreteness; | ||
17 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
18 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
19 | import tools.refinery.store.representation.TruthValue; | ||
20 | import tools.refinery.store.tuple.Tuple; | ||
21 | |||
22 | import static org.hamcrest.MatcherAssert.assertThat; | ||
23 | import static org.hamcrest.Matchers.is; | ||
24 | |||
25 | class TypeHierarchyPartialModelTest { | ||
26 | private final PartialRelation person = new PartialRelation("Person", 1); | ||
27 | private final PartialRelation member = new PartialRelation("Member", 1); | ||
28 | private final PartialRelation student = new PartialRelation("Student", 1); | ||
29 | private final PartialRelation teacher = new PartialRelation("Teacher", 1); | ||
30 | private final PartialRelation pet = new PartialRelation("Pet", 1); | ||
31 | |||
32 | private Model model; | ||
33 | |||
34 | @BeforeEach | ||
35 | void beforeEach() { | ||
36 | var typeHierarchy = TypeHierarchy.builder() | ||
37 | .type(person, true) | ||
38 | .type(member, true, person) | ||
39 | .type(student, member) | ||
40 | .type(teacher, member) | ||
41 | .type(pet) | ||
42 | .build(); | ||
43 | |||
44 | var store = ModelStore.builder() | ||
45 | .with(ViatraModelQueryAdapter.builder()) | ||
46 | .with(ReasoningAdapter.builder()) | ||
47 | .with(new TypeHierarchyTranslator(typeHierarchy)) | ||
48 | .build(); | ||
49 | |||
50 | var seed = ModelSeed.builder(4) | ||
51 | .seed(person, builder -> builder | ||
52 | .reducedValue(TruthValue.UNKNOWN) | ||
53 | .put(Tuple.of(3), TruthValue.FALSE)) | ||
54 | .seed(member, builder -> builder | ||
55 | .reducedValue(TruthValue.UNKNOWN) | ||
56 | .put(Tuple.of(1), TruthValue.TRUE) | ||
57 | .put(Tuple.of(2), TruthValue.TRUE)) | ||
58 | .seed(student, builder -> builder | ||
59 | .reducedValue(TruthValue.UNKNOWN) | ||
60 | .put(Tuple.of(0), TruthValue.TRUE) | ||
61 | .put(Tuple.of(2), TruthValue.FALSE)) | ||
62 | .seed(teacher, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
63 | .seed(pet, builder -> builder.reducedValue(TruthValue.UNKNOWN)) | ||
64 | .build(); | ||
65 | model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(seed); | ||
66 | } | ||
67 | |||
68 | @Test | ||
69 | void initialModelTest() { | ||
70 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
71 | |||
72 | var personInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, person); | ||
73 | assertThat(personInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
74 | assertThat(personInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
75 | assertThat(personInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
76 | assertThat(personInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
77 | |||
78 | var memberInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, member); | ||
79 | assertThat(memberInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
80 | assertThat(memberInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
81 | assertThat(memberInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
82 | assertThat(memberInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
83 | |||
84 | var studentInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, student); | ||
85 | assertThat(studentInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
86 | assertThat(studentInterpretation.get(Tuple.of(1)), is(TruthValue.UNKNOWN)); | ||
87 | assertThat(studentInterpretation.get(Tuple.of(2)), is(TruthValue.FALSE)); | ||
88 | assertThat(studentInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
89 | |||
90 | var teacherInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, teacher); | ||
91 | assertThat(teacherInterpretation.get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
92 | assertThat(teacherInterpretation.get(Tuple.of(1)), is(TruthValue.UNKNOWN)); | ||
93 | assertThat(teacherInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
94 | assertThat(teacherInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
95 | |||
96 | var petInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, pet); | ||
97 | assertThat(petInterpretation.get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
98 | assertThat(petInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
99 | assertThat(petInterpretation.get(Tuple.of(2)), is(TruthValue.FALSE)); | ||
100 | assertThat(petInterpretation.get(Tuple.of(3)), is(TruthValue.UNKNOWN)); | ||
101 | } | ||
102 | |||
103 | @Test | ||
104 | void initialModelCandidateTest() { | ||
105 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
106 | |||
107 | var personCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, person); | ||
108 | assertThat(personCandidateInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
109 | assertThat(personCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
110 | assertThat(personCandidateInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
111 | assertThat(personCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
112 | |||
113 | var memberCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, member); | ||
114 | assertThat(memberCandidateInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
115 | assertThat(memberCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
116 | assertThat(memberCandidateInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
117 | assertThat(memberCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
118 | |||
119 | var studentCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, student); | ||
120 | assertThat(studentCandidateInterpretation.get(Tuple.of(0)), is(TruthValue.TRUE)); | ||
121 | assertThat(studentCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
122 | assertThat(studentCandidateInterpretation.get(Tuple.of(2)), is(TruthValue.FALSE)); | ||
123 | assertThat(studentCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
124 | |||
125 | var teacherCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, teacher); | ||
126 | assertThat(teacherCandidateInterpretation.get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
127 | assertThat(teacherCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
128 | assertThat(teacherCandidateInterpretation.get(Tuple.of(2)), is(TruthValue.TRUE)); | ||
129 | assertThat(teacherCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
130 | |||
131 | var petCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, pet); | ||
132 | assertThat(petCandidateInterpretation.get(Tuple.of(0)), is(TruthValue.FALSE)); | ||
133 | assertThat(petCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
134 | assertThat(petCandidateInterpretation.get(Tuple.of(2)), is(TruthValue.FALSE)); | ||
135 | assertThat(petCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
136 | } | ||
137 | |||
138 | @Test | ||
139 | void refinedModelTest() { | ||
140 | var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); | ||
141 | var studentRefiner = reasoningAdapter.getRefiner(student); | ||
142 | studentRefiner.merge(Tuple.of(1), TruthValue.FALSE); | ||
143 | studentRefiner.merge(Tuple.of(3), TruthValue.TRUE); | ||
144 | model.getAdapter(ModelQueryAdapter.class).flushChanges(); | ||
145 | |||
146 | var personInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, person); | ||
147 | assertThat(personInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
148 | assertThat(personInterpretation.get(Tuple.of(3)), is(TruthValue.ERROR)); | ||
149 | |||
150 | var personCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, person); | ||
151 | assertThat(personCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
152 | assertThat(personCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
153 | |||
154 | var memberInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, member); | ||
155 | assertThat(memberInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
156 | assertThat(memberInterpretation.get(Tuple.of(3)), is(TruthValue.ERROR)); | ||
157 | |||
158 | var memberCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, member); | ||
159 | assertThat(memberCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
160 | assertThat(memberCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
161 | |||
162 | var studentInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, student); | ||
163 | assertThat(studentInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
164 | assertThat(studentInterpretation.get(Tuple.of(3)), is(TruthValue.ERROR)); | ||
165 | |||
166 | var studentCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, student); | ||
167 | assertThat(studentCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
168 | assertThat(studentCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
169 | |||
170 | var teacherInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, teacher); | ||
171 | assertThat(teacherInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
172 | assertThat(teacherInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
173 | |||
174 | var teacherCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, teacher); | ||
175 | assertThat(teacherCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.TRUE)); | ||
176 | assertThat(teacherCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
177 | |||
178 | var petInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.PARTIAL, pet); | ||
179 | assertThat(petInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
180 | assertThat(petInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
181 | |||
182 | var petCandidateInterpretation = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, pet); | ||
183 | assertThat(petCandidateInterpretation.get(Tuple.of(1)), is(TruthValue.FALSE)); | ||
184 | assertThat(petCandidateInterpretation.get(Tuple.of(3)), is(TruthValue.FALSE)); | ||
185 | } | ||
186 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTest.java new file mode 100644 index 00000000..931c62dd --- /dev/null +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTest.java | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.reasoning.translator.typehierarchy; | ||
7 | |||
8 | import org.hamcrest.Matchers; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
11 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
12 | import tools.refinery.store.representation.TruthValue; | ||
13 | |||
14 | import java.util.Set; | ||
15 | |||
16 | import static org.hamcrest.MatcherAssert.assertThat; | ||
17 | import static org.hamcrest.Matchers.hasEntry; | ||
18 | import static org.junit.jupiter.api.Assertions.assertAll; | ||
19 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
20 | |||
21 | class TypeHierarchyTest { | ||
22 | @Test | ||
23 | void directSupertypesTest() { | ||
24 | var c1 = new PartialRelation("C1", 1); | ||
25 | var c2 = new PartialRelation("C2", 1); | ||
26 | var c3 = new PartialRelation("C3", 1); | ||
27 | |||
28 | var sut = TypeHierarchy.builder() | ||
29 | .type(c1, c2, c3) | ||
30 | .type(c2, c3) | ||
31 | .type(c3) | ||
32 | .build(); | ||
33 | var tester = new TypeHierarchyTester(sut); | ||
34 | |||
35 | assertAll( | ||
36 | () -> tester.assertConcreteType(c1), | ||
37 | () -> tester.assertConcreteType(c2, c1), | ||
38 | () -> tester.assertConcreteType(c3, c2) | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | @Test | ||
43 | void typeEliminationAbstractToConcreteTest() { | ||
44 | var c1 = new PartialRelation("C1", 1); | ||
45 | var c2 = new PartialRelation("C2", 1); | ||
46 | var a11 = new PartialRelation("A11", 1); | ||
47 | var a12 = new PartialRelation("A12", 1); | ||
48 | var a21 = new PartialRelation("A21", 1); | ||
49 | var a22 = new PartialRelation("A22", 1); | ||
50 | var a3 = new PartialRelation("A3", 1); | ||
51 | |||
52 | var sut = TypeHierarchy.builder() | ||
53 | .type(a3, true) | ||
54 | .type(a21, true, a3) | ||
55 | .type(a22, true, a3) | ||
56 | .type(a11, true, a21, a22) | ||
57 | .type(a12, true, a21, a22) | ||
58 | .type(c1, a11, a12) | ||
59 | .type(c2, a3) | ||
60 | .build(); | ||
61 | var tester = new TypeHierarchyTester(sut); | ||
62 | |||
63 | assertAll( | ||
64 | () -> tester.assertConcreteType(c1), | ||
65 | () -> tester.assertConcreteType(c2), | ||
66 | () -> tester.assertEliminatedType(a11, c1), | ||
67 | () -> tester.assertEliminatedType(a12, c1), | ||
68 | () -> tester.assertEliminatedType(a21, c1), | ||
69 | () -> tester.assertEliminatedType(a22, c1), | ||
70 | () -> tester.assertAbstractType(a3, c1, c2) | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | @Test | ||
75 | void typeEliminationConcreteToAbstractTest() { | ||
76 | var c1 = new PartialRelation("C1", 1); | ||
77 | var c2 = new PartialRelation("C2", 1); | ||
78 | var a11 = new PartialRelation("A11", 1); | ||
79 | var a12 = new PartialRelation("A12", 1); | ||
80 | var a21 = new PartialRelation("A21", 1); | ||
81 | var a22 = new PartialRelation("A22", 1); | ||
82 | var a3 = new PartialRelation("A3", 1); | ||
83 | |||
84 | var sut = TypeHierarchy.builder() | ||
85 | .type(c1, a11, a12) | ||
86 | .type(c2, a3) | ||
87 | .type(a11, true, a21, a22) | ||
88 | .type(a12, true, a21, a22) | ||
89 | .type(a21, true, a3) | ||
90 | .type(a22, true, a3) | ||
91 | .type(a3, true) | ||
92 | .build(); | ||
93 | var tester = new TypeHierarchyTester(sut); | ||
94 | |||
95 | assertAll( | ||
96 | () -> tester.assertConcreteType(c1), | ||
97 | () -> tester.assertConcreteType(c2), | ||
98 | () -> tester.assertEliminatedType(a11, c1), | ||
99 | () -> tester.assertEliminatedType(a12, c1), | ||
100 | () -> tester.assertEliminatedType(a21, c1), | ||
101 | () -> tester.assertEliminatedType(a22, c1), | ||
102 | () -> tester.assertAbstractType(a3, c1, c2) | ||
103 | ); | ||
104 | } | ||
105 | |||
106 | @Test | ||
107 | void preserveConcreteTypeTest() { | ||
108 | var c1 = new PartialRelation("C1", 1); | ||
109 | var a1 = new PartialRelation("A1", 1); | ||
110 | var c2 = new PartialRelation("C2", 1); | ||
111 | var a2 = new PartialRelation("A2", 1); | ||
112 | |||
113 | var sut = TypeHierarchy.builder() | ||
114 | .type(c1, a1) | ||
115 | .type(a1, true, c2) | ||
116 | .type(c2, a2) | ||
117 | .type(a2, true) | ||
118 | .build(); | ||
119 | var tester = new TypeHierarchyTester(sut); | ||
120 | |||
121 | assertAll( | ||
122 | () -> tester.assertConcreteType(c1), | ||
123 | () -> tester.assertEliminatedType(a1, c1), | ||
124 | () -> tester.assertConcreteType(c2, c1), | ||
125 | () -> tester.assertEliminatedType(a2, c2) | ||
126 | ); | ||
127 | } | ||
128 | |||
129 | @Test | ||
130 | void mostGeneralCurrentTypeTest() { | ||
131 | var c1 = new PartialRelation("C1", 1); | ||
132 | var c2 = new PartialRelation("C2", 1); | ||
133 | var c3 = new PartialRelation("C3", 1); | ||
134 | |||
135 | var sut = TypeHierarchy.builder() | ||
136 | .type(c1, c3) | ||
137 | .type(c2, c3) | ||
138 | .type(c3) | ||
139 | .build(); | ||
140 | var tester = new TypeHierarchyTester(sut); | ||
141 | var c3Result = tester.getPreservedType(c3); | ||
142 | |||
143 | var expected = new InferredType(Set.of(c3), Set.of(c1, c2, c3), c3); | ||
144 | assertAll( | ||
145 | () -> assertThat(tester.getInferredType(c3), Matchers.is(expected)), | ||
146 | () -> assertThat(c3Result.merge(sut.getUnknownType(), TruthValue.TRUE), Matchers.is(expected)) | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | @Test | ||
151 | void preferFirstConcreteTypeTest() { | ||
152 | var a1 = new PartialRelation("A1", 1); | ||
153 | var c1 = new PartialRelation("C1", 1); | ||
154 | var c2 = new PartialRelation("C2", 1); | ||
155 | var c3 = new PartialRelation("C3", 1); | ||
156 | var c4 = new PartialRelation("C4", 1); | ||
157 | |||
158 | var sut = TypeHierarchy.builder() | ||
159 | .type(c1, a1) | ||
160 | .type(c2, a1) | ||
161 | .type(c3, a1) | ||
162 | .type(c4, c3) | ||
163 | .type(a1, true) | ||
164 | .build(); | ||
165 | var tester = new TypeHierarchyTester(sut); | ||
166 | var c1Result = tester.getPreservedType(c1); | ||
167 | var a1Result = tester.getPreservedType(a1); | ||
168 | |||
169 | assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | ||
170 | Matchers.is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c2))); | ||
171 | } | ||
172 | |||
173 | @Test | ||
174 | void preferFirstMostGeneralConcreteTypeTest() { | ||
175 | var a1 = new PartialRelation("A1", 1); | ||
176 | var c1 = new PartialRelation("C1", 1); | ||
177 | var c2 = new PartialRelation("C2", 1); | ||
178 | var c3 = new PartialRelation("C3", 1); | ||
179 | var c4 = new PartialRelation("C4", 1); | ||
180 | |||
181 | var sut = TypeHierarchy.builder() | ||
182 | .type(c4, c3) | ||
183 | .type(c3, a1) | ||
184 | .type(c2, a1) | ||
185 | .type(c1, a1) | ||
186 | .type(a1, true) | ||
187 | .build(); | ||
188 | var tester = new TypeHierarchyTester(sut); | ||
189 | var c1Result = tester.getPreservedType(c1); | ||
190 | var a1Result = tester.getPreservedType(a1); | ||
191 | |||
192 | assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), | ||
193 | Matchers.is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c3))); | ||
194 | } | ||
195 | |||
196 | @Test | ||
197 | void circularTypeHierarchyTest() { | ||
198 | var c1 = new PartialRelation("C1", 1); | ||
199 | var c2 = new PartialRelation("C2", 1); | ||
200 | var builder = TypeHierarchy.builder() | ||
201 | .type(c1, c2) | ||
202 | .type(c2, c1); | ||
203 | |||
204 | assertThrows(TranslationException.class, builder::build); | ||
205 | } | ||
206 | |||
207 | @Test | ||
208 | void chainedEliminationTest() { | ||
209 | var a1 = new PartialRelation("A1", 1); | ||
210 | var a2 = new PartialRelation("A2", 1); | ||
211 | var c1 = new PartialRelation("C1", 1); | ||
212 | |||
213 | var sut = TypeHierarchy.builder() | ||
214 | .type(a1, true) | ||
215 | .type(a2, true, a1) | ||
216 | .type(c1, a2) | ||
217 | .build(); | ||
218 | |||
219 | assertAll( | ||
220 | () -> assertThat(sut.getEliminatedTypes(), hasEntry(a1, c1)), | ||
221 | () -> assertThat(sut.getEliminatedTypes(), hasEntry(a2, c1)) | ||
222 | ); | ||
223 | } | ||
224 | } | ||
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTester.java index 2924816e..647bd782 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTester.java | |||
@@ -11,10 +11,10 @@ import static org.hamcrest.MatcherAssert.assertThat; | |||
11 | import static org.hamcrest.Matchers.*; | 11 | import static org.hamcrest.Matchers.*; |
12 | import static org.hamcrest.Matchers.is; | 12 | import static org.hamcrest.Matchers.is; |
13 | 13 | ||
14 | class TypeAnalyzerTester { | 14 | class TypeHierarchyTester { |
15 | private final TypeAnalyzer sut; | 15 | private final TypeHierarchy sut; |
16 | 16 | ||
17 | public TypeAnalyzerTester(TypeAnalyzer sut) { | 17 | public TypeHierarchyTester(TypeHierarchy sut) { |
18 | this.sut = sut; | 18 | this.sut = sut; |
19 | } | 19 | } |
20 | 20 | ||
@@ -32,22 +32,21 @@ class TypeAnalyzerTester { | |||
32 | 32 | ||
33 | private void assertPreservedType(PartialRelation partialRelation, boolean isAbstract, boolean isVacuous, | 33 | private void assertPreservedType(PartialRelation partialRelation, boolean isAbstract, boolean isVacuous, |
34 | PartialRelation... directSubtypes) { | 34 | PartialRelation... directSubtypes) { |
35 | var result = sut.getAnalysisResults().get(partialRelation); | 35 | var result = sut.getPreservedTypes().get(partialRelation); |
36 | assertThat(result, is(instanceOf(PreservedType.class))); | 36 | assertThat(result, not(nullValue())); |
37 | var preservedResult = (PreservedType) result; | 37 | assertThat(result.isAbstractType(), is(isAbstract)); |
38 | assertThat(preservedResult.isAbstractType(), is(isAbstract)); | 38 | assertThat(result.isVacuous(), is(isVacuous)); |
39 | assertThat(preservedResult.isVacuous(), is(isVacuous)); | 39 | assertThat(result.getDirectSubtypes(), hasItems(directSubtypes)); |
40 | assertThat(preservedResult.getDirectSubtypes(), hasItems(directSubtypes)); | ||
41 | } | 40 | } |
42 | 41 | ||
43 | public void assertEliminatedType(PartialRelation partialRelation, PartialRelation replacement) { | 42 | public void assertEliminatedType(PartialRelation partialRelation, PartialRelation replacement) { |
44 | var result = sut.getAnalysisResults().get(partialRelation); | 43 | var result = sut.getEliminatedTypes().get(partialRelation); |
45 | assertThat(result, is(instanceOf(EliminatedType.class))); | 44 | assertThat(result, not(nullValue())); |
46 | assertThat(((EliminatedType) result).replacement(), is(replacement)); | 45 | assertThat(result, is(replacement)); |
47 | } | 46 | } |
48 | 47 | ||
49 | public PreservedType getPreservedType(PartialRelation partialRelation) { | 48 | public TypeAnalysisResult getPreservedType(PartialRelation partialRelation) { |
50 | return (PreservedType) sut.getAnalysisResults().get(partialRelation); | 49 | return sut.getPreservedTypes().get(partialRelation); |
51 | } | 50 | } |
52 | 51 | ||
53 | public InferredType getInferredType(PartialRelation partialRelation) { | 52 | public InferredType getInferredType(PartialRelation partialRelation) { |