diff options
| author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-09-07 13:08:31 +0200 |
|---|---|---|
| committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-09-07 13:08:31 +0200 |
| commit | 2b661f3ac6fdb5156168b6775ede24e4c7b53758 (patch) | |
| tree | 0e3514c38fedf41febff82e9bf93aea2ab4d7a7f /src/main/scala/rsacomb/RSAOntology.scala | |
| parent | 7e126824e9a6cb456295d2f1535aef975bb63237 (diff) | |
| download | RSAComb-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.scala | 165 |
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 */ |
| 21 | import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer | 21 | import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer |
| 22 | import 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 |
