aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/rsacomb/CanonicalModel.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/rsacomb/CanonicalModel.scala')
-rw-r--r--src/main/scala/rsacomb/CanonicalModel.scala292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/main/scala/rsacomb/CanonicalModel.scala b/src/main/scala/rsacomb/CanonicalModel.scala
new file mode 100644
index 0000000..f7a45a7
--- /dev/null
+++ b/src/main/scala/rsacomb/CanonicalModel.scala
@@ -0,0 +1,292 @@
1package rsacomb
2
3import org.semanticweb.owlapi.model.{OWLObjectInverseOf, OWLObjectProperty}
4import org.semanticweb.owlapi.model.{
5 OWLClass,
6 // OWLObjectProperty,
7 OWLSubObjectPropertyOfAxiom,
8 // OWLObjectPropertyExpression,
9 OWLObjectSomeValuesFrom,
10 OWLSubClassOfAxiom
11}
12
13import tech.oxfordsemantic.jrdfox.logic.datalog.{
14 Rule,
15 BodyFormula,
16 TupleTableAtom,
17 Negation
18}
19import tech.oxfordsemantic.jrdfox.logic.expression.{
20 Term,
21 Variable,
22 // Resource,
23 IRI
24}
25
26import suffix.{Empty, Forward, Backward, Inverse}
27
28class CanonicalModel(val ontology: RSAOntology) extends RSAAxiom {
29
30 // Makes working with IRIs less painful
31 import RDFoxUtil._
32
33 val named: List[Rule] =
34 ontology.individuals.map(a =>
35 Rule.create(TupleTableAtom.rdf(a, IRI.RDF_TYPE, RSA.Named))
36 )
37
38 val rolesAdditionalRules: List[Rule] = {
39 // Given a role (predicate) compute additional logic rules
40 def additional(pred: String): Seq[Rule] = {
41 val varX = Variable.create("X")
42 val varY = Variable.create("Y")
43 for (
44 (hSuffix, bSuffix) <- List(
45 (Empty, Forward),
46 (Empty, Backward),
47 (Inverse, Forward + Inverse),
48 (Inverse, Backward + Inverse),
49 (Backward + Inverse, Forward),
50 (Forward + Inverse, Backward),
51 (Backward, Forward + Inverse),
52 (Forward, Backward + Inverse)
53 )
54 )
55 yield Rule.create(
56 TupleTableAtom.rdf(varX, pred :: hSuffix, varY),
57 TupleTableAtom.rdf(varX, pred :: bSuffix, varY)
58 )
59 }
60 // Compute additional rules per role
61 ontology.roles
62 .collect { case prop: OWLObjectProperty => prop }
63 .map(_.getIRI.getIRIString)
64 .flatMap(additional)
65 }
66
67 private lazy val topAxioms: List[Rule] = {
68 val varX = Variable.create("X")
69 val varY = Variable.create("Y")
70 val concepts = ontology.concepts.map(c => {
71 Rule.create(
72 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING),
73 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, c.getIRI)
74 )
75 })
76 val roles = ontology.roles.map(r => {
77 val name = r match {
78 case x: OWLObjectProperty => x.getIRI.getIRIString
79 case x: OWLObjectInverseOf =>
80 x.getInverse.getNamedProperty.getIRI.getIRIString :: Inverse
81 }
82 Rule.create(
83 List(
84 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING),
85 TupleTableAtom.rdf(varY, IRI.RDF_TYPE, IRI.THING)
86 ),
87 List(TupleTableAtom.rdf(varX, name, varY))
88 )
89 })
90 concepts ::: roles
91 }
92
93 private val equalityAxioms: List[Rule] = {
94 val varX = Variable.create("X")
95 val varY = Variable.create("Y")
96 val varZ = Variable.create("Z")
97 List(
98 Rule.create(
99 TupleTableAtom.rdf(varX, RSA.EquivTo, varX),
100 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING)
101 ),
102 Rule.create(
103 TupleTableAtom.rdf(varY, RSA.EquivTo, varX),
104 TupleTableAtom.rdf(varX, RSA.EquivTo, varY)
105 ),
106 Rule.create(
107 TupleTableAtom.rdf(varX, RSA.EquivTo, varZ),
108 TupleTableAtom.rdf(varX, RSA.EquivTo, varY),
109 TupleTableAtom.rdf(varY, RSA.EquivTo, varZ)
110 )
111 )
112 }
113
114 val rules: List[Rule] = {
115 // Compute rules from ontology axioms
116 val rules = ontology.axioms.flatMap(_.accept(RuleGenerator))
117 // Return full set of rules
118 rules ::: rolesAdditionalRules ::: topAxioms ::: equalityAxioms ::: named
119 }
120
121 object RuleGenerator
122 extends RDFoxAxiomConverter(
123 Variable.create("X"),
124 ontology.unsafeRoles,
125 SkolemStrategy.None,
126 Empty
127 ) {
128
129 private def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = {
130 val unfold = ontology.unfold(axiom).toList
131 // Fresh Variables
132 val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom))
133 val varX = Variable.create("X")
134 // Predicates
135 val atomA: TupleTableAtom = {
136 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
137 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, cls)
138 }
139 def predIN(t: Term): TupleTableAtom = {
140 TupleTableAtom.rdf(
141 t,
142 RSA.rsa("IN"),
143 RSA.rsa(unfold.hashCode.toString)
144 )
145 }
146 def notIn(t: Term): Negation = Negation.create(predIN(t))
147 val roleRf: TupleTableAtom = {
148 val visitor =
149 new RDFoxPropertyExprConverter(varX, v0, Forward)
150 axiom.getSuperClass
151 .asInstanceOf[OWLObjectSomeValuesFrom]
152 .getProperty
153 .accept(visitor)
154 .head
155 }
156 val atomB: TupleTableAtom = {
157 val cls = axiom.getSuperClass
158 .asInstanceOf[OWLObjectSomeValuesFrom]
159 .getFiller
160 .asInstanceOf[OWLClass]
161 .getIRI
162 TupleTableAtom.rdf(v0, IRI.RDF_TYPE, cls)
163 }
164 // TODO: To be consistent with the specifics of the visitor we are
165 // returning facts as `Rule`s with true body. While this is correct
166 // there is an easier way to import facts into RDFox. Are we able to
167 // do that?
168 val facts = unfold.map(x => Rule.create(predIN(x)))
169 val rules = List(
170 Rule.create(roleRf, atomA, notIn(varX)),
171 Rule.create(atomB, atomA, notIn(varX))
172 )
173 facts ++ rules
174 }
175
176 private def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = {
177 val roleR =
178 axiom.getSuperClass
179 .asInstanceOf[OWLObjectSomeValuesFrom]
180 .getProperty
181 if (ontology.confl(roleR) contains roleR) {
182 // Fresh Variables
183 val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom))
184 val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom))
185 val v2 = RSA.rsa("v2_" ++ RSA.hashed(axiom))
186 // Predicates
187 def atomA(t: Term): TupleTableAtom = {
188 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
189 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
190 }
191 def roleRf(t1: Term, t2: Term): TupleTableAtom = {
192 val visitor =
193 new RDFoxPropertyExprConverter(t1, t2, Forward)
194 roleR.accept(visitor).head
195 }
196 def atomB(t: Term): TupleTableAtom = {
197 val cls = axiom.getSuperClass
198 .asInstanceOf[OWLObjectSomeValuesFrom]
199 .getFiller
200 .asInstanceOf[OWLClass]
201 .getIRI
202 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
203 }
204 //Rules
205 List(
206 Rule.create(roleRf(v0, v1), atomA(v0)),
207 Rule.create(atomB(v1), atomA(v0)),
208 Rule.create(roleRf(v1, v2), atomA(v1)),
209 Rule.create(atomB(v2), atomA(v1))
210 )
211 } else {
212 List()
213 }
214 }
215
216 private def rules3(axiom: OWLSubClassOfAxiom): List[Rule] = {
217 val cycle = ontology.cycle(axiom).toList
218 val roleR =
219 axiom.getSuperClass
220 .asInstanceOf[OWLObjectSomeValuesFrom]
221 .getProperty
222 // Fresh Variables
223 val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom))
224 // Predicates
225 def atomA(t: Term): TupleTableAtom = {
226 val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI
227 TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls)
228 }
229 def roleRf(t: Term): TupleTableAtom = {
230 val visitor =
231 new RDFoxPropertyExprConverter(t, v1, Forward)
232 roleR.accept(visitor).head
233 }
234 val atomB: TupleTableAtom = {
235 val cls = axiom.getSuperClass
236 .asInstanceOf[OWLObjectSomeValuesFrom]
237 .getFiller
238 .asInstanceOf[OWLClass]
239 .getIRI
240 TupleTableAtom.rdf(v1, IRI.RDF_TYPE, cls)
241 }
242 cycle.flatMap { x =>
243 List(
244 Rule.create(roleRf(x), atomA(x)),
245 Rule.create(atomB, atomA(x))
246 )
247 }
248 }
249
250 override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = {
251 if (axiom.isT5) {
252 // TODO: get role in T5 axiom
253 // Assuming one role here
254 val role = axiom.objectPropertyExpressionsInSignature(0)
255 if (ontology.unsafeRoles contains role) {
256 val visitor =
257 new RDFoxAxiomConverter(
258 Variable.create("X"),
259 ontology.unsafeRoles,
260 SkolemStrategy.Standard(axiom.toString),
261 Forward
262 )
263 axiom.accept(visitor)
264 } else {
265 rules1(axiom) ::: rules2(axiom) ::: rules3(axiom)
266 }
267 } else {
268 // Fallback to standard OWL to LP translation
269 super.visit(axiom)
270 }
271 }
272
273 override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = {
274 val varX = Variable.create("X")
275 val visitorF = new RDFoxAxiomConverter(
276 varX,
277 ontology.unsafeRoles,
278 SkolemStrategy.None,
279 Forward
280 )
281 val visitorB = new RDFoxAxiomConverter(
282 varX,
283 ontology.unsafeRoles,
284 SkolemStrategy.None,
285 Backward
286 )
287 axiom.accept(visitorB) ::: axiom.accept(visitorF)
288 }
289
290 }
291
292}