diff options
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 | ||
