aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/rsacomb/RSAOntology.scala
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2020-09-07 13:08:31 +0200
committerFederico Igne <federico.igne@cs.ox.ac.uk>2020-09-07 13:08:31 +0200
commit2b661f3ac6fdb5156168b6775ede24e4c7b53758 (patch)
tree0e3514c38fedf41febff82e9bf93aea2ab4d7a7f /src/main/scala/rsacomb/RSAOntology.scala
parent7e126824e9a6cb456295d2f1535aef975bb63237 (diff)
downloadRSAComb-2b661f3ac6fdb5156168b6775ede24e4c7b53758.tar.gz
RSAComb-2b661f3ac6fdb5156168b6775ede24e4c7b53758.zip
Add setup code to compute the RSA filtering program
Not all rules of the filtering program have been implemented, but the code for the generation and reification of the rules seems to work.
Diffstat (limited to 'src/main/scala/rsacomb/RSAOntology.scala')
-rw-r--r--src/main/scala/rsacomb/RSAOntology.scala165
1 files changed, 163 insertions, 2 deletions
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala
index 3d9210e..9d52612 100644
--- a/src/main/scala/rsacomb/RSAOntology.scala
+++ b/src/main/scala/rsacomb/RSAOntology.scala
@@ -19,6 +19,7 @@ import scalax.collection.GraphEdge.UnDiEdge
19 19
20/* Debug only */ 20/* Debug only */
21import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer 21import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer
22import tech.oxfordsemantic.jrdfox.logic._
22 23
23/* Wrapper trait for the implicit class `RSAOntology`. 24/* Wrapper trait for the implicit class `RSAOntology`.
24 */ 25 */
@@ -163,8 +164,9 @@ trait RSAOntology {
163 } yield role1 164 } yield role1
164 165
165 /* TODO: We should be able to avoid this last conversion to List. 166 /* TODO: We should be able to avoid this last conversion to List.
166 * Maybe we should just move everything to Sets instead of Lists, since 167 * Maybe we should just move everything to Sets instead of Lists,
167 * they have a more straightforward conversion from Java collections. 168 * since they have a more straightforward conversion from Java
169 * collections.
168 */ 170 */
169 (unsafe1 ++ unsafe2).toList 171 (unsafe1 ++ unsafe2).toList
170 } 172 }
@@ -184,6 +186,165 @@ trait RSAOntology {
184 Graph(edges: _*) 186 Graph(edges: _*)
185 } 187 }
186 188
189 def getFilteringProgram(query: Query): List[Rule] = {
190
191 // Import implicit conversion to RDFox IRI
192 import RDFoxUtil._
193
194 sealed trait Reified;
195 case class ReifiedHead(bind: BindAtom, atoms: List[Atom]) extends Reified
196 case class ReifiedBody(atoms: List[Atom]) extends Reified
197 case class Unaltered(formula: BodyFormula) extends Reified
198
199 def getBindAtom(atom: Atom): BindAtom = {
200 // TODO: We need to implement another way to introduce fresh
201 // variables.
202 val varA = Variable.create("A")
203 val args = atom
204 .getArguments()
205 .asScala
206 .toSeq
207 //.prepended(atom.getTupleTableName.getIRI)
208 BindAtom.create(
209 BuiltinFunctionCall
210 .create("SKOLEM", args: _*),
211 varA
212 )
213 }
214
215 def reifyAtom(atom: Atom, variable: Variable): List[Atom] = {
216 def iri(i: Int) = atom.getTupleTableName().getIRI() ++ s"_$i"
217 atom
218 .getArguments()
219 .asScala
220 .zipWithIndex
221 .map { case (t, i) => Atom.rdf(variable, iri(i), t) }
222 .toList
223 }
224
225 // Is this the best way to determine if an atom is an RDF triple?
226 // Note that we can't use `getNumberOfArguments()` because is not
227 // "consistent":
228 // - for an atom created with `rdf(<term1>, <term2>, <term3>)`,
229 // `getNumberOfArguments` returns 3
230 // - for an atom created with `Atom.create(<tupletablename>, <term1>,
231 // <term2>, <term3>)`, `getNumberOfArguments()` returns 3
232 //
233 // This is probably because `Atom.rdf(...) is implemented as:
234 // ```scala
235 // def rdf(term1: Term, term2: Term, term3: Term): Atom =
236 // Atom.create(TupleTableName.create("internal:triple"), term1, term2, term3)
237 // ```
238 def isRdfTriple(atom: Atom): Boolean =
239 atom.getTupleTableName.getIRI.equals("internal:triple")
240
241 def reify(
242 formula: BodyFormula,
243 head: Boolean
244 ): Reified = {
245 def default[A <: BodyFormula](x: A) = Unaltered(x)
246 formula match {
247 case a: Atom => {
248 if (!isRdfTriple(a)) {
249 if (head) {
250 val b = getBindAtom(a)
251 ReifiedHead(b, reifyAtom(a, b.getBoundVariable))
252 } else {
253 val varA = Variable.create("A")
254 ReifiedBody(reifyAtom(a, varA))
255 }
256 } else {
257 default(a)
258 }
259 }
260 case a => default(a)
261 }
262 }
263
264 def skolemizeRule(rule: Rule): Rule = {
265 // Rule body
266 val body =
267 rule.getBody.asScala.map(reify(_, false)).flatMap {
268 case ReifiedHead(_, _) => List(); /* handle impossible case */
269 case ReifiedBody(x) => x;
270 case Unaltered(x) => List(x)
271 }
272 // Rule head
273 val reified = rule.getHead.asScala.map(reify(_, true))
274 val skols = reified.flatMap {
275 case ReifiedHead(x, _) => Some(x);
276 case ReifiedBody(_) => None; /* handle impossible case */
277 case Unaltered(_) => None
278 }
279 val head = reified.flatMap {
280 case ReifiedHead(_, x) => x;
281 case ReifiedBody(_) => List(); /* handle impossible case */
282 case Unaltered(x) =>
283 List(x.asInstanceOf[Atom]) /* Can we do better that a cast? */
284 }
285 Rule.create(head.asJava, (skols ++ body).asJava)
286 }
287
288 def formulaToRuleBody(body: Formula): List[BodyFormula] = {
289 body match {
290 case a: BodyFormula => List(a);
291 case a: Conjunction =>
292 a.getConjuncts().asScala.toList.flatMap(formulaToRuleBody(_));
293 case _ => List() /* We don't handle this for now */
294 }
295 }
296
297 val body = formulaToRuleBody(query.getQueryFormula)
298 val vars: List[Term] = query.getAnswerVariables.asScala.toList
299 def id(t1: Term, t2: Term) =
300 Atom.create(
301 TupleTableName.create("http://127.0.0.1/ID"),
302 vars.appendedAll(List(t1, t2)).asJava
303 )
304 val qm = Atom.create(TupleTableName.create("QM"), vars.asJava)
305
306 /* Filtering program */
307 val rule1 = Rule.create(qm, body.asJava)
308 val rule3a =
309 for ((v, i) <- vars.zipWithIndex)
310 yield Rule.create(
311 id(
312 IRI.create(s"http://127.0.0.1/$i"),
313 IRI.create(s"http://127.0.0.1/$i")
314 ),
315 List(
316 qm,
317 Negation.create(
318 Atom.rdf(v, IRI.RDF_TYPE, IRI.create("http://127.0.0.1/NI"))
319 )
320 ).asJava
321 )
322 val rule3b = Rule.create(
323 id(Variable.create("V"), Variable.create("U")),
324 id(Variable.create("U"), Variable.create("V"))
325 )
326 val rule3c = Rule.create(
327 id(Variable.create("U"), Variable.create("W")),
328 List[BodyFormula](
329 id(Variable.create("U"), Variable.create("V")),
330 id(Variable.create("V"), Variable.create("W"))
331 ).asJava
332 )
333
334 var rules: List[Rule] =
335 List.empty
336 .prepended(rule3c)
337 .prepended(rule3b)
338 .prependedAll(rule3a)
339 .prepended(rule1)
340
341 // DEBUG
342 println("FILTERING PROGRAM:")
343 rules.map(skolemizeRule(_)).foreach(println(_))
344
345 List()
346 }
347
187 } // implicit class RSAOntology 348 } // implicit class RSAOntology
188 349
189} // trait RSAOntology 350} // trait RSAOntology