aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java')
-rw-r--r--subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/multiobject/PartialCountTest.java321
1 files changed, 321 insertions, 0 deletions
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 */
6package tools.refinery.store.reasoning.translator.multiobject;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.Query;
12import tools.refinery.store.query.resultset.ResultSet;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.viatra.ViatraModelQueryAdapter;
15import tools.refinery.store.reasoning.ReasoningAdapter;
16import tools.refinery.store.reasoning.ReasoningStoreAdapter;
17import tools.refinery.store.reasoning.literal.CountLowerBoundLiteral;
18import tools.refinery.store.reasoning.literal.CountUpperBoundLiteral;
19import tools.refinery.store.reasoning.representation.PartialRelation;
20import tools.refinery.store.reasoning.seed.ModelSeed;
21import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
22import tools.refinery.store.representation.Symbol;
23import tools.refinery.store.representation.TruthValue;
24import tools.refinery.store.representation.cardinality.CardinalityIntervals;
25import tools.refinery.store.representation.cardinality.UpperCardinalities;
26import tools.refinery.store.representation.cardinality.UpperCardinality;
27import tools.refinery.store.tuple.Tuple;
28
29import java.util.List;
30
31import static org.hamcrest.MatcherAssert.assertThat;
32import static org.hamcrest.Matchers.is;
33import static tools.refinery.store.query.literal.Literals.not;
34import static tools.refinery.store.reasoning.literal.PartialLiterals.must;
35
36class 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}