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