diff options
Diffstat (limited to 'subprojects/store-reasoning-scope/src/test/java')
3 files changed, 327 insertions, 0 deletions
diff --git a/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MPSolverTest.java b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MPSolverTest.java new file mode 100644 index 00000000..c9745d22 --- /dev/null +++ b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MPSolverTest.java | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.reasoning.scope; | ||
7 | |||
8 | import com.google.ortools.Loader; | ||
9 | import com.google.ortools.linearsolver.MPSolver; | ||
10 | import org.junit.jupiter.api.BeforeAll; | ||
11 | import org.junit.jupiter.api.Test; | ||
12 | |||
13 | import static org.hamcrest.MatcherAssert.assertThat; | ||
14 | import static org.hamcrest.Matchers.closeTo; | ||
15 | import static org.hamcrest.Matchers.is; | ||
16 | |||
17 | class MPSolverTest { | ||
18 | @BeforeAll | ||
19 | static void beforeAll() { | ||
20 | Loader.loadNativeLibraries(); | ||
21 | } | ||
22 | |||
23 | @Test | ||
24 | void updateProblemTest() { | ||
25 | var solver = MPSolver.createSolver("GLOP"); | ||
26 | var x = solver.makeNumVar(0, Double.POSITIVE_INFINITY, "x"); | ||
27 | var y = solver.makeNumVar(0, 1, "y"); | ||
28 | var constraint = solver.makeConstraint(5, 5); | ||
29 | constraint.setCoefficient(x, 1); | ||
30 | constraint.setCoefficient(y, 1); | ||
31 | var objective = solver.objective(); | ||
32 | |||
33 | objective.setCoefficient(x, 1); | ||
34 | objective.setMinimization(); | ||
35 | assertThat(solver.solve(), is(MPSolver.ResultStatus.OPTIMAL)); | ||
36 | assertThat(objective.value(), closeTo(4, 0.01)); | ||
37 | |||
38 | objective.setMaximization(); | ||
39 | assertThat(solver.solve(), is(MPSolver.ResultStatus.OPTIMAL)); | ||
40 | assertThat(objective.value(), closeTo(5, 0.01)); | ||
41 | |||
42 | objective.setCoefficient(x, 0); | ||
43 | objective.setCoefficient(y, 1); | ||
44 | objective.setMinimization(); | ||
45 | assertThat(solver.solve(), is(MPSolver.ResultStatus.OPTIMAL)); | ||
46 | assertThat(objective.value(), closeTo(0, 0.01)); | ||
47 | |||
48 | objective.setMaximization(); | ||
49 | assertThat(solver.solve(), is(MPSolver.ResultStatus.OPTIMAL)); | ||
50 | assertThat(objective.value(), closeTo(1, 0.01)); | ||
51 | } | ||
52 | } | ||
diff --git a/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MultiObjectTest.java b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MultiObjectTest.java new file mode 100644 index 00000000..42ce2f56 --- /dev/null +++ b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/MultiObjectTest.java | |||
@@ -0,0 +1,206 @@ | |||
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.scope; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.model.Interpretation; | ||
11 | import tools.refinery.store.model.Model; | ||
12 | import tools.refinery.store.model.ModelStore; | ||
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.refinement.RefinementResult; | ||
17 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
18 | import tools.refinery.store.reasoning.seed.ModelSeed; | ||
19 | import tools.refinery.store.reasoning.translator.PartialRelationTranslator; | ||
20 | import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; | ||
21 | import tools.refinery.store.representation.Symbol; | ||
22 | import tools.refinery.store.representation.TruthValue; | ||
23 | import tools.refinery.store.representation.cardinality.CardinalityInterval; | ||
24 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
25 | import tools.refinery.store.tuple.Tuple; | ||
26 | |||
27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
28 | import static org.hamcrest.Matchers.is; | ||
29 | |||
30 | class MultiObjectTest { | ||
31 | private static final PartialRelation person = new PartialRelation("Person", 1); | ||
32 | |||
33 | private ModelStore store; | ||
34 | private Model model; | ||
35 | private Interpretation<CardinalityInterval> countStorage; | ||
36 | |||
37 | @BeforeEach | ||
38 | void beforeEach() { | ||
39 | store = ModelStore.builder() | ||
40 | .with(ViatraModelQueryAdapter.builder()) | ||
41 | .with(ReasoningAdapter.builder()) | ||
42 | .with(new MultiObjectTranslator()) | ||
43 | .with(PartialRelationTranslator.of(person) | ||
44 | .symbol(Symbol.of("Person", 1, TruthValue.class, TruthValue.FALSE))) | ||
45 | .with(ScopePropagatorAdapter.builder() | ||
46 | .scope(person, CardinalityIntervals.between(5, 15))) | ||
47 | .build(); | ||
48 | model = null; | ||
49 | countStorage = null; | ||
50 | } | ||
51 | |||
52 | @Test | ||
53 | void oneMultiObjectSatisfiableTest() { | ||
54 | createModel(ModelSeed.builder(4) | ||
55 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
56 | .reducedValue(CardinalityIntervals.ONE) | ||
57 | .put(Tuple.of(0), CardinalityIntervals.SET)) | ||
58 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
59 | .build()); | ||
60 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
61 | assertThat(countStorage.get(Tuple.of(0)), is(CardinalityIntervals.between(2, 12))); | ||
62 | } | ||
63 | |||
64 | @Test | ||
65 | void oneMultiObjectExistingBoundSatisfiableTest() { | ||
66 | createModel(ModelSeed.builder(4) | ||
67 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
68 | .reducedValue(CardinalityIntervals.ONE) | ||
69 | .put(Tuple.of(0), CardinalityIntervals.between(5, 20))) | ||
70 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
71 | .build()); | ||
72 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
73 | assertThat(countStorage.get(Tuple.of(0)), is(CardinalityIntervals.between(5, 12))); | ||
74 | } | ||
75 | |||
76 | @Test | ||
77 | void oneMultiObjectUnsatisfiableUpperTest() { | ||
78 | createModel(ModelSeed.builder(21) | ||
79 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
80 | .reducedValue(CardinalityIntervals.ONE) | ||
81 | .put(Tuple.of(0), CardinalityIntervals.SET)) | ||
82 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
83 | .build()); | ||
84 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
85 | } | ||
86 | |||
87 | @Test | ||
88 | void noMultiObjectSatisfiableTest() { | ||
89 | createModel(ModelSeed.builder(10) | ||
90 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder.reducedValue(CardinalityIntervals.ONE)) | ||
91 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
92 | .build()); | ||
93 | assertThat(propagate(), is(RefinementResult.UNCHANGED)); | ||
94 | } | ||
95 | |||
96 | @Test | ||
97 | void noMultiObjectUnsatisfiableTest() { | ||
98 | createModel(ModelSeed.builder(2) | ||
99 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder.reducedValue(CardinalityIntervals.ONE)) | ||
100 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
101 | .build()); | ||
102 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
103 | } | ||
104 | |||
105 | @Test | ||
106 | void oneMultiObjectExistingBoundUnsatisfiableLowerTest() { | ||
107 | createModel(ModelSeed.builder(4) | ||
108 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
109 | .reducedValue(CardinalityIntervals.ONE) | ||
110 | .put(Tuple.of(0), CardinalityIntervals.atLeast(20))) | ||
111 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
112 | .build()); | ||
113 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
114 | } | ||
115 | |||
116 | @Test | ||
117 | void oneMultiObjectExistingBoundUnsatisfiableUpperTest() { | ||
118 | createModel(ModelSeed.builder(4) | ||
119 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
120 | .reducedValue(CardinalityIntervals.ONE) | ||
121 | .put(Tuple.of(0), CardinalityIntervals.atMost(1))) | ||
122 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
123 | .build()); | ||
124 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
125 | } | ||
126 | |||
127 | @Test | ||
128 | void twoMultiObjectsSatisfiableTest() { | ||
129 | createModel(ModelSeed.builder(5) | ||
130 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
131 | .reducedValue(CardinalityIntervals.ONE) | ||
132 | .put(Tuple.of(0), CardinalityIntervals.SET) | ||
133 | .put(Tuple.of(1), CardinalityIntervals.SET)) | ||
134 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
135 | .build()); | ||
136 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
137 | assertThat(countStorage.get(Tuple.of(0)), is(CardinalityIntervals.atMost(12))); | ||
138 | assertThat(countStorage.get(Tuple.of(1)), is(CardinalityIntervals.atMost(12))); | ||
139 | } | ||
140 | |||
141 | @Test | ||
142 | void twoMultiObjectsExistingBoundSatisfiableTest() { | ||
143 | createModel(ModelSeed.builder(5) | ||
144 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
145 | .reducedValue(CardinalityIntervals.ONE) | ||
146 | .put(Tuple.of(0), CardinalityIntervals.between(7, 20)) | ||
147 | .put(Tuple.of(1), CardinalityIntervals.atMost(11))) | ||
148 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
149 | .build()); | ||
150 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
151 | assertThat(countStorage.get(Tuple.of(0)), is(CardinalityIntervals.between(7, 12))); | ||
152 | assertThat(countStorage.get(Tuple.of(1)), is(CardinalityIntervals.atMost(5))); | ||
153 | } | ||
154 | |||
155 | @Test | ||
156 | void twoMultiObjectsExistingBoundUnsatisfiableUpperTest() { | ||
157 | createModel(ModelSeed.builder(5) | ||
158 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
159 | .reducedValue(CardinalityIntervals.ONE) | ||
160 | .put(Tuple.of(0), CardinalityIntervals.between(7, 20)) | ||
161 | .put(Tuple.of(1), CardinalityIntervals.exactly(11))) | ||
162 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
163 | .build()); | ||
164 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
165 | } | ||
166 | |||
167 | @Test | ||
168 | void twoMultiObjectsExistingBoundUnsatisfiableLowerTest() { | ||
169 | createModel(ModelSeed.builder(3) | ||
170 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
171 | .reducedValue(CardinalityIntervals.ONE) | ||
172 | .put(Tuple.of(0), CardinalityIntervals.LONE) | ||
173 | .put(Tuple.of(1), CardinalityIntervals.atMost(2))) | ||
174 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
175 | .build()); | ||
176 | assertThat(propagate(), is(RefinementResult.REJECTED)); | ||
177 | } | ||
178 | |||
179 | @Test | ||
180 | void multiToSingleTest() { | ||
181 | createModel(ModelSeed.builder(5) | ||
182 | .seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | ||
183 | .reducedValue(CardinalityIntervals.ONE) | ||
184 | .put(Tuple.of(0), CardinalityIntervals.LONE) | ||
185 | .put(Tuple.of(1), CardinalityIntervals.SET)) | ||
186 | .seed(person, builder -> builder.reducedValue(TruthValue.TRUE)) | ||
187 | .build()); | ||
188 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
189 | assertThat(countStorage.get(Tuple.of(0)), is(CardinalityIntervals.LONE)); | ||
190 | assertThat(countStorage.get(Tuple.of(1)), is(CardinalityIntervals.between(1, 12))); | ||
191 | countStorage.put(Tuple.of(0), CardinalityIntervals.ONE); | ||
192 | assertThat(propagate(), is(RefinementResult.REFINED)); | ||
193 | assertThat(countStorage.get(Tuple.of(1)), is(CardinalityIntervals.between(1, 11))); | ||
194 | countStorage.put(Tuple.of(1), CardinalityIntervals.ONE); | ||
195 | assertThat(propagate(), is(RefinementResult.UNCHANGED)); | ||
196 | } | ||
197 | |||
198 | private void createModel(ModelSeed modelSeed) { | ||
199 | model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); | ||
200 | countStorage = model.getInterpretation(MultiObjectTranslator.COUNT_STORAGE); | ||
201 | } | ||
202 | |||
203 | private RefinementResult propagate() { | ||
204 | return model.getAdapter(ScopePropagatorAdapter.class).propagate(); | ||
205 | } | ||
206 | } | ||
diff --git a/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/internal/RoundingUtilTest.java b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/internal/RoundingUtilTest.java new file mode 100644 index 00000000..9daed660 --- /dev/null +++ b/subprojects/store-reasoning-scope/src/test/java/tools/refinery/store/reasoning/scope/internal/RoundingUtilTest.java | |||
@@ -0,0 +1,69 @@ | |||
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.scope.internal; | ||
7 | |||
8 | import org.junit.jupiter.params.ParameterizedTest; | ||
9 | import org.junit.jupiter.params.provider.Arguments; | ||
10 | import org.junit.jupiter.params.provider.MethodSource; | ||
11 | |||
12 | import java.util.stream.Stream; | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat; | ||
15 | import static org.hamcrest.Matchers.is; | ||
16 | |||
17 | class RoundingUtilTest { | ||
18 | @ParameterizedTest | ||
19 | @MethodSource | ||
20 | void roundUpTest(double value, int expected) { | ||
21 | int actual = RoundingUtil.roundUp(value); | ||
22 | assertThat(actual, is(expected)); | ||
23 | } | ||
24 | |||
25 | static Stream<Arguments> roundUpTest() { | ||
26 | return Stream.of( | ||
27 | Arguments.of(0.0, 0), | ||
28 | Arguments.of(-0.0, 0), | ||
29 | Arguments.of(-0.9, 0), | ||
30 | Arguments.of(-2, 0), | ||
31 | Arguments.of(0.009, 0), | ||
32 | Arguments.of(0.011, 1), | ||
33 | Arguments.of(0.1, 1), | ||
34 | Arguments.of(0.991, 1), | ||
35 | Arguments.of(1, 1), | ||
36 | Arguments.of(1.009, 1), | ||
37 | Arguments.of(1.011, 2), | ||
38 | Arguments.of(1.5, 2), | ||
39 | Arguments.of(2, 2), | ||
40 | Arguments.of(100.5, 101) | ||
41 | ); | ||
42 | } | ||
43 | |||
44 | @ParameterizedTest | ||
45 | @MethodSource | ||
46 | void roundDownTest(double value, int expected) { | ||
47 | int actual = RoundingUtil.roundDown(value); | ||
48 | assertThat(actual, is(expected)); | ||
49 | } | ||
50 | |||
51 | static Stream<Arguments> roundDownTest() { | ||
52 | return Stream.of( | ||
53 | Arguments.of(0.0, 0), | ||
54 | Arguments.of(-0.0, 0), | ||
55 | Arguments.of(-0.9, 0), | ||
56 | Arguments.of(-2, 0), | ||
57 | Arguments.of(0.989, 0), | ||
58 | Arguments.of(0.991, 1), | ||
59 | Arguments.of(1, 1), | ||
60 | Arguments.of(1.5, 1), | ||
61 | Arguments.of(1.009, 1), | ||
62 | Arguments.of(1.989, 1), | ||
63 | Arguments.of(1.991, 2), | ||
64 | Arguments.of(2, 2), | ||
65 | Arguments.of(2.009, 2), | ||
66 | Arguments.of(100.5, 100) | ||
67 | ); | ||
68 | } | ||
69 | } | ||