diff options
author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-09-09 17:03:42 +0200 |
---|---|---|
committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-09-09 17:03:42 +0200 |
commit | e325a9c6282a4a98bf6799f8d04b3cbc6e56fca2 (patch) | |
tree | c069dba2a4a46a982a2753a0cca699051b6b437e /src | |
parent | 713fd36fb2bd4f71fc690a1ab3a3c1fce5b1a16f (diff) | |
download | RSAComb-e325a9c6282a4a98bf6799f8d04b3cbc6e56fca2.tar.gz RSAComb-e325a9c6282a4a98bf6799f8d04b3cbc6e56fca2.zip |
Move reifing code under `FilteringProgram` class
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/rsacomb/FilteringProgram.scala | 104 | ||||
-rw-r--r-- | src/main/scala/rsacomb/Main.scala | 2 | ||||
-rw-r--r-- | src/main/scala/rsacomb/RSAOntology.scala | 103 |
3 files changed, 96 insertions, 113 deletions
diff --git a/src/main/scala/rsacomb/FilteringProgram.scala b/src/main/scala/rsacomb/FilteringProgram.scala index 91c98d8..afa3f1e 100644 --- a/src/main/scala/rsacomb/FilteringProgram.scala +++ b/src/main/scala/rsacomb/FilteringProgram.scala | |||
@@ -5,17 +5,32 @@ import scala.collection.JavaConverters._ | |||
5 | 5 | ||
6 | class FilteringProgram(query: Query, constants: List[Term]) extends RDFTriple { | 6 | class FilteringProgram(query: Query, constants: List[Term]) extends RDFTriple { |
7 | 7 | ||
8 | /* Makes mplicit conversion OWLAPI IRI <-> RDFox IRI available */ | ||
9 | import RDFoxUtil._ | ||
10 | |||
8 | private val bounded: List[Term] = this.getBoundedVariables | 11 | private val bounded: List[Term] = this.getBoundedVariables |
9 | private val answer: List[Term] = query.getAnswerVariables.asScala.toList | 12 | private val answer: List[Term] = query.getAnswerVariables.asScala.toList |
10 | 13 | ||
11 | val facts: List[Atom] = constants.map(named) | 14 | val facts: List[Atom] = constants.map(named) |
12 | val rules: List[Rule] = this.generateFilteringProgram() | 15 | val rules: List[Rule] = this.generateFilteringProgram().map(reifyRule) |
13 | 16 | ||
14 | private def named(t: Term): Atom = | 17 | private def named(t: Term): Atom = |
15 | Atom.rdf(t, IRI.RDF_TYPE, RSA.internal("NAMED")) | 18 | Atom.rdf(t, IRI.RDF_TYPE, RSA.internal("NAMED")) |
16 | 19 | ||
17 | private def getBoundedVariables: List[Variable] = List() | 20 | private def getBoundedVariables: List[Variable] = List() |
18 | 21 | ||
22 | /* NOTE: we are restricting to queries that contain conjunctions of | ||
23 | * atoms for the time being. This might need to be reviewed in the | ||
24 | * future. | ||
25 | */ | ||
26 | private def queryToBody(body: Formula): List[Atom] = | ||
27 | body match { | ||
28 | case a: Atom => List(a); | ||
29 | case a: Conjunction => | ||
30 | a.getConjuncts.asScala.toList.flatMap(queryToBody); | ||
31 | case _ => List() | ||
32 | } | ||
33 | |||
19 | private def generateFilteringProgram(): List[Rule] = { | 34 | private def generateFilteringProgram(): List[Rule] = { |
20 | // Query formula as a rule body | 35 | // Query formula as a rule body |
21 | val body = queryToBody(query.getQueryFormula) | 36 | val body = queryToBody(query.getQueryFormula) |
@@ -275,21 +290,86 @@ class FilteringProgram(query: Query, constants: List[Term]) extends RDFTriple { | |||
275 | .prepended(r1) | 290 | .prepended(r1) |
276 | } | 291 | } |
277 | 292 | ||
278 | /* NOTE: we are restricting to queries that contain conjunctions of | 293 | private sealed trait Reified; |
279 | * atoms for the time being. This might need to be reviewed in the | 294 | private case class ReifiedHead(bind: BindAtom, atoms: List[Atom]) |
280 | * future. | 295 | extends Reified |
281 | */ | 296 | private case class ReifiedBody(atoms: List[Atom]) extends Reified |
282 | private def queryToBody(body: Formula): List[Atom] = | 297 | private case class Unaltered(formula: BodyFormula) extends Reified |
283 | body match { | 298 | |
284 | case a: Atom => List(a); | 299 | private def getBindAtom(atom: Atom): BindAtom = { |
285 | case a: Conjunction => | 300 | val newvar = RSA.getFreshVariable() |
286 | a.getConjuncts.asScala.toList.flatMap(queryToBody); | 301 | val name = |
287 | case _ => List() | 302 | Literal.create(atom.getTupleTableName.getIRI, Datatype.XSD_STRING) |
303 | val args = atom | ||
304 | .getArguments() | ||
305 | .asScala | ||
306 | .toSeq | ||
307 | .prepended(name) /* Unclear requirement for SKOLEM func calls */ | ||
308 | BindAtom.create( | ||
309 | BuiltinFunctionCall | ||
310 | .create("SKOLEM", args: _*), | ||
311 | newvar | ||
312 | ) | ||
313 | } | ||
314 | |||
315 | private def reifyAtom(atom: Atom, variable: Variable): List[Atom] = { | ||
316 | def iri(i: Int) = atom.getTupleTableName().getIRI() ++ s"_$i" | ||
317 | atom | ||
318 | .getArguments() | ||
319 | .asScala | ||
320 | .zipWithIndex | ||
321 | .map { case (t, i) => Atom.rdf(variable, iri(i), t) } | ||
322 | .toList | ||
323 | } | ||
324 | |||
325 | private def reifyBodyFormula( | ||
326 | formula: BodyFormula, | ||
327 | head: Boolean | ||
328 | ): Reified = { | ||
329 | formula match { | ||
330 | case a: Atom => { | ||
331 | if (!a.isRdfTriple) { | ||
332 | if (head) { | ||
333 | val b = getBindAtom(a) | ||
334 | ReifiedHead(b, reifyAtom(a, b.getBoundVariable)) | ||
335 | } else { | ||
336 | ReifiedBody(reifyAtom(a, RSA.getFreshVariable)) | ||
337 | } | ||
338 | } else { | ||
339 | Unaltered(a) | ||
340 | } | ||
341 | } | ||
342 | case a => Unaltered(a) | ||
343 | } | ||
344 | } | ||
345 | |||
346 | private def reifyRule(rule: Rule): Rule = { | ||
347 | // Rule body | ||
348 | val body = | ||
349 | rule.getBody.asScala.map(reifyBodyFormula(_, false)).flatMap { | ||
350 | case ReifiedHead(_, _) => List(); /* handle impossible case */ | ||
351 | case ReifiedBody(x) => x; | ||
352 | case Unaltered(x) => List(x) | ||
353 | } | ||
354 | // Rule head | ||
355 | val reified = rule.getHead.asScala.map(reifyBodyFormula(_, true)) | ||
356 | val skols = reified.flatMap { | ||
357 | case ReifiedHead(x, _) => Some(x); | ||
358 | case ReifiedBody(_) => None; /* handle impossible case */ | ||
359 | case Unaltered(_) => None | ||
288 | } | 360 | } |
361 | val head = reified.flatMap { | ||
362 | case ReifiedHead(_, x) => x; | ||
363 | case ReifiedBody(_) => List(); /* handle impossible case */ | ||
364 | case Unaltered(x) => | ||
365 | List(x.asInstanceOf[Atom]) /* Can we do better that a cast? */ | ||
366 | } | ||
367 | Rule.create(head.asJava, (skols ++ body).asJava) | ||
368 | } | ||
289 | 369 | ||
290 | } // class FilteringProgram | 370 | } // class FilteringProgram |
291 | 371 | ||
292 | object FilteringProgram { | 372 | object FilteringProgram { |
293 | def apply(query: Query, constants: List[Term]): FilteringProgram = | 373 | def apply(query: Query, constants: List[Term]): FilteringProgram = |
294 | new FilteringProgram(query, constants) | 374 | new FilteringProgram(query, constants) |
295 | } | 375 | } // object FilteringProgram |
diff --git a/src/main/scala/rsacomb/Main.scala b/src/main/scala/rsacomb/Main.scala index d2bc2a8..a449db4 100644 --- a/src/main/scala/rsacomb/Main.scala +++ b/src/main/scala/rsacomb/Main.scala | |||
@@ -57,7 +57,7 @@ object RSAComb { | |||
57 | val query = RSA.test_query | 57 | val query = RSA.test_query |
58 | 58 | ||
59 | /* Compute the filtering program from the given query */ | 59 | /* Compute the filtering program from the given query */ |
60 | val filter = ontology.getFilteringProgram(query) | 60 | val filter = ontology.filteringProgram(query) |
61 | 61 | ||
62 | /* ... */ | 62 | /* ... */ |
63 | 63 | ||
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala index efd6e7f..2f639eb 100644 --- a/src/main/scala/rsacomb/RSAOntology.scala +++ b/src/main/scala/rsacomb/RSAOntology.scala | |||
@@ -28,9 +28,7 @@ trait RSAOntology { | |||
28 | /* Implements additional features to reason about RSA ontologies | 28 | /* Implements additional features to reason about RSA ontologies |
29 | * on top of `OWLOntology` from the OWLAPI. | 29 | * on top of `OWLOntology` from the OWLAPI. |
30 | */ | 30 | */ |
31 | implicit class RSAOntology(ontology: OWLOntology) | 31 | implicit class RSAOntology(ontology: OWLOntology) extends RSAAxiom { |
32 | extends RSAAxiom | ||
33 | with RDFTriple { | ||
34 | 32 | ||
35 | /* Steps for RSA check | 33 | /* Steps for RSA check |
36 | * 1) convert ontology axioms into LP rules | 34 | * 1) convert ontology axioms into LP rules |
@@ -165,11 +163,6 @@ trait RSAOntology { | |||
165 | if roleSuper.contains(role2) || roleSuperInv.contains(role2) | 163 | if roleSuper.contains(role2) || roleSuperInv.contains(role2) |
166 | } yield role1 | 164 | } yield role1 |
167 | 165 | ||
168 | /* TODO: We should be able to avoid this last conversion to List. | ||
169 | * Maybe we should just move everything to Sets instead of Lists, | ||
170 | * since they have a more straightforward conversion from Java | ||
171 | * collections. | ||
172 | */ | ||
173 | (unsafe1 ++ unsafe2).toList | 166 | (unsafe1 ++ unsafe2).toList |
174 | } | 167 | } |
175 | 168 | ||
@@ -188,98 +181,8 @@ trait RSAOntology { | |||
188 | Graph(edges: _*) | 181 | Graph(edges: _*) |
189 | } | 182 | } |
190 | 183 | ||
191 | def getFilteringProgram(query: Query): List[Rule] = { | 184 | def filteringProgram(query: Query): List[Rule] = |
192 | 185 | FilteringProgram(query, List()).rules | |
193 | // Import implicit conversion to RDFox IRI | ||
194 | import RDFoxUtil._ | ||
195 | |||
196 | sealed trait Reified; | ||
197 | case class ReifiedHead(bind: BindAtom, atoms: List[Atom]) extends Reified | ||
198 | case class ReifiedBody(atoms: List[Atom]) extends Reified | ||
199 | case class Unaltered(formula: BodyFormula) extends Reified | ||
200 | |||
201 | def getBindAtom(atom: Atom): BindAtom = { | ||
202 | // TODO: We need to implement another way to introduce fresh | ||
203 | // variables. | ||
204 | val newvar = RSA.getFreshVariable() | ||
205 | val name = | ||
206 | Literal.create(atom.getTupleTableName.getIRI, Datatype.XSD_STRING) | ||
207 | val args = atom | ||
208 | .getArguments() | ||
209 | .asScala | ||
210 | .toSeq | ||
211 | .prepended(name) | ||
212 | BindAtom.create( | ||
213 | BuiltinFunctionCall | ||
214 | .create("SKOLEM", args: _*), | ||
215 | newvar | ||
216 | ) | ||
217 | } | ||
218 | |||
219 | def reifyAtom(atom: Atom, variable: Variable): List[Atom] = { | ||
220 | def iri(i: Int) = atom.getTupleTableName().getIRI() ++ s"_$i" | ||
221 | atom | ||
222 | .getArguments() | ||
223 | .asScala | ||
224 | .zipWithIndex | ||
225 | .map { case (t, i) => Atom.rdf(variable, iri(i), t) } | ||
226 | .toList | ||
227 | } | ||
228 | |||
229 | def reify( | ||
230 | formula: BodyFormula, | ||
231 | head: Boolean | ||
232 | ): Reified = { | ||
233 | def default[A <: BodyFormula](x: A) = Unaltered(x) | ||
234 | formula match { | ||
235 | case a: Atom => { | ||
236 | if (!a.isRdfTriple) { | ||
237 | if (head) { | ||
238 | val b = getBindAtom(a) | ||
239 | ReifiedHead(b, reifyAtom(a, b.getBoundVariable)) | ||
240 | } else { | ||
241 | val varA = RSA.getFreshVariable() | ||
242 | ReifiedBody(reifyAtom(a, varA)) | ||
243 | } | ||
244 | } else { | ||
245 | default(a) | ||
246 | } | ||
247 | } | ||
248 | case a => default(a) | ||
249 | } | ||
250 | } | ||
251 | |||
252 | def skolemizeRule(rule: Rule): Rule = { | ||
253 | // Rule body | ||
254 | val body = | ||
255 | rule.getBody.asScala.map(reify(_, false)).flatMap { | ||
256 | case ReifiedHead(_, _) => List(); /* handle impossible case */ | ||
257 | case ReifiedBody(x) => x; | ||
258 | case Unaltered(x) => List(x) | ||
259 | } | ||
260 | // Rule head | ||
261 | val reified = rule.getHead.asScala.map(reify(_, true)) | ||
262 | val skols = reified.flatMap { | ||
263 | case ReifiedHead(x, _) => Some(x); | ||
264 | case ReifiedBody(_) => None; /* handle impossible case */ | ||
265 | case Unaltered(_) => None | ||
266 | } | ||
267 | val head = reified.flatMap { | ||
268 | case ReifiedHead(_, x) => x; | ||
269 | case ReifiedBody(_) => List(); /* handle impossible case */ | ||
270 | case Unaltered(x) => | ||
271 | List(x.asInstanceOf[Atom]) /* Can we do better that a cast? */ | ||
272 | } | ||
273 | Rule.create(head.asJava, (skols ++ body).asJava) | ||
274 | } | ||
275 | |||
276 | // DEBUG | ||
277 | val rules = FilteringProgram(query, List()).rules | ||
278 | println("FILTERING PROGRAM:") | ||
279 | rules.map(skolemizeRule(_)).foreach(println(_)) | ||
280 | |||
281 | List() | ||
282 | } | ||
283 | 186 | ||
284 | } // implicit class RSAOntology | 187 | } // implicit class RSAOntology |
285 | 188 | ||