diff options
author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-18 19:13:25 +0000 |
---|---|---|
committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-18 19:13:25 +0000 |
commit | 1efc189e90240c162b54cbc50362b46786643dad (patch) | |
tree | 9beabe0a2af7ba1674aea0060787782aa72e8a83 /src/main/scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala | |
parent | a45aeff72b82bbc9a52f10929bf15b414c868525 (diff) | |
download | RSAComb-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.scala | 284 |
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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb | ||
2 | |||
3 | import org.semanticweb.owlapi.model.{OWLObjectInverseOf, OWLObjectProperty} | ||
4 | import org.semanticweb.owlapi.model.{ | ||
5 | OWLClass, | ||
6 | // OWLObjectProperty, | ||
7 | OWLSubObjectPropertyOfAxiom, | ||
8 | // OWLObjectPropertyExpression, | ||
9 | OWLObjectSomeValuesFrom, | ||
10 | OWLSubClassOfAxiom | ||
11 | } | ||
12 | |||
13 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
14 | Rule, | ||
15 | BodyFormula, | ||
16 | TupleTableAtom, | ||
17 | Negation | ||
18 | } | ||
19 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
20 | Term, | ||
21 | Variable, | ||
22 | // Resource, | ||
23 | IRI | ||
24 | } | ||
25 | |||
26 | import uk.ac.ox.cs.rsacomb.converter.{ | ||
27 | SkolemStrategy, | ||
28 | RDFoxAxiomConverter, | ||
29 | RDFoxPropertyExprConverter | ||
30 | } | ||
31 | import uk.ac.ox.cs.rsacomb.implicits.RSAAxiom | ||
32 | import uk.ac.ox.cs.rsacomb.suffix.{Empty, Forward, Backward, Inverse} | ||
33 | import uk.ac.ox.cs.rsacomb.util.RSA | ||
34 | |||
35 | class 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 | } | ||