aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-06 17:18:07 +0000
committerFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-06 17:18:07 +0000
commitb721703c349cebd3ffe888d9644f2b85d5a8eeb7 (patch)
treea3845fbf44827ff66fc956c90fe20c1d4be73115
parentc6babfd508f65e8b7596a96659214cb43881dadd (diff)
downloadRSAComb-b721703c349cebd3ffe888d9644f2b85d5a8eeb7.tar.gz
RSAComb-b721703c349cebd3ffe888d9644f2b85d5a8eeb7.zip
Rework canonical model computation
This is a first attempt to avoid a bug triggered by the nature of the class RSAOntology and CanonicalModel. An OWLOntology is converted implicitly to an RSAOntology object whenever it is needed. From within the RSAOntology class we used to create a CanonicalModel object (and pass the underling OWLOntology object as a parameter). Inside CanonicalModel we require RSAOntology functionalities from the OWLOntology, triggering a new conversion into RSAOntology (that would compute a new CanonicalModel and so on in a loop). While declaring the CanonicalModel as lazy in RSAOntology could solve the problem, it does not fix the underlying issue of having a class strictly related to RSAOntology as a top level class. As a first attempt we moved CanonicalModel as an object inside RSAOntology.
-rw-r--r--src/main/scala/rsacomb/CanonicalModel.scala255
-rw-r--r--src/main/scala/rsacomb/Main.scala69
-rw-r--r--src/main/scala/rsacomb/RSAOntology.scala331
3 files changed, 332 insertions, 323 deletions
diff --git a/src/main/scala/rsacomb/CanonicalModel.scala b/src/main/scala/rsacomb/CanonicalModel.scala
deleted file mode 100644
index fcc404a..0000000
--- a/src/main/scala/rsacomb/CanonicalModel.scala
+++ /dev/null
@@ -1,255 +0,0 @@
1package rsacomb
2
3import org.semanticweb.owlapi.model.{
4 OWLOntology,
5 OWLClass,
6 OWLSubObjectPropertyOfAxiom,
7 OWLSubClassOfAxiom,
8 OWLObjectProperty,
9 OWLObjectPropertyExpression,
10 OWLObjectSomeValuesFrom
11}
12import tech.oxfordsemantic.jrdfox.logic.Datatype
13import tech.oxfordsemantic.jrdfox.logic.expression.{IRI, Term, Variable}
14import tech.oxfordsemantic.jrdfox.logic.datalog.{
15 BodyFormula,
16 TupleTableAtom,
17 Rule
18}
19
20import scala.collection.JavaConverters._
21import rsacomb.RSA._
22
23object ProgramGenerator {
24
25 def apply(
26 ontology: OWLOntology,
27 term: Term = Variable.create("X")
28 ): RDFoxAxiomConverter =
29 new ProgramGenerator(ontology, term)
30
31 def generateRoleRules(
32 roles: Set[OWLObjectProperty]
33 ): List[Rule] = {
34 def additional(pred: String): Seq[Rule] = {
35 val varX = Variable.create("X")
36 val varY = Variable.create("Y")
37 List(
38 Rule.create(
39 TupleTableAtom.rdf(varX, IRI.create(pred), varY),
40 TupleTableAtom
41 .rdf(varX, IRI.create(pred ++ RSASuffix.Forward.getSuffix), varY)
42 ),
43 Rule.create(
44 TupleTableAtom.rdf(varX, IRI.create(pred), varY),
45 TupleTableAtom
46 .rdf(varX, IRI.create(pred ++ RSASuffix.Backward.getSuffix), varY)
47 ),
48 Rule.create(
49 TupleTableAtom.rdf(
50 varY,
51 IRI.create(pred ++ RSASuffix.Backward.getSuffix ++ "_inv"),
52 varX
53 ),
54 TupleTableAtom
55 .rdf(varX, IRI.create(pred ++ RSASuffix.Forward.getSuffix), varY)
56 ),
57 Rule.create(
58 TupleTableAtom.rdf(
59 varY,
60 IRI.create(pred ++ RSASuffix.Forward.getSuffix ++ "_inv"),
61 varX
62 ),
63 TupleTableAtom.rdf(
64 varX,
65 IRI.create(pred ++ RSASuffix.Backward.getSuffix),
66 varY
67 )
68 )
69 )
70 }
71 roles
72 .map(_.getIRI.getIRIString)
73 .flatMap(additional)
74 .toList
75 }
76
77 def NIs(individuals: List[IRI]): List[TupleTableAtom] =
78 individuals.map(TupleTableAtom.rdf(_, IRI.RDF_TYPE, RSA.internal("NI")))
79
80}
81
82class ProgramGenerator(
83 ontology: OWLOntology,
84 term: Term
85) extends RDFoxAxiomConverter(
86 term,
87 ontology.unsafeRoles,
88 SkolemStrategy.None,
89 RSASuffix.None
90 )
91 with RSAAxiom {
92
93 import RDFoxUtil._
94
95 def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = {
96 val unfold = ontology.unfold(axiom).toList
97 // Fresh Variables
98 val v0 = IRI.create("v0_" ++ axiom.hashCode.toString)
99 val varX = Variable.create("X")
100 // Predicates
101 val atomA: TupleTableAtom = {
102 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
103 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, cls)
104 }
105 def notIn(t: Term): TupleTableAtom = {
106 TupleTableAtom.rdf(
107 t,
108 RSA.internal("notIn"),
109 RSA.internal(unfold.hashCode.toString)
110 )
111 }
112 val roleRf: TupleTableAtom = {
113 val visitor =
114 new RDFoxPropertyExprConverter(varX, v0, RSASuffix.Forward)
115 axiom.getSuperClass
116 .asInstanceOf[OWLObjectSomeValuesFrom]
117 .getProperty
118 .accept(visitor)
119 .head
120 }
121 val atomB: TupleTableAtom = {
122 val cls = axiom.getSuperClass
123 .asInstanceOf[OWLObjectSomeValuesFrom]
124 .getFiller
125 .asInstanceOf[OWLClass]
126 .getIRI
127 TupleTableAtom.rdf(v0, IRI.RDF_TYPE, cls)
128 }
129 // TODO: To be consistent with the specifics of the visitor we are
130 // returning facts as `Rule`s with true body. While this is correct
131 // there is an easier way to import facts into RDFox. Are we able to
132 // do that?
133 val facts = unfold.map(x => Rule.create(notIn(x)))
134 val rules = List(
135 Rule.create(roleRf, atomA, notIn(varX)),
136 Rule.create(atomB, atomA, notIn(varX))
137 )
138 facts ++ rules
139 }
140
141 def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = {
142 val roleR =
143 axiom.getSuperClass
144 .asInstanceOf[OWLObjectSomeValuesFrom]
145 .getProperty
146 if (ontology.confl(roleR) contains roleR) {
147 // Fresh Variables
148 val v0 = IRI.create("v0_" ++ axiom.hashCode.toString)
149 val v1 = IRI.create("v1_" ++ axiom.hashCode.toString)
150 val v2 = IRI.create("v2_" ++ axiom.hashCode.toString)
151 // Predicates
152 def atomA(t: Term): TupleTableAtom = {
153 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
154 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
155 }
156 def roleRf(t1: Term, t2: Term): TupleTableAtom = {
157 val visitor = new RDFoxPropertyExprConverter(t1, t2, RSASuffix.Forward)
158 roleR.accept(visitor).head
159 }
160 def atomB(t: Term): TupleTableAtom = {
161 val cls = axiom.getSuperClass
162 .asInstanceOf[OWLObjectSomeValuesFrom]
163 .getFiller
164 .asInstanceOf[OWLClass]
165 .getIRI
166 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
167 }
168 //Rules
169 List(
170 Rule.create(roleRf(v0, v1), atomA(v0)),
171 Rule.create(atomB(v1), atomA(v0)),
172 Rule.create(roleRf(v1, v2), atomA(v1)),
173 Rule.create(atomB(v2), atomA(v1))
174 )
175 } else {
176 List()
177 }
178 }
179
180 def rules3(axiom: OWLSubClassOfAxiom): List[Rule] = {
181 val cycle = ontology.cycle(axiom).toList
182 val roleR =
183 axiom.getSuperClass
184 .asInstanceOf[OWLObjectSomeValuesFrom]
185 .getProperty
186 // Fresh Variables
187 val v1 = IRI.create("v1_" ++ axiom.hashCode.toString)
188 // Predicates
189 def atomA(t: Term): TupleTableAtom = {
190 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
191 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
192 }
193 def roleRf(t: Term): TupleTableAtom = {
194 val visitor =
195 new RDFoxPropertyExprConverter(t, v1, RSASuffix.Forward)
196 roleR.accept(visitor).head
197 }
198 val atomB: TupleTableAtom = {
199 val cls = axiom.getSuperClass
200 .asInstanceOf[OWLObjectSomeValuesFrom]
201 .getFiller
202 .asInstanceOf[OWLClass]
203 .getIRI
204 TupleTableAtom.rdf(v1, IRI.RDF_TYPE, cls)
205 }
206 cycle.flatMap { x =>
207 List(
208 Rule.create(roleRf(x), atomA(x)),
209 Rule.create(atomB, atomA(x))
210 )
211 }
212 }
213
214 override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = {
215 if (axiom.isT5) {
216 // TODO: get role in T5 axiom
217 // Assuming one role here
218 val role = axiom.objectPropertyExpressionsInSignature(0)
219 if (ontology.unsafeRoles.contains(role)) {
220 val visitor =
221 new RDFoxAxiomConverter(
222 term,
223 ontology.unsafeRoles,
224 SkolemStrategy.Standard(axiom.toString),
225 RSASuffix.Forward
226 )
227 axiom.accept(visitor)
228 } else {
229 rules1(axiom) ++ rules2(axiom) ++ rules3(axiom)
230 }
231 } else {
232 // Fallback to standard OWL to LP translation
233 super.visit(axiom)
234 }
235 }
236
237 override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = {
238 val varX = Variable.create("X")
239 val varY = Variable.create("Y")
240 val visitorF = new RDFoxAxiomConverter(
241 term,
242 ontology.unsafeRoles,
243 SkolemStrategy.None,
244 RSASuffix.Forward
245 )
246 val visitorB = new RDFoxAxiomConverter(
247 term,
248 ontology.unsafeRoles,
249 SkolemStrategy.None,
250 RSASuffix.Backward
251 )
252 axiom.accept(visitorB) ++ axiom.accept(visitorF)
253 }
254
255}
diff --git a/src/main/scala/rsacomb/Main.scala b/src/main/scala/rsacomb/Main.scala
index 830f1e0..64343f5 100644
--- a/src/main/scala/rsacomb/Main.scala
+++ b/src/main/scala/rsacomb/Main.scala
@@ -2,6 +2,10 @@ package rsacomb
2 2
3/* Java imports */ 3/* Java imports */
4import java.io.File 4import java.io.File
5import java.util.HashMap
6import scala.collection.JavaConverters._
7
8import tech.oxfordsemantic.jrdfox.client.UpdateType
5 9
6/* Local imports */ 10/* Local imports */
7import rsacomb.RSA._ 11import rsacomb.RSA._
@@ -46,25 +50,64 @@ object RSAComb extends App {
46 * case. 50 * case.
47 */ 51 */
48 52
49 val ontology = RSA.loadOntology(ontoPath) 53 val ontology: RSAOntology = RSA.loadOntology(ontoPath)
50 if (ontology.isRSA) { 54 if (ontology.isRSA) {
51 55
52 /* Build canonical model */
53 //val tboxCanon = rsa.canonicalModel()
54
55 // DEBUG: print program to generate canonical model
56 {
57 ontology.canonicalModel.foreach(println)
58 }
59
60 /* Load query */ 56 /* Load query */
61 val query = RDFoxUtil.parseQuery( 57 val query = RDFoxUtil.parseQuery(
62 "SELECT ?X WHERE {?X ?Y ?Z}" 58 """
59 SELECT ?uno
60 WHERE {
61 ?uno a :D ;
62 :R ?due .
63 ?due :S ?tre .
64 ?tre a :D .
65 }
66 """
63 ) 67 )
64 68
65 val filter = query map { q => ontology.filteringProgram(q) } 69 /* Compute answers to query */
66 70 query match {
67 /* ... */ 71 case Some(query) => {
72 // Open connection to RDFox
73 val (server, data) = RDFoxUtil.openConnection("AnswerComputation")
74
75 // Gather canonical model and filtering rules
76 val canon = ontology.canonicalModel
77 val filter = ontology.filteringProgram(query)
78
79 // Import relevant data
80 data.importData(UpdateType.ADDITION, RSA.Prefixes, ":a a :A .")
81 data.addRules(canon.rules.asJava)
82 data.addRules(filter.rules.asJava)
83
84 // Collect answers to query
85 for ((v, i) <- filter.variables.view.zipWithIndex) {
86 println(s"Variable $i:")
87 val query = s"SELECT ?X ?Y WHERE { ?X internal:Ans_$i ?Y }"
88 val cursor =
89 data.createCursor(
90 RSA.Prefixes,
91 query,
92 new HashMap[String, String]()
93 );
94 var mul = cursor.open()
95 while (mul > 0) {
96 printf(
97 "Ans_%d(%s,%s)",
98 i,
99 cursor.getResource(0),
100 cursor.getResource(1)
101 )
102 mul = cursor.advance()
103 }
104 }
105
106 // Close connection to RDFox
107 RDFoxUtil.closeConnection(server, data)
108 }
109 case None => {}
110 }
68 } 111 }
69} 112}
70 113
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala
index ef1885b..60008a2 100644
--- a/src/main/scala/rsacomb/RSAOntology.scala
+++ b/src/main/scala/rsacomb/RSAOntology.scala
@@ -4,11 +4,13 @@ package rsacomb
4import java.util.HashMap 4import java.util.HashMap
5import java.util.stream.{Collectors, Stream} 5import java.util.stream.{Collectors, Stream}
6 6
7import org.semanticweb.owlapi.model.OWLOntology 7import org.semanticweb.owlapi.model.{OWLOntology, OWLAxiom}
8import org.semanticweb.owlapi.model.{ 8import org.semanticweb.owlapi.model.{
9 OWLClass, 9 OWLClass,
10 OWLObjectProperty, 10 OWLObjectProperty,
11 OWLSubObjectPropertyOfAxiom,
11 OWLObjectPropertyExpression, 12 OWLObjectPropertyExpression,
13 OWLObjectSomeValuesFrom,
12 OWLSubClassOfAxiom 14 OWLSubClassOfAxiom
13} 15}
14import org.semanticweb.owlapi.model.parameters.Imports 16import org.semanticweb.owlapi.model.parameters.Imports
@@ -45,24 +47,37 @@ trait RSAOntology {
45 */ 47 */
46 implicit class RSAOntology(ontology: OWLOntology) extends RSAAxiom { 48 implicit class RSAOntology(ontology: OWLOntology) extends RSAAxiom {
47 49
50 // Gather TBox+RBox from original ontology
51 lazy val tbox: List[OWLAxiom] =
52 ontology
53 .tboxAxioms(Imports.INCLUDED)
54 .collect(Collectors.toList())
55 .asScala
56 .toList
57
58 lazy val rbox: List[OWLAxiom] =
59 ontology
60 .rboxAxioms(Imports.INCLUDED)
61 .collect(Collectors.toList())
62 .asScala
63 .toList
64
65 lazy val axioms: List[OWLAxiom] = tbox ++ rbox
66
48 /* Retrieve individuals in the original ontology 67 /* Retrieve individuals in the original ontology
49 */ 68 */
50 lazy val individuals: List[IRI] = { 69 lazy val individuals: List[IRI] =
51 ontology 70 ontology
52 .getIndividualsInSignature() 71 .getIndividualsInSignature()
53 .asScala 72 .asScala
54 .map(_.getIRI) 73 .map(_.getIRI)
55 .map(RDFoxUtil.owlapi2rdfox) 74 .map(RDFoxUtil.owlapi2rdfox)
56 .toList 75 .toList
57 }
58 76
59 // private val roles: Set[OWLObjectPropertyExpression] = { 77 lazy val roles: List[OWLObjectPropertyExpression] =
60 // ontology 78 axioms
61 // .rboxAxioms(Imports.INCLUDED) 79 .flatMap(_.objectPropertyExpressionsInSignature)
62 // .collect(Collectors.toSet()) 80 .distinct
63 // .asScala
64 // .flatMap(_.objectPropertyExpressionsInSignature)
65 // }
66 81
67 // OWLAPI reasoner for same easier tasks 82 // OWLAPI reasoner for same easier tasks
68 private val reasoner = 83 private val reasoner =
@@ -79,13 +94,6 @@ trait RSAOntology {
79 */ 94 */
80 lazy val isRSA: Boolean = { 95 lazy val isRSA: Boolean = {
81 96
82 val tbox = ontology.tboxAxioms(Imports.INCLUDED)
83 val rbox = ontology.rboxAxioms(Imports.INCLUDED)
84 val axioms =
85 Stream
86 .concat(tbox, rbox)
87 .collect(Collectors.toList())
88 .asScala
89 val unsafe = this.unsafeRoles 97 val unsafe = this.unsafeRoles
90 98
91 /* DEBUG: print rules in DL syntax and unsafe roles */ 99 /* DEBUG: print rules in DL syntax and unsafe roles */
@@ -154,11 +162,6 @@ trait RSAOntology {
154 162
155 lazy val unsafeRoles: List[OWLObjectPropertyExpression] = { 163 lazy val unsafeRoles: List[OWLObjectPropertyExpression] = {
156 164
157 val tbox = ontology
158 .tboxAxioms(Imports.INCLUDED)
159 .collect(Collectors.toSet())
160 .asScala
161
162 /* DEBUG: print rules in DL syntax */ 165 /* DEBUG: print rules in DL syntax */
163 //val renderer = new DLSyntaxObjectRenderer() 166 //val renderer = new DLSyntaxObjectRenderer()
164 167
@@ -210,37 +213,6 @@ trait RSAOntology {
210 (unsafe1 ++ unsafe2).toList 213 (unsafe1 ++ unsafe2).toList
211 } 214 }
212 215
213 lazy val canonicalModel: List[Rule] = {
214 // Compute program to generate canonical model
215 val tbox =
216 ontology
217 .tboxAxioms(Imports.INCLUDED)
218 .collect(Collectors.toList())
219 .asScala
220 .toList
221 val rbox =
222 ontology
223 .rboxAxioms(Imports.INCLUDED)
224 .collect(Collectors.toList())
225 .asScala
226 .toList
227 val axioms = tbox ++ rbox
228 val varX = Variable.create("X")
229 val visitor = ProgramGenerator(ontology, varX)
230 val facts = ProgramGenerator.NIs(individuals)
231 val rules1 = ProgramGenerator.generateRoleRules(
232 axioms
233 .flatMap(
234 _.objectPropertiesInSignature.collect(Collectors.toSet()).asScala
235 )
236 .toSet
237 )
238 val rules2 = axioms.flatMap(_.accept(visitor))
239
240 rules1 ++ rules2
241 // Call RDFox to generate the canonical model
242 }
243
244 private def rsaGraph( 216 private def rsaGraph(
245 data: DataStoreConnection 217 data: DataStoreConnection
246 ): Graph[Resource, UnDiEdge] = { 218 ): Graph[Resource, UnDiEdge] = {
@@ -256,8 +228,8 @@ trait RSAOntology {
256 Graph(edges: _*) 228 Graph(edges: _*)
257 } 229 }
258 230
259 def filteringProgram(query: SelectQuery): List[Rule] = 231 def filteringProgram(query: SelectQuery): FilteringProgram =
260 FilteringProgram(query, individuals).rules 232 FilteringProgram(query, individuals)
261 233
262 // TODO: the following functions needs testing 234 // TODO: the following functions needs testing
263 def confl( 235 def confl(
@@ -366,6 +338,255 @@ trait RSAOntology {
366 def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = 338 def unfold(axiom: OWLSubClassOfAxiom): Set[Term] =
367 this.self(axiom) | this.cycle(axiom) 339 this.self(axiom) | this.cycle(axiom)
368 340
341 object canonicalModel {
342
343 import RDFoxUtil._
344
345 val NIs: List[Rule] =
346 individuals.map(a =>
347 Rule.create(TupleTableAtom.rdf(a, IRI.RDF_TYPE, RSA.internal("NI")))
348 )
349
350 val rolesAdditionalRules: List[Rule] = {
351 // Given a role (predicate) compute additional logic rules
352 def additional(pred: String): Seq[Rule] = {
353 val varX = Variable.create("X")
354 val varY = Variable.create("Y")
355 List(
356 Rule.create(
357 TupleTableAtom.rdf(varX, IRI.create(pred), varY),
358 TupleTableAtom
359 .rdf(
360 varX,
361 IRI.create(pred ++ RSASuffix.Forward.getSuffix),
362 varY
363 )
364 ),
365 Rule.create(
366 TupleTableAtom.rdf(varX, IRI.create(pred), varY),
367 TupleTableAtom
368 .rdf(
369 varX,
370 IRI.create(pred ++ RSASuffix.Backward.getSuffix),
371 varY
372 )
373 ),
374 Rule.create(
375 TupleTableAtom.rdf(
376 varY,
377 IRI.create(pred ++ RSASuffix.Backward.getSuffix ++ "_inv"),
378 varX
379 ),
380 TupleTableAtom
381 .rdf(
382 varX,
383 IRI.create(pred ++ RSASuffix.Forward.getSuffix),
384 varY
385 )
386 ),
387 Rule.create(
388 TupleTableAtom.rdf(
389 varY,
390 IRI.create(pred ++ RSASuffix.Forward.getSuffix ++ "_inv"),
391 varX
392 ),
393 TupleTableAtom.rdf(
394 varX,
395 IRI.create(pred ++ RSASuffix.Backward.getSuffix),
396 varY
397 )
398 )
399 )
400 }
401 // Compute additional rules per role
402 axioms
403 .flatMap(
404 _.objectPropertiesInSignature.collect(Collectors.toSet()).asScala
405 )
406 .distinct
407 .map(_.getIRI.getIRIString)
408 .flatMap(additional)
409 }
410
411 val rules: List[Rule] = {
412 // Compute rules from ontology axioms
413 val rules = axioms.flatMap(_.accept(this.ProgramGenerator))
414 // Return full set of rules
415 rules ++ rolesAdditionalRules ++ NIs
416 }
417
418 object ProgramGenerator
419 extends RDFoxAxiomConverter(
420 Variable.create("X"),
421 unsafeRoles,
422 SkolemStrategy.None,
423 RSASuffix.None
424 ) {
425
426 private def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = {
427 val unfold = ontology.unfold(axiom).toList
428 // Fresh Variables
429 val v0 = IRI.create("v0_" ++ axiom.hashCode.toString)
430 val varX = Variable.create("X")
431 // Predicates
432 val atomA: TupleTableAtom = {
433 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
434 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, cls)
435 }
436 def notIn(t: Term): TupleTableAtom = {
437 TupleTableAtom.rdf(
438 t,
439 RSA.internal("notIn"),
440 RSA.internal(unfold.hashCode.toString)
441 )
442 }
443 val roleRf: TupleTableAtom = {
444 val visitor =
445 new RDFoxPropertyExprConverter(varX, v0, RSASuffix.Forward)
446 axiom.getSuperClass
447 .asInstanceOf[OWLObjectSomeValuesFrom]
448 .getProperty
449 .accept(visitor)
450 .head
451 }
452 val atomB: TupleTableAtom = {
453 val cls = axiom.getSuperClass
454 .asInstanceOf[OWLObjectSomeValuesFrom]
455 .getFiller
456 .asInstanceOf[OWLClass]
457 .getIRI
458 TupleTableAtom.rdf(v0, IRI.RDF_TYPE, cls)
459 }
460 // TODO: To be consistent with the specifics of the visitor we are
461 // returning facts as `Rule`s with true body. While this is correct
462 // there is an easier way to import facts into RDFox. Are we able to
463 // do that?
464 val facts = unfold.map(x => Rule.create(notIn(x)))
465 val rules = List(
466 Rule.create(roleRf, atomA, notIn(varX)),
467 Rule.create(atomB, atomA, notIn(varX))
468 )
469 facts ++ rules
470 }
471
472 private def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = {
473 val roleR =
474 axiom.getSuperClass
475 .asInstanceOf[OWLObjectSomeValuesFrom]
476 .getProperty
477 if (ontology.confl(roleR) contains roleR) {
478 // Fresh Variables
479 val v0 = IRI.create("v0_" ++ axiom.hashCode.toString)
480 val v1 = IRI.create("v1_" ++ axiom.hashCode.toString)
481 val v2 = IRI.create("v2_" ++ axiom.hashCode.toString)
482 // Predicates
483 def atomA(t: Term): TupleTableAtom = {
484 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
485 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
486 }
487 def roleRf(t1: Term, t2: Term): TupleTableAtom = {
488 val visitor =
489 new RDFoxPropertyExprConverter(t1, t2, RSASuffix.Forward)
490 roleR.accept(visitor).head
491 }
492 def atomB(t: Term): TupleTableAtom = {
493 val cls = axiom.getSuperClass
494 .asInstanceOf[OWLObjectSomeValuesFrom]
495 .getFiller
496 .asInstanceOf[OWLClass]
497 .getIRI
498 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
499 }
500 //Rules
501 List(
502 Rule.create(roleRf(v0, v1), atomA(v0)),
503 Rule.create(atomB(v1), atomA(v0)),
504 Rule.create(roleRf(v1, v2), atomA(v1)),
505 Rule.create(atomB(v2), atomA(v1))
506 )
507 } else {
508 List()
509 }
510 }
511
512 private def rules3(axiom: OWLSubClassOfAxiom): List[Rule] = {
513 val cycle = ontology.cycle(axiom).toList
514 val roleR =
515 axiom.getSuperClass
516 .asInstanceOf[OWLObjectSomeValuesFrom]
517 .getProperty
518 // Fresh Variables
519 val v1 = IRI.create("v1_" ++ axiom.hashCode.toString)
520 // Predicates
521 def atomA(t: Term): TupleTableAtom = {
522 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
523 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
524 }
525 def roleRf(t: Term): TupleTableAtom = {
526 val visitor =
527 new RDFoxPropertyExprConverter(t, v1, RSASuffix.Forward)
528 roleR.accept(visitor).head
529 }
530 val atomB: TupleTableAtom = {
531 val cls = axiom.getSuperClass
532 .asInstanceOf[OWLObjectSomeValuesFrom]
533 .getFiller
534 .asInstanceOf[OWLClass]
535 .getIRI
536 TupleTableAtom.rdf(v1, IRI.RDF_TYPE, cls)
537 }
538 cycle.flatMap { x =>
539 List(
540 Rule.create(roleRf(x), atomA(x)),
541 Rule.create(atomB, atomA(x))
542 )
543 }
544 }
545
546 override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = {
547 if (axiom.isT5) {
548 // TODO: get role in T5 axiom
549 // Assuming one role here
550 val role = axiom.objectPropertyExpressionsInSignature(0)
551 if (ontology.unsafeRoles.contains(role)) {
552 val visitor =
553 new RDFoxAxiomConverter(
554 Variable.create("X"),
555 ontology.unsafeRoles,
556 SkolemStrategy.Standard(axiom.toString),
557 RSASuffix.Forward
558 )
559 axiom.accept(visitor)
560 } else {
561 rules1(axiom) ++ rules2(axiom) ++ rules3(axiom)
562 }
563 } else {
564 // Fallback to standard OWL to LP translation
565 super.visit(axiom)
566 }
567 }
568
569 override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = {
570 val varX = Variable.create("X")
571 val varY = Variable.create("Y")
572 val visitorF = new RDFoxAxiomConverter(
573 Variable.create("X"),
574 ontology.unsafeRoles,
575 SkolemStrategy.None,
576 RSASuffix.Forward
577 )
578 val visitorB = new RDFoxAxiomConverter(
579 Variable.create("X"),
580 ontology.unsafeRoles,
581 SkolemStrategy.None,
582 RSASuffix.Backward
583 )
584 axiom.accept(visitorB) ++ axiom.accept(visitorF)
585 }
586
587 }
588
589 }
369 } // implicit class RSAOntology 590 } // implicit class RSAOntology
370 591
371} // trait RSAOntology 592} // trait RSAOntology