diff options
Diffstat (limited to 'src/test/scala/uk')
4 files changed, 1381 insertions, 0 deletions
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala new file mode 100644 index 0000000..376729c --- /dev/null +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala | |||
@@ -0,0 +1,370 @@ | |||
1 | package rsacomb | ||
2 | |||
3 | import java.io.File | ||
4 | import org.scalatest.LoneElement | ||
5 | import org.scalatest.flatspec.AnyFlatSpec | ||
6 | import org.scalatest.matchers.should.Matchers | ||
7 | |||
8 | import org.semanticweb.owlapi.model._ | ||
9 | import uk.ac.manchester.cs.owl.owlapi._ | ||
10 | import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer | ||
11 | |||
12 | import tech.oxfordsemantic.jrdfox.logic.datalog.Rule | ||
13 | import tech.oxfordsemantic.jrdfox.logic.expression.Variable | ||
14 | |||
15 | import scala.collection.JavaConverters._ | ||
16 | |||
17 | import uk.ac.ox.cs.rsacomb.RSAOntology | ||
18 | import uk.ac.ox.cs.rsacomb.util.{RDFoxHelpers, RSA} | ||
19 | |||
20 | object Ontology1_CanonicalModelSpec { | ||
21 | |||
22 | /* Renderer to display OWL Axioms with DL syntax*/ | ||
23 | val renderer = new DLSyntaxObjectRenderer() | ||
24 | |||
25 | def base(str: String): IRI = | ||
26 | IRI.create("http://example.com/rsa_example.owl#" + str) | ||
27 | |||
28 | val ontology_path: File = new File("examples/example1.ttl") | ||
29 | val ontology = RSAOntology(ontology_path) | ||
30 | val program = ontology.canonicalModel | ||
31 | |||
32 | val roleR = new OWLObjectPropertyImpl(base("R")) | ||
33 | val roleS = new OWLObjectPropertyImpl(base("S")) | ||
34 | val roleT = new OWLObjectPropertyImpl(base("T")) | ||
35 | val roleR_inv = roleR.getInverseProperty() | ||
36 | val roleS_inv = roleS.getInverseProperty() | ||
37 | val roleT_inv = roleT.getInverseProperty() | ||
38 | |||
39 | val AsubClassOfD = new OWLSubClassOfAxiomImpl( | ||
40 | new OWLClassImpl(base("A")), | ||
41 | new OWLClassImpl(base("D")), | ||
42 | Seq().asJava | ||
43 | ) | ||
44 | |||
45 | val DsomeValuesFromRB = new OWLSubClassOfAxiomImpl( | ||
46 | new OWLClassImpl(base("D")), | ||
47 | new OWLObjectSomeValuesFromImpl( | ||
48 | roleR, | ||
49 | new OWLClassImpl(base("B")) | ||
50 | ), | ||
51 | Seq().asJava | ||
52 | ) | ||
53 | |||
54 | val BsomeValuesFromSD = new OWLSubClassOfAxiomImpl( | ||
55 | new OWLClassImpl(base("B")), | ||
56 | new OWLObjectSomeValuesFromImpl( | ||
57 | roleS, | ||
58 | new OWLClassImpl(base("D")) | ||
59 | ), | ||
60 | Seq().asJava | ||
61 | ) | ||
62 | |||
63 | val AsomeValuesFromSiC = new OWLSubClassOfAxiomImpl( | ||
64 | new OWLClassImpl(base("A")), | ||
65 | new OWLObjectSomeValuesFromImpl( | ||
66 | roleS_inv, | ||
67 | new OWLClassImpl(base("C")) | ||
68 | ), | ||
69 | Seq().asJava | ||
70 | ) | ||
71 | |||
72 | val SsubPropertyOfT = new OWLSubObjectPropertyOfAxiomImpl( | ||
73 | new OWLObjectPropertyImpl(base("S")), | ||
74 | new OWLObjectPropertyImpl(base("T")), | ||
75 | Seq().asJava | ||
76 | ) | ||
77 | |||
78 | } | ||
79 | |||
80 | class Ontology1_CanonicalModelSpec | ||
81 | extends AnyFlatSpec | ||
82 | with Matchers | ||
83 | with LoneElement { | ||
84 | |||
85 | import Ontology1_CanonicalModelSpec._ | ||
86 | |||
87 | "The program generated from Example #1" should "not be empty" in { | ||
88 | program.rules should not be empty | ||
89 | } | ||
90 | |||
91 | renderer.render(AsubClassOfD) should "be converted into a single Rule" in { | ||
92 | val varX = Variable.create("X") | ||
93 | val visitor = program.RuleGenerator | ||
94 | val rules = AsubClassOfD.accept(visitor) | ||
95 | rules.loneElement shouldBe a[Rule] | ||
96 | } | ||
97 | |||
98 | // Role R // | ||
99 | |||
100 | renderer.render(roleR) should "be safe" in { | ||
101 | ontology.unsafeRoles should not contain roleR | ||
102 | } | ||
103 | |||
104 | it should "have 3 elements in its conflict set" in { | ||
105 | ontology.confl(roleR) should have size 3 | ||
106 | } | ||
107 | |||
108 | it should "contain S in its conflict set" in { | ||
109 | ontology.confl(roleR) should contain(roleS) | ||
110 | } | ||
111 | |||
112 | it should "contain T in its conflict set" in { | ||
113 | ontology.confl(roleR) should contain(roleT) | ||
114 | } | ||
115 | |||
116 | it should ("contain " + renderer.render( | ||
117 | roleR_inv | ||
118 | ) + " in its conflict set") in { | ||
119 | ontology.confl(roleR) should contain(roleR_inv) | ||
120 | } | ||
121 | |||
122 | // Role S // | ||
123 | |||
124 | renderer.render(roleS) should "be safe" in { | ||
125 | ontology.unsafeRoles should not contain roleS | ||
126 | } | ||
127 | |||
128 | it should "have 3 elements in its conflict set" in { | ||
129 | ontology.confl(roleS) should have size 3 | ||
130 | } | ||
131 | |||
132 | it should "contain R in its conflict set" in { | ||
133 | ontology.confl(roleS) should contain(roleR) | ||
134 | } | ||
135 | |||
136 | it should ("contain " + renderer.render( | ||
137 | roleS_inv | ||
138 | ) + " in its conflict set") in { | ||
139 | ontology.confl(roleS) should contain(roleS_inv) | ||
140 | } | ||
141 | |||
142 | it should ("contain " + renderer.render( | ||
143 | roleT_inv | ||
144 | ) + " in its conflict set") in { | ||
145 | ontology.confl(roleS) should contain(roleT_inv) | ||
146 | } | ||
147 | |||
148 | // S⁻ | ||
149 | |||
150 | renderer.render(roleS_inv) should "be unsafe" in { | ||
151 | ontology.unsafeRoles should contain(roleS_inv) | ||
152 | } | ||
153 | |||
154 | renderer.render( | ||
155 | AsomeValuesFromSiC | ||
156 | ) should "produce 1 rule" in { | ||
157 | val varX = Variable.create("X") | ||
158 | val visitor = program.RuleGenerator | ||
159 | val rules = AsomeValuesFromSiC.accept(visitor) | ||
160 | rules should have length 1 | ||
161 | } | ||
162 | |||
163 | renderer.render( | ||
164 | DsomeValuesFromRB | ||
165 | ) should "have a 'cycle' set of 48 elements" in { | ||
166 | // Cycle introduces a new constant for each possible triple (the | ||
167 | // order among triples is total). In this example there are 4 | ||
168 | // concept names and R has 3 safe roles in its conflict set (S, T, | ||
169 | // Inv(R)). Triples are | ||
170 | // (concept, role, concept) | ||
171 | // and hence we have 4*3*4=48 new constants introduced. | ||
172 | ontology.cycle(DsomeValuesFromRB) should have size 48 | ||
173 | } | ||
174 | |||
175 | it should "produce 5 rules" in { | ||
176 | // Rule 1 provides 1 rule (split in 2) + 48 fact | ||
177 | // Rule 2 provides 0 rules | ||
178 | // Rule 3 provides 48 rule (split in 2) | ||
179 | // Then (1*2 + 48) + (0) + (48*2) = 146 | ||
180 | val varX = Variable.create("X") | ||
181 | val visitor = program.RuleGenerator | ||
182 | val rules = DsomeValuesFromRB.accept(visitor) | ||
183 | rules should have length 146 | ||
184 | } | ||
185 | |||
186 | renderer.render( | ||
187 | BsomeValuesFromSD | ||
188 | ) should "have a 'cycle' set of 32 elements" in { | ||
189 | // Cycle introduces a new constant for each possible triple (the | ||
190 | // order among triples is total). In this example there are 4 | ||
191 | // concept names and S has 2 safe roles in its conflict set (R, | ||
192 | // Inv(T)). Triples are | ||
193 | // (concept, role, concept) | ||
194 | // and hence we have 4*2*4=32 new constants introduced. | ||
195 | ontology.cycle(BsomeValuesFromSD) should have size 32 | ||
196 | } | ||
197 | |||
198 | it should "produce 5 rules" in { | ||
199 | // Rule 1 provides 1 rule (split in 2) + 32 fact | ||
200 | // Rule 2 provides 0 rules | ||
201 | // Rule 3 provides 32 rule (split in 2) | ||
202 | // Then (1*2 + 32) + (0) + (32*2) = 98 | ||
203 | val varX = Variable.create("X") | ||
204 | val visitor = program.RuleGenerator | ||
205 | val rules = DsomeValuesFromRB.accept(visitor) | ||
206 | rules should have length 146 | ||
207 | } | ||
208 | |||
209 | renderer.render( | ||
210 | SsubPropertyOfT | ||
211 | ) should "produce 2 rules" in { | ||
212 | val varX = Variable.create("X") | ||
213 | val visitor = program.RuleGenerator | ||
214 | val rules = SsubPropertyOfT.accept(visitor) | ||
215 | rules should have length 2 | ||
216 | } | ||
217 | |||
218 | } | ||
219 | |||
220 | object Ontology2_CanonicalModelSpec { | ||
221 | |||
222 | /* Renderer to display OWL Axioms with DL syntax*/ | ||
223 | val renderer = new DLSyntaxObjectRenderer() | ||
224 | |||
225 | def base(str: String): IRI = | ||
226 | IRI.create("http://example.com/rsa_example.owl#" + str) | ||
227 | |||
228 | val ontology_path: File = new File("examples/example2.owl") | ||
229 | val ontology = RSAOntology(ontology_path) | ||
230 | val program = ontology.canonicalModel | ||
231 | |||
232 | val roleR = new OWLObjectPropertyImpl(base("R")) | ||
233 | val roleS = new OWLObjectPropertyImpl(base("S")) | ||
234 | val roleT = new OWLObjectPropertyImpl(base("T")) | ||
235 | val roleP = new OWLObjectPropertyImpl(base("P")) | ||
236 | val roleR_inv = roleR.getInverseProperty() | ||
237 | val roleS_inv = roleS.getInverseProperty() | ||
238 | val roleT_inv = roleT.getInverseProperty() | ||
239 | val roleP_inv = roleP.getInverseProperty() | ||
240 | |||
241 | val AsomeValuesFromRB = new OWLSubClassOfAxiomImpl( | ||
242 | new OWLClassImpl(base("A")), | ||
243 | new OWLObjectSomeValuesFromImpl( | ||
244 | roleR, | ||
245 | new OWLClassImpl(base("B")) | ||
246 | ), | ||
247 | Seq().asJava | ||
248 | ) | ||
249 | |||
250 | val BsomeValuesFromSC = new OWLSubClassOfAxiomImpl( | ||
251 | new OWLClassImpl(base("B")), | ||
252 | new OWLObjectSomeValuesFromImpl( | ||
253 | roleS, | ||
254 | new OWLClassImpl(base("C")) | ||
255 | ), | ||
256 | Seq().asJava | ||
257 | ) | ||
258 | |||
259 | val CsomeValuesFromTD = new OWLSubClassOfAxiomImpl( | ||
260 | new OWLClassImpl(base("C")), | ||
261 | new OWLObjectSomeValuesFromImpl( | ||
262 | roleT, | ||
263 | new OWLClassImpl(base("D")) | ||
264 | ), | ||
265 | Seq().asJava | ||
266 | ) | ||
267 | |||
268 | val DsomeValuesFromPA = new OWLSubClassOfAxiomImpl( | ||
269 | new OWLClassImpl(base("D")), | ||
270 | new OWLObjectSomeValuesFromImpl( | ||
271 | roleP, | ||
272 | new OWLClassImpl(base("A")) | ||
273 | ), | ||
274 | Seq().asJava | ||
275 | ) | ||
276 | |||
277 | } | ||
278 | |||
279 | class Ontology2_CanonicalModelSpec | ||
280 | extends AnyFlatSpec | ||
281 | with Matchers | ||
282 | with LoneElement { | ||
283 | |||
284 | import Ontology2_CanonicalModelSpec._ | ||
285 | |||
286 | "The program generated from Example #1" should "not be empty" in { | ||
287 | program.rules should not be empty | ||
288 | } | ||
289 | |||
290 | // Role R // | ||
291 | |||
292 | renderer.render(roleR) should "be unsafe" in { | ||
293 | ontology.unsafeRoles should contain(roleR) | ||
294 | } | ||
295 | |||
296 | it should "have only its inverse in its conflict set" in { | ||
297 | ontology.confl(roleR).loneElement shouldBe roleR_inv | ||
298 | } | ||
299 | |||
300 | // Role S // | ||
301 | |||
302 | renderer.render(roleS) should "be unsafe" in { | ||
303 | ontology.unsafeRoles should contain(roleS) | ||
304 | } | ||
305 | |||
306 | it should "have only its inverse in its conflict set" in { | ||
307 | ontology.confl(roleS).loneElement shouldBe roleS_inv | ||
308 | } | ||
309 | |||
310 | // Role T // | ||
311 | |||
312 | renderer.render(roleT) should "be unsafe" in { | ||
313 | ontology.unsafeRoles should contain(roleT) | ||
314 | } | ||
315 | |||
316 | it should "have only its inverse in its conflict set" in { | ||
317 | ontology.confl(roleT).loneElement shouldBe roleT_inv | ||
318 | } | ||
319 | |||
320 | // Role P // | ||
321 | |||
322 | renderer.render(roleP) should "be unsafe" in { | ||
323 | ontology.unsafeRoles should contain(roleP) | ||
324 | } | ||
325 | |||
326 | it should "have only its inverse in its conflict set" in { | ||
327 | ontology.confl(roleP).loneElement shouldBe roleP_inv | ||
328 | } | ||
329 | |||
330 | // A ⊑ ∃ R.B | ||
331 | |||
332 | renderer.render( | ||
333 | AsomeValuesFromRB | ||
334 | ) should "produce 1 rule" in { | ||
335 | val visitor = program.RuleGenerator | ||
336 | val rules = AsomeValuesFromRB.accept(visitor) | ||
337 | rules should have length 1 | ||
338 | } | ||
339 | |||
340 | // B ⊑ ∃ S.C | ||
341 | |||
342 | renderer.render( | ||
343 | BsomeValuesFromSC | ||
344 | ) should "produce 1 rule" in { | ||
345 | val visitor = program.RuleGenerator | ||
346 | val rules = BsomeValuesFromSC.accept(visitor) | ||
347 | rules should have length 1 | ||
348 | } | ||
349 | |||
350 | // C ⊑ ∃ T.D | ||
351 | |||
352 | renderer.render( | ||
353 | CsomeValuesFromTD | ||
354 | ) should "produce 1 rule" in { | ||
355 | val visitor = program.RuleGenerator | ||
356 | val rules = CsomeValuesFromTD.accept(visitor) | ||
357 | rules should have length 1 | ||
358 | } | ||
359 | |||
360 | // D ⊑ ∃ P.A | ||
361 | |||
362 | renderer.render( | ||
363 | DsomeValuesFromPA | ||
364 | ) should "produce 1 rule" in { | ||
365 | val visitor = program.RuleGenerator | ||
366 | val rules = DsomeValuesFromPA.accept(visitor) | ||
367 | rules should have length 1 | ||
368 | } | ||
369 | |||
370 | } | ||
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala new file mode 100644 index 0000000..49abd48 --- /dev/null +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala | |||
@@ -0,0 +1,398 @@ | |||
1 | package rsacomb | ||
2 | |||
3 | import java.io.File | ||
4 | import java.util.{ArrayList => JList} | ||
5 | import org.scalatest.LoneElement | ||
6 | import org.scalatest.Inspectors | ||
7 | import org.scalatest.flatspec.AnyFlatSpec | ||
8 | import org.scalatest.matchers.should.Matchers | ||
9 | |||
10 | import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom | ||
11 | import tech.oxfordsemantic.jrdfox.logic.expression.{Variable, IRI} | ||
12 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.{Query, SelectQuery} | ||
13 | import tech.oxfordsemantic.jrdfox.Prefixes | ||
14 | |||
15 | import scala.collection.JavaConverters._ | ||
16 | |||
17 | import uk.ac.ox.cs.rsacomb.FilteringProgram | ||
18 | import uk.ac.ox.cs.rsacomb.util.RDFoxHelpers | ||
19 | |||
20 | object FilteringProgramSpec { | ||
21 | |||
22 | val prefixes = new Prefixes() | ||
23 | prefixes.declarePrefix( | ||
24 | ":", | ||
25 | "http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#" | ||
26 | ) | ||
27 | prefixes.declarePrefix("rdf:", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") | ||
28 | prefixes.declarePrefix("rdfs:", "http://www.w3.org/2000/01/rdf-schema#") | ||
29 | prefixes.declarePrefix("owl:", "http://www.w3.org/2002/07/owl#") | ||
30 | |||
31 | // DEBUG: Quick helper functions | ||
32 | def v(v: String): Variable = Variable.create(v) | ||
33 | def c(c: String): IRI = IRI.create(":" + c) | ||
34 | |||
35 | // QUERY 0 | ||
36 | |||
37 | val query0 = RDFoxHelpers | ||
38 | .parseSelectQuery(""" | ||
39 | SELECT ?subj | ||
40 | WHERE { | ||
41 | ?subj ?pred ?obj | ||
42 | } | ||
43 | """, prefixes) | ||
44 | .get | ||
45 | |||
46 | // val query0 = Query.create( | ||
47 | // QueryType.SELECT, | ||
48 | // false, | ||
49 | // List(v("subj")).asJava, | ||
50 | // Atom.rdf(v("subj"), v("pred"), v("obj")) | ||
51 | // ) | ||
52 | |||
53 | // QUERY 1 | ||
54 | |||
55 | val query1 = RDFoxHelpers | ||
56 | .parseSelectQuery(""" | ||
57 | SELECT * | ||
58 | WHERE { | ||
59 | ?w a :Wellbore | ||
60 | } | ||
61 | """, prefixes) | ||
62 | .get | ||
63 | |||
64 | // val query1 = Query.create( | ||
65 | // QueryType.SELECT, | ||
66 | // false, | ||
67 | // List(v("w")).asJava, | ||
68 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")) | ||
69 | // ) | ||
70 | |||
71 | // QUERY 2 | ||
72 | |||
73 | val query2 = RDFoxHelpers | ||
74 | .parseSelectQuery( | ||
75 | """ | ||
76 | SELECT * | ||
77 | WHERE { | ||
78 | ?w a :Wellbore ; | ||
79 | :wellboreDocument ?doc . | ||
80 | ?doc :hasURL ?document_hyperlink | ||
81 | } | ||
82 | """, | ||
83 | prefixes | ||
84 | ) | ||
85 | .get | ||
86 | |||
87 | // val query2 = Query.create( | ||
88 | // QueryType.SELECT, | ||
89 | // false, | ||
90 | // List(v("w"), v("doc"), v("document_hyperlink")).asJava, | ||
91 | // Conjunction.create( | ||
92 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
93 | // Atom.rdf(v("w"), c("wellboreDocument"), v("doc")), | ||
94 | // Atom.rdf(v("doc"), c("hasURL"), v("document_hyperlink")) | ||
95 | // ) | ||
96 | // ) | ||
97 | |||
98 | // QUERY 3 | ||
99 | |||
100 | val query3 = RDFoxHelpers | ||
101 | .parseSelectQuery( | ||
102 | """ | ||
103 | SELECT ?wellbore ?formation_pressure | ||
104 | WHERE { | ||
105 | ?w a :Wellbore ; | ||
106 | :name ?wellbore ; | ||
107 | :hasFormationPressure ?fp . | ||
108 | ?fp :valueInStandardUnit ?formation_pressure | ||
109 | } | ||
110 | """, | ||
111 | prefixes | ||
112 | ) | ||
113 | .get | ||
114 | |||
115 | // val query3 = Query.create( | ||
116 | // QueryType.SELECT, | ||
117 | // false, | ||
118 | // List(v("wellbore"), v("formation_pressure")).asJava, | ||
119 | // Conjunction.create( | ||
120 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
121 | // Atom.rdf(v("w"), c("name"), v("wellbore")), | ||
122 | // Atom.rdf(v("w"), c("hasFormationPressure"), v("fp")), | ||
123 | // Atom.rdf(v("fp"), c("valueInStandardUnit"), v("formation_pressure")) | ||
124 | // ) | ||
125 | // ) | ||
126 | |||
127 | // QUERY 4 | ||
128 | |||
129 | val query4 = RDFoxHelpers | ||
130 | .parseSelectQuery( | ||
131 | """ | ||
132 | SELECT * | ||
133 | WHERE { | ||
134 | ?w a :Wellbore ; | ||
135 | :hasGeochemicalMeasurement ?measurement . | ||
136 | ?measurement :cgType ?cgtype ; | ||
137 | :peakName ?peakType ; | ||
138 | :peakHeight ?peak_height ; | ||
139 | :peakAmount ?peak_amount | ||
140 | } | ||
141 | """, | ||
142 | prefixes | ||
143 | ) | ||
144 | .get | ||
145 | |||
146 | // val query4 = Query.create( | ||
147 | // QueryType.SELECT, | ||
148 | // false, | ||
149 | // List( | ||
150 | // v("w"), | ||
151 | // v("measurement"), | ||
152 | // v("cgtype"), | ||
153 | // v("peakType"), | ||
154 | // v("peak_height"), | ||
155 | // v("peak_amount") | ||
156 | // ).asJava, | ||
157 | // Conjunction.create( | ||
158 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
159 | // Atom.rdf(v("w"), c("hasGeochemicalMeasurement"), v("measurement")), | ||
160 | // Atom.rdf(v("measurement"), c("cgType"), v("cgtype")), | ||
161 | // Atom.rdf(v("measurement"), c("peakName"), v("peakType")), | ||
162 | // Atom.rdf(v("measurement"), c("peakHeight"), v("peak_height")), | ||
163 | // Atom.rdf(v("measurement"), c("peakAmount"), v("peak_amount")) | ||
164 | // ) | ||
165 | // ) | ||
166 | |||
167 | // QUERY 5 | ||
168 | |||
169 | val query5 = RDFoxHelpers | ||
170 | .parseSelectQuery( | ||
171 | """ | ||
172 | SELECT ?wellbore ?unit_name ?discovery | ||
173 | WHERE { | ||
174 | ?w a :Wellbore ; | ||
175 | :name ?wellbore ; | ||
176 | :hasWellboreInterval ?c_int ; | ||
177 | :hasWellboreInterval ?f_int . | ||
178 | ?c_int :hasUnit ?c_unit . | ||
179 | ?c_unit :name ?unit_name . | ||
180 | ?f_int a :FluidZone ; | ||
181 | :name ?discovery ; | ||
182 | :overlapsWellboreInterval ?c_int | ||
183 | } | ||
184 | """, | ||
185 | prefixes | ||
186 | ) | ||
187 | .get | ||
188 | |||
189 | // val query5 = Query.create( | ||
190 | // QueryType.SELECT, | ||
191 | // false, | ||
192 | // List(v("wellbore"), v("unit_name"), v("discovery")).asJava, | ||
193 | // Conjunction.create( | ||
194 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
195 | // Atom.rdf(v("w"), c("name"), v("wellbore")), | ||
196 | // Atom.rdf(v("w"), c("hasWellboreInterval"), v("c_int")), | ||
197 | // Atom.rdf(v("w"), c("hasWellboreInterval"), v("f_int")), | ||
198 | // Atom.rdf(v("c_int"), c("hasUnit"), v("c_unit")), | ||
199 | // Atom.rdf(v("c_unit"), c("name"), v("unit_name")), | ||
200 | // Atom.rdf(v("f_int"), IRI.RDF_TYPE, c("FluidZone")), | ||
201 | // Atom.rdf(v("f_int"), c("name"), v("discovery")), | ||
202 | // Atom.rdf(v("f_int"), c("overlapsWellboreInterval"), v("c_int")) | ||
203 | // ) | ||
204 | // ) | ||
205 | |||
206 | // QUERY 6 | ||
207 | |||
208 | val query6 = RDFoxHelpers | ||
209 | .parseSelectQuery( | ||
210 | """ | ||
211 | SELECT DISTINCT ?wellbore ?content | ||
212 | WHERE { | ||
213 | ?w a :Wellbore ; | ||
214 | :name ?wellbore ; | ||
215 | :hasWellboreInterval ?int . | ||
216 | ?int a :FluidZone ; | ||
217 | :fluidZoneContent ?content | ||
218 | } | ||
219 | """, | ||
220 | prefixes | ||
221 | ) | ||
222 | .get | ||
223 | |||
224 | // val query6 = Query.create( | ||
225 | // QueryType.SELECT, | ||
226 | // true, | ||
227 | // List(v("wellbore"), v("content")).asJava, | ||
228 | // Conjunction.create( | ||
229 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
230 | // Atom.rdf(v("w"), c("name"), v("wellbore")), | ||
231 | // Atom.rdf(v("w"), c("hasWellboreInterval"), v("int")), | ||
232 | // Atom.rdf(v("int"), IRI.RDF_TYPE, c("FluidZone")), | ||
233 | // Atom.rdf(v("int"), c("fluidZoneContent"), v("content")) | ||
234 | // ) | ||
235 | // ) | ||
236 | |||
237 | // QUERY 7 | ||
238 | |||
239 | val query7 = RDFoxHelpers | ||
240 | .parseSelectQuery( | ||
241 | """ | ||
242 | SELECT ?wName ?sample ?porosity ?top_depth_md ?bot_depth_md | ||
243 | WHERE { | ||
244 | ?w a :Wellbore ; | ||
245 | :name ?wName ; | ||
246 | :hasWellboreInterval ?z . | ||
247 | ?z :hasUnit ?u . | ||
248 | ?u :name ?strat_unit_name . | ||
249 | ?wellbore :hasWellboreInterval ?cored_int . | ||
250 | ?c :extractedFrom ?cored_int ; | ||
251 | :hasCoreSample ?sample . | ||
252 | ?sample :hasDepth ?sample_depth . | ||
253 | ?sample_depth | ||
254 | :inWellboreInterval ?z . | ||
255 | ?sample :hasPorosity ?p . | ||
256 | ?p :valueInStandardUnit ?porosity . | ||
257 | ?z :hasTopDepth ?top . | ||
258 | ?top a :MeasuredDepth ; | ||
259 | :valueInStandardUnit ?top_depth_md . | ||
260 | ?z :hasBottomDepth ?bot . | ||
261 | ?bot a :MeasuredDepth ; | ||
262 | :valueInStandardUnit ?bot_depth_md | ||
263 | } | ||
264 | """, | ||
265 | prefixes | ||
266 | ) | ||
267 | .get | ||
268 | |||
269 | // val query7 = Query.create( | ||
270 | // QueryType.SELECT, | ||
271 | // false, | ||
272 | // List( | ||
273 | // v("wName"), | ||
274 | // v("sample"), | ||
275 | // v("porosity"), | ||
276 | // v("top_depth_md"), | ||
277 | // v("bot_depth_md") | ||
278 | // ).asJava, | ||
279 | // Conjunction.create( | ||
280 | // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")), | ||
281 | // Atom.rdf(v("w"), c("name"), v("wName")), | ||
282 | // Atom.rdf(v("w"), c("hasWellboreInterval"), v("z")), | ||
283 | // Atom.rdf(v("z"), c("hasUnit"), v("u")), | ||
284 | // Atom.rdf(v("u"), c("name"), v("strat_unit_name")), | ||
285 | // Atom.rdf(v("wellbore"), c("hasWellboreInterval"), v("cored_int")), | ||
286 | // Atom.rdf(v("c"), c("extractedFrom"), v("cored_int")), | ||
287 | // Atom.rdf(v("c"), c("hasCoreSample"), v("sample")), | ||
288 | // Atom.rdf(v("sample"), c("hasDepth"), v("sample_depth")), | ||
289 | // Atom.rdf(v("sample_depth"), c("inWellboreInterval"), v("z")), | ||
290 | // Atom.rdf(v("sample"), c("hasPorosity"), v("p")), | ||
291 | // Atom.rdf(v("p"), c("valueInStandardUnit"), v("porosity")), | ||
292 | // Atom.rdf(v("z"), c("hasTopDepth"), v("top")), | ||
293 | // Atom.rdf(v("top"), IRI.RDF_TYPE, c("MeasuredDepth")), | ||
294 | // Atom.rdf(v("top"), c("valueInStandardUnit"), v("top_depth_md")), | ||
295 | // Atom.rdf(v("z"), c("hasBottomDepth"), v("bot")), | ||
296 | // Atom.rdf(v("bot"), IRI.RDF_TYPE, c("MeasuredDepth")), | ||
297 | // Atom.rdf(v("bot"), c("valueInStandardUnit"), v("bot_depth_md")) | ||
298 | // ) | ||
299 | // ) | ||
300 | |||
301 | val queries = | ||
302 | List(query0, query1, query2, query3, query4, query5, query6, query7) | ||
303 | } | ||
304 | |||
305 | class FilteringProgramSpec | ||
306 | extends AnyFlatSpec | ||
307 | with Matchers | ||
308 | with LoneElement | ||
309 | with Inspectors { | ||
310 | |||
311 | import FilteringProgramSpec._ | ||
312 | |||
313 | "Queries" should "have distinct answer and bounded variables" in { | ||
314 | for (query <- queries) { | ||
315 | val program = new FilteringProgram(query, List()) | ||
316 | forAll(program.answer) { v => program.bounded should not contain v } | ||
317 | forAll(program.bounded) { v => program.answer should not contain v } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | "Query 0" should "have {?obj, ?pred} as bounded variables" in { | ||
322 | val pred = Variable.create("obj") | ||
323 | val obj = Variable.create("pred") | ||
324 | val program = new FilteringProgram(query0, List()) | ||
325 | program.bounded should contain theSameElementsAs List(pred, obj) | ||
326 | } | ||
327 | |||
328 | "Query 1" should "have no bounded variable" in { | ||
329 | val program = new FilteringProgram(query1, List()) | ||
330 | program.bounded shouldBe empty | ||
331 | } | ||
332 | |||
333 | "Query 2" should "have no bounded variable" in { | ||
334 | val program = new FilteringProgram(query2, List()) | ||
335 | program.bounded shouldBe empty | ||
336 | } | ||
337 | |||
338 | "Query 3" should "have {?w, ?fp} as bounded variables" in { | ||
339 | val w = Variable.create("w") | ||
340 | val fp = Variable.create("fp") | ||
341 | val program = new FilteringProgram(query3, List()) | ||
342 | program.bounded should contain theSameElementsAs List(w, fp) | ||
343 | } | ||
344 | |||
345 | "Query 4" should "have no bounded variable" in { | ||
346 | val program = new FilteringProgram(query4, List()) | ||
347 | program.bounded shouldBe empty | ||
348 | } | ||
349 | |||
350 | "Query 5" should "have a non-empty bounded set" in { | ||
351 | val w = Variable.create("w") | ||
352 | val c_int = Variable.create("c_int") | ||
353 | val f_int = Variable.create("f_int") | ||
354 | val c_unit = Variable.create("c_unit") | ||
355 | val program = new FilteringProgram(query5, List()) | ||
356 | program.bounded should contain theSameElementsAs List( | ||
357 | w, | ||
358 | c_int, | ||
359 | f_int, | ||
360 | c_unit | ||
361 | ) | ||
362 | } | ||
363 | |||
364 | "Query 6" should "have a non-empty bounded set" in { | ||
365 | val w = Variable.create("w") | ||
366 | val int = Variable.create("int") | ||
367 | val program = new FilteringProgram(query6, List()) | ||
368 | program.bounded should contain theSameElementsAs List(w, int) | ||
369 | } | ||
370 | |||
371 | "Query 7" should "have a non-empty bounded set" in { | ||
372 | val w = Variable.create("w") | ||
373 | val z = Variable.create("z") | ||
374 | val u = Variable.create("u") | ||
375 | val strat_unit_name = Variable.create("strat_unit_name") | ||
376 | val wellbore = Variable.create("wellbore") | ||
377 | val cored_int = Variable.create("cored_int") | ||
378 | val c = Variable.create("c") | ||
379 | val sample_depth = Variable.create("sample_depth") | ||
380 | val p = Variable.create("p") | ||
381 | val top = Variable.create("top") | ||
382 | val bot = Variable.create("bot") | ||
383 | val program = new FilteringProgram(query7, List()) | ||
384 | program.bounded should contain theSameElementsAs List( | ||
385 | w, | ||
386 | z, | ||
387 | u, | ||
388 | strat_unit_name, | ||
389 | wellbore, | ||
390 | cored_int, | ||
391 | c, | ||
392 | sample_depth, | ||
393 | p, | ||
394 | top, | ||
395 | bot | ||
396 | ) | ||
397 | } | ||
398 | } | ||
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/OWLAxiomSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/OWLAxiomSpec.scala new file mode 100644 index 0000000..8aee03d --- /dev/null +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/OWLAxiomSpec.scala | |||
@@ -0,0 +1,336 @@ | |||
1 | package rsacomb | ||
2 | |||
3 | import java.util.{ArrayList => JList} | ||
4 | import org.scalatest.LoneElement | ||
5 | import org.scalatest.flatspec.AnyFlatSpec | ||
6 | import org.scalatest.matchers.should.Matchers | ||
7 | |||
8 | import org.semanticweb.owlapi.model.OWLClassExpression | ||
9 | import uk.ac.manchester.cs.owl.owlapi.{OWLSubClassOfAxiomImpl} | ||
10 | import uk.ac.manchester.cs.owl.owlapi.{ | ||
11 | OWLClassImpl, | ||
12 | OWLObjectSomeValuesFromImpl, | ||
13 | OWLObjectIntersectionOfImpl, | ||
14 | OWLObjectOneOfImpl, | ||
15 | OWLObjectAllValuesFromImpl, | ||
16 | OWLObjectMaxCardinalityImpl, | ||
17 | OWLNamedIndividualImpl | ||
18 | } | ||
19 | import uk.ac.manchester.cs.owl.owlapi.{OWLObjectPropertyImpl} | ||
20 | import org.semanticweb.owlapi.model.{OWLAxiom} | ||
21 | |||
22 | import tech.oxfordsemantic.jrdfox.logic.Datatype | ||
23 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
24 | Rule, | ||
25 | BindAtom, | ||
26 | TupleTableAtom, | ||
27 | TupleTableName | ||
28 | } | ||
29 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
30 | FunctionCall, | ||
31 | Term, | ||
32 | Variable, | ||
33 | Literal | ||
34 | } | ||
35 | |||
36 | import org.semanticweb.owlapi.model.{IRI => OWLIRI} | ||
37 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI => RDFIRI} | ||
38 | |||
39 | import uk.ac.ox.cs.rsacomb.converter.{RDFoxAxiomConverter, SkolemStrategy} | ||
40 | import uk.ac.ox.cs.rsacomb.util.RSA | ||
41 | |||
42 | object OWLAxiomSpec { | ||
43 | |||
44 | // IRI | ||
45 | val iri_Professor = OWLIRI.create("univ:Professor") | ||
46 | val iri_Female = OWLIRI.create("std:Female") | ||
47 | val iri_Student = OWLIRI.create("univ:Student") | ||
48 | val iri_PartTimeStudent = OWLIRI.create("univ:PartTimeStudent") | ||
49 | val iri_Worker = OWLIRI.create("univ:Worker") | ||
50 | val iri_alice = OWLIRI.create("univ:alice") | ||
51 | val iri_supervises = OWLIRI.create("univ:supervises") | ||
52 | val iri_hasSupervisor = OWLIRI.create("univ:hasSupervisor") | ||
53 | val iri_sameAs = OWLIRI.create("owl:sameAs") | ||
54 | |||
55 | // RDFox Terms | ||
56 | val term_x = Variable.create("x") | ||
57 | val term_y = Variable.create("y") | ||
58 | val term_z = Variable.create("z") | ||
59 | val term_c1 = RSA("c_1") | ||
60 | val term_c2 = RSA("c_2") | ||
61 | val term_alice = RDFIRI.create("univ:alice") | ||
62 | |||
63 | // RDFox Predicates | ||
64 | val pred_sameAs = TupleTableName.create("owl:sameAs") | ||
65 | val pred_Professor = TupleTableName.create(iri_Professor.getIRIString) | ||
66 | val pred_hasSupervisor = TupleTableName.create(iri_hasSupervisor.getIRIString) | ||
67 | |||
68 | // OWL Classes | ||
69 | // Name Class corresponding to | ||
70 | // | ||
71 | // Professor | ||
72 | // | ||
73 | val class_Professor = new OWLClassImpl(iri_Professor) | ||
74 | val class_Female = new OWLClassImpl(iri_Female) | ||
75 | val class_Student = new OWLClassImpl(iri_Student) | ||
76 | val class_PartTimeStudent = new OWLClassImpl(iri_PartTimeStudent) | ||
77 | val class_Worker = new OWLClassImpl(iri_Worker) | ||
78 | val class_OWLClass = class_Professor | ||
79 | // Class Conjunction corresponding to | ||
80 | // | ||
81 | // Student ∧ Worker | ||
82 | // | ||
83 | val class_OWLObjectIntersectionOf = { | ||
84 | val conjuncts = new JList[OWLClassExpression]() | ||
85 | conjuncts.add(class_Student) | ||
86 | conjuncts.add(class_Worker) | ||
87 | new OWLObjectIntersectionOfImpl(conjuncts) | ||
88 | } | ||
89 | // Singleton Class corresponding to | ||
90 | // | ||
91 | // { alice } | ||
92 | // | ||
93 | val class_OWLObjectOneOf = | ||
94 | new OWLObjectOneOfImpl( | ||
95 | new OWLNamedIndividualImpl(iri_alice) | ||
96 | ) | ||
97 | // Object Existential Restiction corresponding to | ||
98 | // | ||
99 | // ∃ hasSupervisor.Professor | ||
100 | // | ||
101 | val class_OWLObjectSomeValuesFrom = | ||
102 | new OWLObjectSomeValuesFromImpl( | ||
103 | new OWLObjectPropertyImpl(iri_hasSupervisor), | ||
104 | class_Professor | ||
105 | ) | ||
106 | // Object Max Cardinality Restriction corresponding to | ||
107 | // | ||
108 | // ≤ 1 hasSupervisor . Professor | ||
109 | val class_OWLObjectMaxCardinality = | ||
110 | new OWLObjectMaxCardinalityImpl( | ||
111 | new OWLObjectPropertyImpl(iri_hasSupervisor), | ||
112 | 1, | ||
113 | class_Professor | ||
114 | ) | ||
115 | |||
116 | // OWL Axioms | ||
117 | // Axiom SubClassOf corresponding to | ||
118 | // | ||
119 | // Student ∧ Worker -> PartTimeStudent | ||
120 | // | ||
121 | val axiom_OWLSubClassOf1 = | ||
122 | new OWLSubClassOfAxiomImpl( | ||
123 | class_OWLObjectIntersectionOf, | ||
124 | class_PartTimeStudent, | ||
125 | new JList() | ||
126 | ) | ||
127 | |||
128 | // Axiom SubClassOf corresponding to | ||
129 | // | ||
130 | // Student -> ∃ hasSupervisor.Professor | ||
131 | // | ||
132 | val axiom_OWLSubClassOf2 = | ||
133 | new OWLSubClassOfAxiomImpl( | ||
134 | class_Student, | ||
135 | class_OWLObjectSomeValuesFrom, | ||
136 | new JList() | ||
137 | ) | ||
138 | |||
139 | // Axiom SubClassOf corresponding to | ||
140 | // | ||
141 | // ∃ hasSupervisor.Professor -> Student | ||
142 | // | ||
143 | val axiom_OWLSubClassOf3 = | ||
144 | new OWLSubClassOfAxiomImpl( | ||
145 | class_OWLObjectSomeValuesFrom, | ||
146 | class_Student, | ||
147 | new JList() | ||
148 | ) | ||
149 | |||
150 | // Axiom SubClassOf corresponding to | ||
151 | // | ||
152 | // Student -> { alice } | ||
153 | // | ||
154 | val axiom_OWLSubClassOf4 = | ||
155 | new OWLSubClassOfAxiomImpl( | ||
156 | class_Student, | ||
157 | class_OWLObjectOneOf, | ||
158 | new JList() | ||
159 | ) | ||
160 | |||
161 | // Axiom SubClassOf corresponding to | ||
162 | // | ||
163 | // Student -> ≤1 hasSupervisor.Professor | ||
164 | // | ||
165 | val axiom_OWLSubClassOf5 = | ||
166 | new OWLSubClassOfAxiomImpl( | ||
167 | class_Student, | ||
168 | class_OWLObjectMaxCardinality, | ||
169 | new JList() | ||
170 | ) | ||
171 | |||
172 | def convertAxiom( | ||
173 | axiom: OWLAxiom, | ||
174 | term: Term, | ||
175 | skolem: SkolemStrategy = SkolemStrategy.None | ||
176 | ): List[Rule] = { | ||
177 | axiom.accept(RDFoxAxiomConverter(term, List())) | ||
178 | } | ||
179 | |||
180 | } // object OWLAxiomSpec | ||
181 | |||
182 | class OWLAxiomSpec extends AnyFlatSpec with Matchers with LoneElement { | ||
183 | |||
184 | // Import required data | ||
185 | import OWLAxiomSpec._ | ||
186 | // Implicit convertion from IRI in OWLAPI to IRI in JRDFox | ||
187 | import uk.ac.ox.cs.rsacomb.implicits.RDFox._ | ||
188 | |||
189 | // OWLSubClassOfAxiom #1 | ||
190 | axiom_OWLSubClassOf1.toString should "be converted into a singleton List[Rule]" in { | ||
191 | val result = convertAxiom(axiom_OWLSubClassOf1, term_x) | ||
192 | result.loneElement shouldBe a[Rule] | ||
193 | } | ||
194 | |||
195 | it should "contain a conjuction of atoms (Student[?x],Worker[?x]) in the body of the rule" in { | ||
196 | val result = convertAxiom(axiom_OWLSubClassOf1, term_x) | ||
197 | val body = List( | ||
198 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student), | ||
199 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Worker) | ||
200 | ) | ||
201 | result.loneElement.getBody should contain theSameElementsAs body | ||
202 | } | ||
203 | |||
204 | it should "contain a single atom (PartTimeStudent[?x]) in the head of the rule" in { | ||
205 | val result = convertAxiom(axiom_OWLSubClassOf1, term_x) | ||
206 | val head = TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_PartTimeStudent) | ||
207 | result.loneElement.getHead.loneElement should be(head) | ||
208 | } | ||
209 | |||
210 | // OWLSubClassOfAxiom #2 (w/ constant skolemization) | ||
211 | (axiom_OWLSubClassOf2.toString + "\n(w/ constant skolemization)") should | ||
212 | "be converted into a singleton List[Rule]" in { | ||
213 | val skolem = SkolemStrategy.Constant(axiom_OWLSubClassOf2.toString) | ||
214 | val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
215 | result.loneElement shouldBe a[Rule] | ||
216 | } | ||
217 | |||
218 | it should "contain a single atom (Student[?x]) in the body of the rule" in { | ||
219 | val skolem = SkolemStrategy.Constant(axiom_OWLSubClassOf2.toString) | ||
220 | val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
221 | val body = | ||
222 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student.getIRIString) | ||
223 | result.loneElement.getBody.loneElement should equal(body) | ||
224 | } | ||
225 | |||
226 | // it should "contain a conjuction of atoms (hasSupervisor[?x,?c],Professor[?c]) in the head of the rule" in { | ||
227 | // val skolem = SkolemStrategy.Constant(axiom_OWLSubClassOf2.toString) | ||
228 | // val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
229 | // val term_c = RSA.rsa(skolem.const.getIRI) | ||
230 | // val head = List( | ||
231 | // TupleTableAtom.rdf(term_x, iri_hasSupervisor, term_c), | ||
232 | // TupleTableAtom.rdf(term_c, RDFIRI.RDF_TYPE, iri_Professor) | ||
233 | // ) | ||
234 | // result.loneElement.getHead should contain theSameElementsAs (head) | ||
235 | // } | ||
236 | |||
237 | // OWLSubClassOfAxiom #2 (w/ skolemization) | ||
238 | (axiom_OWLSubClassOf2.toString + "\n(w/ skolemization)") should | ||
239 | "be converted into a singleton List[Rule]" in { | ||
240 | val skolem = SkolemStrategy.Standard(axiom_OWLSubClassOf2.toString) | ||
241 | val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
242 | result.loneElement shouldBe a[Rule] | ||
243 | } | ||
244 | |||
245 | it should "contain an atom (Student[?x]) in the body of the rule" in { | ||
246 | val skolem = SkolemStrategy.Standard(axiom_OWLSubClassOf2.toString) | ||
247 | val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
248 | val body = | ||
249 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student) | ||
250 | result.loneElement.getBody should contain(body) | ||
251 | } | ||
252 | |||
253 | // it should "contain a built-in function call (BIND(?y,SKOLEM(?f,?x))) in the body of the rule" in { | ||
254 | // val skolem = SkolemStrategy.Standard(axiom_OWLSubClassOf2.toString) | ||
255 | // val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
256 | // val call = | ||
257 | // BindAtom.create(BuiltinFunctionCall.create("SKOLEM", term_x), term_y) | ||
258 | // result.loneElement.getBody should contain(call) | ||
259 | // } | ||
260 | |||
261 | // it should "contain a conjuction of atom (hasSupervisor[?x,?y],Professor[?y]) in the head of the rule" in { | ||
262 | // val skolem = SkolemStrategy.Standard(axiom_OWLSubClassOf2.toString) | ||
263 | // val result = convertAxiom(axiom_OWLSubClassOf2, term_x, skolem) | ||
264 | // val head = List( | ||
265 | // TupleTableAtom.rdf(term_x, iri_hasSupervisor, term_y), | ||
266 | // TupleTableAtom.rdf(term_y, RDFIRI.RDF_TYPE, iri_Professor) | ||
267 | // ) | ||
268 | // result.loneElement.getHead should contain theSameElementsAs head | ||
269 | // } | ||
270 | |||
271 | // OWLSubClassOfAxiom #3 | ||
272 | axiom_OWLSubClassOf3.toString should "be converted into a singleton List[Rule]" in { | ||
273 | val result = convertAxiom(axiom_OWLSubClassOf3, term_x) | ||
274 | result.loneElement shouldBe a[Rule] | ||
275 | } | ||
276 | |||
277 | // it should "contain a conjunction of atoms (hasSupervisor[?x,?y],Professor[?y]) in the body of the rule" in { | ||
278 | // val result = convertAxiom(axiom_OWLSubClassOf3, term_x) | ||
279 | // val body = List( | ||
280 | // TupleTableAtom.rdf(term_x, iri_hasSupervisor, term_y), | ||
281 | // TupleTableAtom.rdf(term_y, RDFIRI.RDF_TYPE, iri_Professor) | ||
282 | // ) | ||
283 | // result.loneElement.getBody should contain theSameElementsAs body | ||
284 | // } | ||
285 | |||
286 | it should "contain a single atom (Student[?x]) in the head of the rule" in { | ||
287 | val result = convertAxiom(axiom_OWLSubClassOf3, term_x) | ||
288 | val head = | ||
289 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student) | ||
290 | result.loneElement.getHead.loneElement should be(head) | ||
291 | } | ||
292 | |||
293 | // OWLSubClassOfAxiom #4 | ||
294 | axiom_OWLSubClassOf4.toString should "be converted into a singleton List[Rule]" in { | ||
295 | val result = convertAxiom(axiom_OWLSubClassOf4, term_x) | ||
296 | result.loneElement shouldBe a[Rule] | ||
297 | } | ||
298 | |||
299 | it should "contain a single atoms (Student[?x]) in the body of the rule" in { | ||
300 | val result = convertAxiom(axiom_OWLSubClassOf4, term_x) | ||
301 | val body = | ||
302 | TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student) | ||
303 | result.loneElement.getBody.loneElement should be(body) | ||
304 | } | ||
305 | |||
306 | it should "contain a single atom (sameAs[?x,alice])) in the head of the rule" in { | ||
307 | val result = convertAxiom(axiom_OWLSubClassOf4, term_x) | ||
308 | val head = TupleTableAtom.rdf(term_x, RDFIRI.SAME_AS, term_alice) | ||
309 | result.loneElement.getHead.loneElement should be(head) | ||
310 | } | ||
311 | |||
312 | // OWLSubClassOfAxiom #5 | ||
313 | axiom_OWLSubClassOf5.toString should "be converted into a singleton List[Rule]" in { | ||
314 | val result = convertAxiom(axiom_OWLSubClassOf5, term_x) | ||
315 | result.loneElement shouldBe a[Rule] | ||
316 | } | ||
317 | |||
318 | // it should "contain a conjunction of atoms (...) in the body of the rule" in { | ||
319 | // val result = convertAxiom(axiom_OWLSubClassOf5, term_x) | ||
320 | // val body = List( | ||
321 | // TupleTableAtom.rdf(term_x, RDFIRI.RDF_TYPE, iri_Student), | ||
322 | // TupleTableAtom.rdf(term_x, iri_hasSupervisor, term_y), | ||
323 | // TupleTableAtom.rdf(term_y, RDFIRI.RDF_TYPE, iri_Professor), | ||
324 | // TupleTableAtom.rdf(term_x, iri_hasSupervisor, term_z), | ||
325 | // TupleTableAtom.rdf(term_z, RDFIRI.RDF_TYPE, iri_Professor) | ||
326 | // ) | ||
327 | // result.loneElement.getBody should contain theSameElementsAs body | ||
328 | // } | ||
329 | |||
330 | // it should "contain a single atom (sameAs[?x,?z])) in the head of the rule" in { | ||
331 | // val result = convertAxiom(axiom_OWLSubClassOf5, term_x) | ||
332 | // val head = TupleTableAtom.rdf(term_y, RDFIRI.SAME_AS, term_z) | ||
333 | // result.loneElement.getHead.loneElement should be(head) | ||
334 | // } | ||
335 | |||
336 | } // class OWLAxiomSpec | ||
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/OWLClassSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/OWLClassSpec.scala new file mode 100644 index 0000000..459fe21 --- /dev/null +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/OWLClassSpec.scala | |||
@@ -0,0 +1,277 @@ | |||
1 | package rsacomb | ||
2 | |||
3 | import java.util.{ArrayList => JList} | ||
4 | |||
5 | import org.scalatest.LoneElement | ||
6 | import org.scalatest.flatspec.AnyFlatSpec | ||
7 | import org.scalatest.matchers.should.Matchers | ||
8 | |||
9 | import org.semanticweb.owlapi.model.OWLClassExpression | ||
10 | import uk.ac.manchester.cs.owl.owlapi.{ | ||
11 | OWLClassImpl, | ||
12 | OWLObjectSomeValuesFromImpl, | ||
13 | OWLObjectIntersectionOfImpl, | ||
14 | OWLObjectOneOfImpl, | ||
15 | OWLObjectAllValuesFromImpl, | ||
16 | OWLObjectMaxCardinalityImpl, | ||
17 | OWLNamedIndividualImpl | ||
18 | } | ||
19 | import uk.ac.manchester.cs.owl.owlapi.{OWLObjectPropertyImpl} | ||
20 | import org.semanticweb.owlapi.model.IRI | ||
21 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI => RDFIRI} | ||
22 | |||
23 | import tech.oxfordsemantic.jrdfox.logic.Datatype | ||
24 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
25 | TupleTableAtom, | ||
26 | TupleTableName, | ||
27 | BindAtom | ||
28 | } | ||
29 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
30 | FunctionCall, | ||
31 | Term, | ||
32 | Variable, | ||
33 | Literal | ||
34 | } | ||
35 | |||
36 | import uk.ac.ox.cs.rsacomb.converter.{ | ||
37 | RDFoxRuleShards, | ||
38 | RDFoxClassExprConverter, | ||
39 | SkolemStrategy | ||
40 | } | ||
41 | import uk.ac.ox.cs.rsacomb.util.RSA | ||
42 | |||
43 | object OWLClassSpec { | ||
44 | |||
45 | // IRI | ||
46 | val iri_Professor = IRI.create("univ:Professor") | ||
47 | val iri_Female = IRI.create("std:Female") | ||
48 | val iri_Student = IRI.create("univ:Student") | ||
49 | val iri_Worker = IRI.create("univ:Worker") | ||
50 | val iri_alice = IRI.create("univ:alice") | ||
51 | val iri_supervises = IRI.create("univ:supervises") | ||
52 | val iri_hasSupervisor = IRI.create("univ:hasSupervisor") | ||
53 | |||
54 | // RDFox Terms | ||
55 | val term_x = Variable.create("x") | ||
56 | val term_y = Variable.create("y") | ||
57 | val term_c1 = RSA("c_1") | ||
58 | val term_c2 = RSA("c_2") | ||
59 | val term_alice = RDFIRI.create("univ:alice") | ||
60 | |||
61 | // RDFox Predicates | ||
62 | val pred_sameAs = TupleTableName.create("owl:sameAs") | ||
63 | val pred_Professor = TupleTableName.create(iri_Professor.getIRIString) | ||
64 | val pred_hasSupervisor = TupleTableName.create(iri_hasSupervisor.getIRIString) | ||
65 | |||
66 | // OWL Classes | ||
67 | // Name Class corresponding to | ||
68 | // | ||
69 | // Professor | ||
70 | // | ||
71 | val class_Professor = new OWLClassImpl(iri_Professor) | ||
72 | val class_Female = new OWLClassImpl(iri_Female) | ||
73 | val class_Student = new OWLClassImpl(iri_Student) | ||
74 | val class_Worker = new OWLClassImpl(iri_Worker) | ||
75 | val class_OWLClass = class_Professor | ||
76 | |||
77 | // Class Conjunction corresponding to | ||
78 | // | ||
79 | // Female ∧ Student ∧ Worker | ||
80 | // | ||
81 | val class_OWLObjectIntersectionOf = { | ||
82 | val conjuncts = new JList[OWLClassExpression]() | ||
83 | conjuncts.add(class_Female) | ||
84 | conjuncts.add(class_Student) | ||
85 | conjuncts.add(class_Worker) | ||
86 | new OWLObjectIntersectionOfImpl(conjuncts) | ||
87 | } | ||
88 | // Singleton Class corresponding to | ||
89 | // | ||
90 | // { alice } | ||
91 | // | ||
92 | val class_OWLObjectOneOf = | ||
93 | new OWLObjectOneOfImpl( | ||
94 | new OWLNamedIndividualImpl(iri_alice) | ||
95 | ) | ||
96 | // Object Existential Restiction corresponding to | ||
97 | // | ||
98 | // ∃ hasSupervisor.Professor | ||
99 | // | ||
100 | val class_OWLObjectSomeValuesFrom = | ||
101 | new OWLObjectSomeValuesFromImpl( | ||
102 | new OWLObjectPropertyImpl(iri_hasSupervisor), | ||
103 | class_Professor | ||
104 | ) | ||
105 | // Object Max Cardinality Restriction corresponding to | ||
106 | // | ||
107 | // ≤1 hasSupervisor.Professor | ||
108 | val class_OWLObjectMaxCardinality = | ||
109 | new OWLObjectMaxCardinalityImpl( | ||
110 | new OWLObjectPropertyImpl(iri_hasSupervisor), | ||
111 | 1, | ||
112 | class_Professor | ||
113 | ) | ||
114 | } // object OWLClassSpec | ||
115 | |||
116 | class OWLClassSpec extends AnyFlatSpec with Matchers with LoneElement { | ||
117 | // Import required data | ||
118 | import OWLClassSpec._ | ||
119 | |||
120 | // OWLClass | ||
121 | class_OWLClass.toString should "be converted into a RDFoxRuleShards" in { | ||
122 | val visitor = RDFoxClassExprConverter(term_x) | ||
123 | val result = class_OWLClass.accept(visitor) | ||
124 | result shouldBe a[RDFoxRuleShards] | ||
125 | } | ||
126 | |||
127 | it should "have a single TupleTableAtom in its result list" in { | ||
128 | val visitor = RDFoxClassExprConverter(term_x) | ||
129 | val result = class_OWLClass.accept(visitor) | ||
130 | result.res.loneElement shouldBe an[TupleTableAtom] | ||
131 | } | ||
132 | |||
133 | it should "have an empty extension list" in { | ||
134 | val visitor = RDFoxClassExprConverter(term_x) | ||
135 | val result = class_OWLClass.accept(visitor) | ||
136 | result.ext shouldBe empty | ||
137 | } | ||
138 | |||
139 | // OWLObjectIntersectionOf | ||
140 | class_OWLObjectIntersectionOf.toString should "be converted into a RDFoxRuleShards" in { | ||
141 | val visitor = RDFoxClassExprConverter(term_x) | ||
142 | val result = class_OWLObjectIntersectionOf.accept(visitor) | ||
143 | result shouldBe a[RDFoxRuleShards] | ||
144 | } | ||
145 | |||
146 | it should "be converted in the union of its converted conjuncts" in { | ||
147 | val visitor = RDFoxClassExprConverter(term_x) | ||
148 | val result1 = class_OWLObjectIntersectionOf.accept(visitor) | ||
149 | val result2 = RDFoxClassExprConverter.merge( | ||
150 | List( | ||
151 | class_Female.accept(visitor), | ||
152 | class_Student.accept(visitor), | ||
153 | class_Worker.accept(visitor) | ||
154 | ) | ||
155 | ) | ||
156 | result1.res should contain theSameElementsAs result2.res | ||
157 | result1.ext should contain theSameElementsAs result2.ext | ||
158 | } | ||
159 | |||
160 | // OWLObjectOneOf | ||
161 | class_OWLObjectOneOf.toString should "be converted into a RDFoxRuleShards" in { | ||
162 | val visitor = RDFoxClassExprConverter(term_x) | ||
163 | val result = class_OWLObjectOneOf.accept(visitor) | ||
164 | result shouldBe a[RDFoxRuleShards] | ||
165 | } | ||
166 | |||
167 | // it should "be converted into a single <owl:sameAs> TupleTableAtom" in { | ||
168 | // val visitor = RDFoxClassExprConverter(term_x) | ||
169 | // val result = class_OWLObjectOneOf.accept(visitor) | ||
170 | // result.res.loneElement should (be (a [TupleTableAtom]) and have ('tupleTableName (pred_sameAs))) | ||
171 | // } | ||
172 | |||
173 | it should "have an empty extension list" in { | ||
174 | val visitor = RDFoxClassExprConverter(term_x) | ||
175 | val result = class_OWLObjectOneOf.accept(visitor) | ||
176 | result.ext shouldBe empty | ||
177 | } | ||
178 | |||
179 | // OWLObjectSomeValuesFrom | ||
180 | (class_OWLObjectSomeValuesFrom.toString ++ " w/o skolemization") should | ||
181 | "be converted into a RDFoxRuleShards" in { | ||
182 | val visitor = RDFoxClassExprConverter(term_x) | ||
183 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
184 | result shouldBe a[RDFoxRuleShards] | ||
185 | } | ||
186 | |||
187 | it should "have two TupleTableAtoms in its result list" in { | ||
188 | val visitor = RDFoxClassExprConverter(term_x) | ||
189 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
190 | exactly(2, result.res) should (be(an[TupleTableAtom]) | ||
191 | //and have('numberOfArguments (3)) | ||
192 | ) | ||
193 | } | ||
194 | |||
195 | it should "have an empty extension list" in { | ||
196 | val visitor = RDFoxClassExprConverter(term_x) | ||
197 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
198 | result.ext shouldBe empty | ||
199 | } | ||
200 | |||
201 | (class_OWLObjectSomeValuesFrom.toString ++ " w/ skolemization") should | ||
202 | "be converted into a RDFoxRuleShards" in { | ||
203 | val skolem = SkolemStrategy.Standard(class_OWLObjectSomeValuesFrom.toString) | ||
204 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
205 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
206 | result shouldBe a[RDFoxRuleShards] | ||
207 | } | ||
208 | |||
209 | it should "have exactly two TupleTableAtoms in its result list" in { | ||
210 | val skolem = SkolemStrategy.Standard(class_OWLObjectSomeValuesFrom.toString) | ||
211 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
212 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
213 | exactly(2, result.res) should (be(an[TupleTableAtom]) | ||
214 | //and have('numberOfArguments (3)) | ||
215 | ) | ||
216 | } | ||
217 | |||
218 | it should "should have a single SKOLEM call in the extension list" in { | ||
219 | val skolem = SkolemStrategy.Standard(class_OWLObjectSomeValuesFrom.toString) | ||
220 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
221 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
222 | result.ext.loneElement shouldBe a[BindAtom] | ||
223 | val builtin = result.ext.head.asInstanceOf[BindAtom].getExpression | ||
224 | builtin should (be(a[FunctionCall]) and have( | ||
225 | 'functionName ("SKOLEM") | ||
226 | )) | ||
227 | } | ||
228 | |||
229 | (class_OWLObjectSomeValuesFrom.toString ++ " w/ constant skolemization") should | ||
230 | "be converted into a RDFoxRuleShards" in { | ||
231 | val skolem = SkolemStrategy.Constant(class_OWLObjectSomeValuesFrom.toString) | ||
232 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
233 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
234 | result shouldBe a[RDFoxRuleShards] | ||
235 | } | ||
236 | |||
237 | it should "have exactly two TupleTableAtoms in its result list" in { | ||
238 | val skolem = SkolemStrategy.Constant(class_OWLObjectSomeValuesFrom.toString) | ||
239 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
240 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
241 | exactly(2, result.res) should (be(an[TupleTableAtom]) | ||
242 | //and have('numberOfArguments (3)) | ||
243 | ) | ||
244 | } | ||
245 | |||
246 | it should "have an empty extension list" in { | ||
247 | val skolem = SkolemStrategy.Constant(class_OWLObjectSomeValuesFrom.toString) | ||
248 | val visitor = RDFoxClassExprConverter(term_x, List(), skolem) | ||
249 | val result = class_OWLObjectSomeValuesFrom.accept(visitor) | ||
250 | result.ext shouldBe empty | ||
251 | } | ||
252 | |||
253 | // OWLObjectMaxCardinalityImpl | ||
254 | class_OWLObjectMaxCardinality.toString should | ||
255 | "be converted into a RDFoxRuleShards" in { | ||
256 | val visitor = RDFoxClassExprConverter(term_x) | ||
257 | val result = class_OWLObjectMaxCardinality.accept(visitor) | ||
258 | result shouldBe a[RDFoxRuleShards] | ||
259 | } | ||
260 | |||
261 | // it should "have a single <owl:sameAs> TupleTableAtom in the result list" in { | ||
262 | // val visitor = RDFoxClassExprConverter(term_x) | ||
263 | // val result = class_OWLObjectMaxCardinality.accept(visitor) | ||
264 | // result.res.loneElement should (be(an[TupleTableAtom]) and have( | ||
265 | // 'tupleTableName (pred_sameAs) | ||
266 | // )) | ||
267 | // } | ||
268 | |||
269 | it should "have 4 TupleTableAtoms in its extension list" in { | ||
270 | val visitor = RDFoxClassExprConverter(term_x) | ||
271 | val result = class_OWLObjectMaxCardinality.accept(visitor) | ||
272 | exactly(4, result.ext) should (be(an[TupleTableAtom]) | ||
273 | //and have('numberOfArguments (3)) | ||
274 | ) | ||
275 | } | ||
276 | |||
277 | } // class OWLClassSpec | ||