diff options
| author | Federico Igne <git@federicoigne.com> | 2021-10-02 09:15:43 +0100 |
|---|---|---|
| committer | Federico Igne <git@federicoigne.com> | 2021-10-02 09:15:43 +0100 |
| commit | 424d5d6fcabb410622907c095364903577014765 (patch) | |
| tree | 4025b3136572e40ce619affcf94def09ae186be7 /src/main/scala | |
| parent | 360e10e686d144b918825939f48004aebc31b7f3 (diff) | |
| download | RSAComb-424d5d6fcabb410622907c095364903577014765.tar.gz RSAComb-424d5d6fcabb410622907c095364903577014765.zip | |
Rework revides filtering program computation to use named graphs
Diffstat (limited to 'src/main/scala')
7 files changed, 254 insertions, 262 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala index 6a3dca2..993e9df 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | |||
| @@ -545,7 +545,7 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) | |||
| 545 | RDFoxUtil.addFacts( | 545 | RDFoxUtil.addFacts( |
| 546 | data, | 546 | data, |
| 547 | RSAOntology.CanonGraph, | 547 | RSAOntology.CanonGraph, |
| 548 | (individuals ++ literals) map RSA.Named | 548 | (individuals ++ literals) map RSA.Named(RSAOntology.CanonGraph) |
| 549 | ) | 549 | ) |
| 550 | data.evaluateUpdate( | 550 | data.evaluateUpdate( |
| 551 | null, // the base IRI for the query (if null, a default is used) | 551 | null, // the base IRI for the query (if null, a default is used) |
| @@ -569,13 +569,12 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) | |||
| 569 | 569 | ||
| 570 | queries map { query => | 570 | queries map { query => |
| 571 | { | 571 | { |
| 572 | //val graph = RSAOntology.FilterGraph(query) | ||
| 573 | val filter = RSAOntology.filteringProgram(query) | 572 | val filter = RSAOntology.filteringProgram(query) |
| 573 | |||
| 574 | /* Add filtering program */ | 574 | /* Add filtering program */ |
| 575 | Logger print s"Filtering program rules: ${filter.rules.length}" | 575 | Logger print s"Filtering program rules: ${filter.rules.length}" |
| 576 | RDFoxUtil.addRules(data, filter.rules) | 576 | RDFoxUtil.addRules(data, filter.rules) |
| 577 | 577 | // TODO: We remove the rules, should we drop the tuple table as well? | |
| 578 | // We remove the rules, should we drop the tuple table as well? | ||
| 579 | data.clearRulesAxiomsExplicateFacts() | 578 | data.clearRulesAxiomsExplicateFacts() |
| 580 | 579 | ||
| 581 | /* Gather answers to the query */ | 580 | /* Gather answers to the query */ |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala index 1777713..6174c9d 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala | |||
| @@ -32,7 +32,7 @@ import tech.oxfordsemantic.jrdfox.logic.expression.{ | |||
| 32 | Variable | 32 | Variable |
| 33 | } | 33 | } |
| 34 | import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery | 34 | import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery |
| 35 | import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward, Nth} | 35 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Forward, Backward, Nth} |
| 36 | import uk.ac.ox.cs.rsacomb.util.{DataFactory, RSA, RDFoxUtil} | 36 | import uk.ac.ox.cs.rsacomb.util.{DataFactory, RSA, RDFoxUtil} |
| 37 | 37 | ||
| 38 | /** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ | 38 | /** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ |
| @@ -95,10 +95,41 @@ class NaiveFilteringProgram( | |||
| 95 | 95 | ||
| 96 | /** `TupleTableName`s for the source/targer named graphs */ | 96 | /** `TupleTableName`s for the source/targer named graphs */ |
| 97 | val tts: TupleTableName = TupleTableName.create(source.getIRI) | 97 | val tts: TupleTableName = TupleTableName.create(source.getIRI) |
| 98 | implicit val ttt: TupleTableName = TupleTableName.create(target.getIRI) | 98 | val ttt: TupleTableName = TupleTableName.create(target.getIRI) |
| 99 | 99 | ||
| 100 | /** Set of atoms in the body of the query */ | 100 | /** Set of atoms in the body of the query */ |
| 101 | val queryBody: List[TupleTableAtom] = query.atoms(tts) | 101 | private val queryBody: List[TupleTableAtom] = query.atoms(tts) |
| 102 | |||
| 103 | /** Helpers */ | ||
| 104 | private def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) | ||
| 105 | |||
| 106 | private val QM: TupleTableAtom = | ||
| 107 | TupleTableAtom.create(ttt, RSA.QM :: query.answer ::: query.bounded) | ||
| 108 | private def ID(t1: Term, t2: Term) = | ||
| 109 | TupleTableAtom.create( | ||
| 110 | ttt, | ||
| 111 | RSA.ID +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 112 | ) | ||
| 113 | private def NI(term: Term) = | ||
| 114 | TupleTableAtom.create(ttt, term, IRI.RDF_TYPE, RSA.NI) | ||
| 115 | private def TQ(sx: RSASuffix, t1: Term, t2: Term) = | ||
| 116 | TupleTableAtom.create( | ||
| 117 | ttt, | ||
| 118 | (RSA.TQ :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 119 | ) | ||
| 120 | private def AQ(sx: RSASuffix, t1: Term, t2: Term) = | ||
| 121 | TupleTableAtom.create( | ||
| 122 | ttt, | ||
| 123 | (RSA.AQ :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 124 | ) | ||
| 125 | private val FK: TupleTableAtom = | ||
| 126 | TupleTableAtom.create(ttt, RSA.FK :: query.answer ::: query.bounded) | ||
| 127 | private val SP: TupleTableAtom = | ||
| 128 | TupleTableAtom.create(ttt, RSA.SP :: query.answer ::: query.bounded) | ||
| 129 | private def Ans = if (query.bcq) | ||
| 130 | TupleTableAtom.create(ttt, RSA("blank"), IRI.RDF_TYPE, RSA.ANS) | ||
| 131 | else | ||
| 132 | TupleTableAtom.create(ttt, RSA.ANS :: query.answer) | ||
| 102 | 133 | ||
| 103 | /** Rule generating the instances of the predicate `rsa:NI`. | 134 | /** Rule generating the instances of the predicate `rsa:NI`. |
| 104 | * | 135 | * |
| @@ -117,23 +148,20 @@ class NaiveFilteringProgram( | |||
| 117 | */ | 148 | */ |
| 118 | val nis: Rule = | 149 | val nis: Rule = |
| 119 | Rule.create( | 150 | Rule.create( |
| 120 | RSA.NI(varX), | 151 | NI(varX), |
| 121 | RSA.Congruent(varX, varY)(tts), | 152 | RSA.Congruent(tts)(varX, varY), |
| 122 | RSA.Named(varY)(tts) | 153 | RSA.Named(tts)(varY) |
| 123 | ) | 154 | ) |
| 124 | 155 | ||
| 125 | /** Collection of filtering program rules. */ | 156 | /** Collection of filtering program rules. */ |
| 126 | val rules: List[Rule] = | 157 | val rules: List[Rule] = |
| 127 | nis :: { | 158 | nis :: { |
| 128 | 159 | ||
| 129 | /** Negates a [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]] */ | ||
| 130 | def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) | ||
| 131 | |||
| 132 | /** Generates all possible, unfiltered answers. | 160 | /** Generates all possible, unfiltered answers. |
| 133 | * | 161 | * |
| 134 | * @note corresponds to rule 1 in Table 3 in the paper. | 162 | * @note corresponds to rule 1 in Table 3 in the paper. |
| 135 | */ | 163 | */ |
| 136 | val r1 = Rule.create(RSA.QM, queryBody: _*) | 164 | val r1 = Rule.create(QM, queryBody: _*) |
| 137 | 165 | ||
| 138 | /** Initializes instances of `rsa:ID`. | 166 | /** Initializes instances of `rsa:ID`. |
| 139 | * | 167 | * |
| @@ -145,10 +173,10 @@ class NaiveFilteringProgram( | |||
| 145 | */ | 173 | */ |
| 146 | val r3a = | 174 | val r3a = |
| 147 | for ((v, i) <- query.bounded.zipWithIndex) | 175 | for ((v, i) <- query.bounded.zipWithIndex) |
| 148 | yield Rule.create(RSA.ID(RSA(i), RSA(i)), RSA.QM, not(RSA.NI(v))) | 176 | yield Rule.create(ID(RSA(i), RSA(i)), QM, not(NI(v))) |
| 149 | val r3b = Rule.create(RSA.ID(varV, varU), RSA.ID(varU, varV)) | 177 | val r3b = Rule.create(ID(varV, varU), ID(varU, varV)) |
| 150 | val r3c = | 178 | val r3c = |
| 151 | Rule.create(RSA.ID(varU, varW), RSA.ID(varU, varV), RSA.ID(varV, varW)) | 179 | Rule.create(ID(varU, varW), ID(varU, varV), ID(varV, varW)) |
| 152 | 180 | ||
| 153 | /** Detects forks in the canonical model. | 181 | /** Detects forks in the canonical model. |
| 154 | * | 182 | * |
| @@ -162,10 +190,10 @@ class NaiveFilteringProgram( | |||
| 162 | index2 = query.bounded indexOf (role2.getArguments get 2) | 190 | index2 = query.bounded indexOf (role2.getArguments get 2) |
| 163 | if index2 >= 0 | 191 | if index2 >= 0 |
| 164 | } yield Rule.create( | 192 | } yield Rule.create( |
| 165 | RSA.FK, | 193 | FK, |
| 166 | RSA.ID(RSA(index1), RSA(index2)), | 194 | ID(RSA(index1), RSA(index2)), |
| 167 | role1 << Forward, | 195 | role1 :: Forward, |
| 168 | role2 << Forward, | 196 | role2 :: Forward, |
| 169 | not( | 197 | not( |
| 170 | TupleTableAtom.create( | 198 | TupleTableAtom.create( |
| 171 | tts, | 199 | tts, |
| @@ -183,10 +211,10 @@ class NaiveFilteringProgram( | |||
| 183 | index2 = query.bounded indexOf (role2.getArguments get 0) | 211 | index2 = query.bounded indexOf (role2.getArguments get 0) |
| 184 | if index2 >= 0 | 212 | if index2 >= 0 |
| 185 | } yield Rule.create( | 213 | } yield Rule.create( |
| 186 | RSA.FK, | 214 | FK, |
| 187 | RSA.ID(RSA(index1), RSA(index2)), | 215 | ID(RSA(index1), RSA(index2)), |
| 188 | role1 << Forward, | 216 | role1 :: Forward, |
| 189 | role2 << Backward, | 217 | role2 :: Backward, |
| 190 | not( | 218 | not( |
| 191 | TupleTableAtom.create( | 219 | TupleTableAtom.create( |
| 192 | tts, | 220 | tts, |
| @@ -204,10 +232,10 @@ class NaiveFilteringProgram( | |||
| 204 | index2 = query.bounded indexOf (role2.getArguments get 0) | 232 | index2 = query.bounded indexOf (role2.getArguments get 0) |
| 205 | if index2 >= 0 | 233 | if index2 >= 0 |
| 206 | } yield Rule.create( | 234 | } yield Rule.create( |
| 207 | RSA.FK, | 235 | FK, |
| 208 | RSA.ID(RSA(index1), RSA(index2)), | 236 | ID(RSA(index1), RSA(index2)), |
| 209 | role1 << Backward, | 237 | role1 :: Backward, |
| 210 | role2 << Backward, | 238 | role2 :: Backward, |
| 211 | not( | 239 | not( |
| 212 | TupleTableAtom.create( | 240 | TupleTableAtom.create( |
| 213 | tts, | 241 | tts, |
| @@ -234,18 +262,18 @@ class NaiveFilteringProgram( | |||
| 234 | r2arg2 = role2.getArguments get 2 | 262 | r2arg2 = role2.getArguments get 2 |
| 235 | if query.bounded contains r2arg2 | 263 | if query.bounded contains r2arg2 |
| 236 | } yield Rule.create( | 264 | } yield Rule.create( |
| 237 | RSA.ID( | 265 | ID( |
| 238 | RSA(query.bounded indexOf r1arg0), | 266 | RSA(query.bounded indexOf r1arg0), |
| 239 | RSA(query.bounded indexOf r2arg0) | 267 | RSA(query.bounded indexOf r2arg0) |
| 240 | ), | 268 | ), |
| 241 | RSA.ID( | 269 | ID( |
| 242 | RSA(query.bounded indexOf r1arg2), | 270 | RSA(query.bounded indexOf r1arg2), |
| 243 | RSA(query.bounded indexOf r2arg2) | 271 | RSA(query.bounded indexOf r2arg2) |
| 244 | ), | 272 | ), |
| 245 | TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg0), | 273 | TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg0), |
| 246 | role1 << Forward, | 274 | role1 :: Forward, |
| 247 | role2 << Forward, | 275 | role2 :: Forward, |
| 248 | not(RSA.NI(r1arg0)) | 276 | not(NI(r1arg0)) |
| 249 | ) | 277 | ) |
| 250 | val r5b = for { | 278 | val r5b = for { |
| 251 | role1 <- queryBody filter (_.isRoleAssertion) | 279 | role1 <- queryBody filter (_.isRoleAssertion) |
| @@ -259,18 +287,18 @@ class NaiveFilteringProgram( | |||
| 259 | r2arg2 = role2.getArguments get 2 | 287 | r2arg2 = role2.getArguments get 2 |
| 260 | if query.bounded contains r2arg2 | 288 | if query.bounded contains r2arg2 |
| 261 | } yield Rule.create( | 289 | } yield Rule.create( |
| 262 | RSA.ID( | 290 | ID( |
| 263 | RSA(query.bounded indexOf r1arg0), | 291 | RSA(query.bounded indexOf r1arg0), |
| 264 | RSA(query.bounded indexOf r2arg2) | 292 | RSA(query.bounded indexOf r2arg2) |
| 265 | ), | 293 | ), |
| 266 | RSA.ID( | 294 | ID( |
| 267 | RSA(query.bounded indexOf r1arg2), | 295 | RSA(query.bounded indexOf r1arg2), |
| 268 | RSA(query.bounded indexOf r2arg0) | 296 | RSA(query.bounded indexOf r2arg0) |
| 269 | ), | 297 | ), |
| 270 | TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg2), | 298 | TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg2), |
| 271 | role1 << Forward, | 299 | role1 :: Forward, |
| 272 | role2 << Backward, | 300 | role2 :: Backward, |
| 273 | not(RSA.NI(r1arg0)) | 301 | not(NI(r1arg0)) |
| 274 | ) | 302 | ) |
| 275 | val r5c = for { | 303 | val r5c = for { |
| 276 | role1 <- queryBody filter (_.isRoleAssertion) | 304 | role1 <- queryBody filter (_.isRoleAssertion) |
| @@ -284,18 +312,18 @@ class NaiveFilteringProgram( | |||
| 284 | r2arg2 = role2.getArguments get 2 | 312 | r2arg2 = role2.getArguments get 2 |
| 285 | if query.bounded contains r2arg2 | 313 | if query.bounded contains r2arg2 |
| 286 | } yield Rule.create( | 314 | } yield Rule.create( |
| 287 | RSA.ID( | 315 | ID( |
| 288 | RSA(query.bounded indexOf r1arg2), | 316 | RSA(query.bounded indexOf r1arg2), |
| 289 | RSA(query.bounded indexOf r2arg2) | 317 | RSA(query.bounded indexOf r2arg2) |
| 290 | ), | 318 | ), |
| 291 | RSA.ID( | 319 | ID( |
| 292 | RSA(query.bounded indexOf r1arg0), | 320 | RSA(query.bounded indexOf r1arg0), |
| 293 | RSA(query.bounded indexOf r2arg0) | 321 | RSA(query.bounded indexOf r2arg0) |
| 294 | ), | 322 | ), |
| 295 | TupleTableAtom.create(tts, r1arg2, RSA.CONGRUENT, r2arg2), | 323 | TupleTableAtom.create(tts, r1arg2, RSA.CONGRUENT, r2arg2), |
| 296 | role1 << Backward, | 324 | role1 :: Backward, |
| 297 | role2 << Backward, | 325 | role2 :: Backward, |
| 298 | not(RSA.NI(r1arg2)) | 326 | not(NI(r1arg2)) |
| 299 | ) | 327 | ) |
| 300 | 328 | ||
| 301 | /** Detect cycles in the canonical model. | 329 | /** Detect cycles in the canonical model. |
| @@ -314,23 +342,23 @@ class NaiveFilteringProgram( | |||
| 314 | if index2 >= 0 | 342 | if index2 >= 0 |
| 315 | suffix <- Seq(Forward, Backward) | 343 | suffix <- Seq(Forward, Backward) |
| 316 | } yield Rule.create( | 344 | } yield Rule.create( |
| 317 | RSA.AQ(suffix, varV, varW), | 345 | AQ(suffix, varV, varW), |
| 318 | role << suffix, | 346 | role :: suffix, |
| 319 | RSA.ID(RSA(index0), varV), | 347 | ID(RSA(index0), varV), |
| 320 | RSA.ID(RSA(index2), varW) | 348 | ID(RSA(index2), varW) |
| 321 | ) | 349 | ) |
| 322 | val r7a = | 350 | val r7a = |
| 323 | for (suffix <- List(Forward, Backward)) | 351 | for (suffix <- List(Forward, Backward)) |
| 324 | yield Rule.create( | 352 | yield Rule.create( |
| 325 | RSA.TQ(suffix, varU, varV), | 353 | TQ(suffix, varU, varV), |
| 326 | RSA.AQ(suffix, varU, varV) | 354 | AQ(suffix, varU, varV) |
| 327 | ) | 355 | ) |
| 328 | val r7b = | 356 | val r7b = |
| 329 | for (suffix <- List(Forward, Backward)) | 357 | for (suffix <- List(Forward, Backward)) |
| 330 | yield Rule.create( | 358 | yield Rule.create( |
| 331 | RSA.TQ(suffix, varU, varW), | 359 | TQ(suffix, varU, varW), |
| 332 | RSA.AQ(suffix, varU, varV), | 360 | AQ(suffix, varU, varV), |
| 333 | RSA.TQ(suffix, varV, varW) | 361 | TQ(suffix, varV, varW) |
| 334 | ) | 362 | ) |
| 335 | 363 | ||
| 336 | /** Flag spurious answers. | 364 | /** Flag spurious answers. |
| @@ -340,19 +368,14 @@ class NaiveFilteringProgram( | |||
| 340 | val r8a = | 368 | val r8a = |
| 341 | for (v <- query.answer) | 369 | for (v <- query.answer) |
| 342 | yield Rule.create( | 370 | yield Rule.create( |
| 343 | RSA.SP, | 371 | SP, |
| 344 | RSA.QM, | 372 | QM, |
| 345 | not( | 373 | not(TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED)) |
| 346 | TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED) | ||
| 347 | ) | ||
| 348 | ) | 374 | ) |
| 349 | val r8b = Rule.create(RSA.SP, RSA.FK) | 375 | val r8b = Rule.create(SP, FK) |
| 350 | val r8c = | 376 | val r8c = |
| 351 | for (suffix <- List(Forward, Backward)) | 377 | for (suffix <- List(Forward, Backward)) |
| 352 | yield Rule.create( | 378 | yield Rule.create(SP, TQ(suffix, varV, varV)) |
| 353 | RSA.SP, | ||
| 354 | RSA.TQ(suffix, varV, varV) | ||
| 355 | ) | ||
| 356 | 379 | ||
| 357 | /** Determine answers to the query | 380 | /** Determine answers to the query |
| 358 | * | 381 | * |
| @@ -369,7 +392,7 @@ class NaiveFilteringProgram( | |||
| 369 | * | 392 | * |
| 370 | * @note corresponds to rule 9 in Table 3. | 393 | * @note corresponds to rule 9 in Table 3. |
| 371 | */ | 394 | */ |
| 372 | val r9 = Rule.create(RSA.Ans, RSA.QM, not(RSA.SP)) | 395 | val r9 = Rule.create(Ans, QM, not(SP)) |
| 373 | 396 | ||
| 374 | (r1 :: | 397 | (r1 :: |
| 375 | r3a ::: r3b :: r3c :: | 398 | r3a ::: r3b :: r3c :: |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala index 5d11369..f059bcd 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala | |||
| @@ -54,8 +54,12 @@ object RevisedFilteringProgram { | |||
| 54 | * | 54 | * |
| 55 | * @param query CQ to be converted into logic rules. | 55 | * @param query CQ to be converted into logic rules. |
| 56 | */ | 56 | */ |
| 57 | def apply(query: ConjunctiveQuery): RevisedFilteringProgram = | 57 | def apply( |
| 58 | new RevisedFilteringProgram(query) | 58 | source: IRI, |
| 59 | target: IRI, | ||
| 60 | query: ConjunctiveQuery | ||
| 61 | ): RevisedFilteringProgram = | ||
| 62 | new RevisedFilteringProgram(source, target, query) | ||
| 59 | 63 | ||
| 60 | } | 64 | } |
| 61 | 65 | ||
| @@ -66,8 +70,11 @@ object RevisedFilteringProgram { | |||
| 66 | * | 70 | * |
| 67 | * Instances can be created using the companion object. | 71 | * Instances can be created using the companion object. |
| 68 | */ | 72 | */ |
| 69 | class RevisedFilteringProgram(val query: ConjunctiveQuery) | 73 | class RevisedFilteringProgram( |
| 70 | extends FilteringProgram { | 74 | val source: IRI, |
| 75 | val target: IRI, | ||
| 76 | val query: ConjunctiveQuery | ||
| 77 | ) extends FilteringProgram { | ||
| 71 | 78 | ||
| 72 | import RDFoxDSL._ | 79 | import RDFoxDSL._ |
| 73 | 80 | ||
| @@ -76,45 +83,47 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 76 | */ | 83 | */ |
| 77 | import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._ | 84 | import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._ |
| 78 | 85 | ||
| 86 | /** Simplify conversion between Java and Scala `List`s */ | ||
| 87 | import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ | ||
| 88 | |||
| 79 | /** Implicit parameter used in RSA internal predicates. | 89 | /** Implicit parameter used in RSA internal predicates. |
| 80 | * | 90 | * |
| 81 | * @see [[uk.ac.ox.cs.rsacomb.util.RSA]] for more information. | 91 | * @see [[uk.ac.ox.cs.rsacomb.util.RSA]] for more information. |
| 82 | */ | 92 | */ |
| 83 | implicit private[this] val _query = query | 93 | implicit private[this] val _query = query |
| 84 | 94 | ||
| 85 | /** Helpers */ | 95 | /** `TupleTableName`s for the source/targer named graphs */ |
| 96 | val tts: TupleTableName = TupleTableName.create(source.getIRI) | ||
| 97 | val ttt: TupleTableName = TupleTableName.create(target.getIRI) | ||
| 98 | |||
| 99 | /** Set of atoms in the body of the query */ | ||
| 100 | private val queryBody: List[TupleTableAtom] = query.atoms(tts) | ||
| 86 | 101 | ||
| 87 | //private def v(name: String): Term = Variable.create(s"${name}i") | 102 | /** Helpers */ |
| 88 | private def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) | 103 | private def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) |
| 89 | 104 | ||
| 90 | private def named(x: Term): TupleTableAtom = | ||
| 91 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA.NAMED) | ||
| 92 | private def congruent(x: Term, y: Term): TupleTableAtom = | ||
| 93 | TupleTableAtom.rdf(x, RSA.CONGRUENT, y) | ||
| 94 | private def skolem(skolem: Term, terms: List[Term]): TupleTableAtom = | ||
| 95 | TupleTableAtom.create(TupleTableName.SKOLEM, (terms :+ skolem): _*) | ||
| 96 | private def QM(x: Term): TupleTableAtom = | 105 | private def QM(x: Term): TupleTableAtom = |
| 97 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("QM")) | 106 | TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.QM) |
| 98 | private def FK(x: Term): TupleTableAtom = | 107 | private def FK(x: Term): TupleTableAtom = |
| 99 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("FK")) | 108 | TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.FK) |
| 100 | private def SP(x: Term): TupleTableAtom = | 109 | private def SP(x: Term): TupleTableAtom = |
| 101 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("SP")) | 110 | TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.SP) |
| 102 | private def NI(x: Term): TupleTableAtom = | 111 | private def NI(x: Term): TupleTableAtom = |
| 103 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("NI")) | 112 | TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.NI) |
| 104 | private def Ans(x: Term): TupleTableAtom = | 113 | private def Ans(x: Term): TupleTableAtom = |
| 105 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("Ans")) | 114 | TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.ANS) |
| 106 | private def ID(x: Term, y: Term): TupleTableAtom = | 115 | private def ID(x: Term, y: Term): TupleTableAtom = |
| 107 | TupleTableAtom.rdf(x, RSA("ID"), y) | 116 | TupleTableAtom.create(ttt, x, RSA.ID, y) |
| 108 | private def AQ(suffix: RSASuffix, x: Term, y: Term): TupleTableAtom = | 117 | private def AQ(suffix: RSASuffix)(x: Term, y: Term): TupleTableAtom = |
| 109 | TupleTableAtom.rdf(x, RSA("AQ"), y) << suffix | 118 | TupleTableAtom.create(ttt, x, RSA.AQ :: suffix, y) |
| 110 | private def TQ(suffix: RSASuffix, x: Term, y: Term): TupleTableAtom = | 119 | private def TQ(suffix: RSASuffix)(x: Term, y: Term): TupleTableAtom = |
| 111 | TupleTableAtom.rdf(x, RSA("TQ"), y) << suffix | 120 | TupleTableAtom.create(ttt, x, RSA.TQ :: suffix, y) |
| 112 | 121 | ||
| 113 | /** Rule generating the instances of the predicate `rsa:NI`. | 122 | /** Rule generating the instances of the predicate `rsa:NI`. |
| 114 | * | 123 | * |
| 115 | * According to the original paper, the set of `rsa:NI` is defined as | 124 | * According to the original paper, the set of `rsa:NI` is defined as |
| 116 | * the set of constants that are equal (w.r.t. the congruence | 125 | * the set of constants that are equal (w.r.t. the congruence |
| 117 | * relation represented by `rsa:Congruent`) to a constant in the | 126 | * relation represented by `rsacomb:Congruent`) to a constant in the |
| 118 | * original ontology. | 127 | * original ontology. |
| 119 | * | 128 | * |
| 120 | * @note that the set of `rsa:Named` constants is always a subset of | 129 | * @note that the set of `rsa:Named` constants is always a subset of |
| @@ -125,7 +134,8 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 125 | * predicate, this is not feasible, and the instances are instead | 134 | * predicate, this is not feasible, and the instances are instead |
| 126 | * generate in the filtering program using a logic rule. | 135 | * generate in the filtering program using a logic rule. |
| 127 | */ | 136 | */ |
| 128 | val nis: Rule = Rule.create(NI(v"X"), named(v"Y"), congruent(v"X", v"Y")) | 137 | val nis: Rule = |
| 138 | Rule.create(NI(v"X"), RSA.Named(tts)(v"Y"), RSA.Congruent(tts)(v"X", v"Y")) | ||
| 129 | 139 | ||
| 130 | /** Collection of filtering program rules. */ | 140 | /** Collection of filtering program rules. */ |
| 131 | val rules: List[Rule] = | 141 | val rules: List[Rule] = |
| @@ -138,7 +148,7 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 138 | * @note corresponds to rule 1 in Table 3 in the paper. | 148 | * @note corresponds to rule 1 in Table 3 in the paper. |
| 139 | */ | 149 | */ |
| 140 | val r1 = | 150 | val r1 = |
| 141 | Rule.create(QM(v"K"), (query.atoms :+ skolem(v"K", variables)): _*) | 151 | Rule.create(QM(v"K"), queryBody :+ RSA.Skolem(v"K", variables)) |
| 142 | 152 | ||
| 143 | /** Initializes instances of `rsa:ID`. | 153 | /** Initializes instances of `rsa:ID`. |
| 144 | * | 154 | * |
| @@ -153,26 +163,26 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 153 | yield Rule.create( | 163 | yield Rule.create( |
| 154 | ID(v"K", v"S"), | 164 | ID(v"K", v"S"), |
| 155 | QM(v"K"), | 165 | QM(v"K"), |
| 156 | skolem(v"K", variables), | 166 | RSA.Skolem(v"K", variables), |
| 157 | not(NI(v)), | 167 | not(NI(v)), |
| 158 | skolem(v"S", variables :+ RSA(i) :+ RSA(i)) | 168 | RSA.Skolem(v"S", variables :+ RSA(i) :+ RSA(i)) |
| 159 | ) | 169 | ) |
| 160 | val r3b = Rule.create( | 170 | val r3b = Rule.create( |
| 161 | ID(v"K", v"T"), | 171 | ID(v"K", v"T"), |
| 162 | ID(v"K", v"S"), | 172 | ID(v"K", v"S"), |
| 163 | skolem(v"S", variables :+ v"U" :+ v"V"), | 173 | RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), |
| 164 | skolem(v"T", variables :+ v"V" :+ v"U") | 174 | RSA.Skolem(v"T", variables :+ v"V" :+ v"U") |
| 165 | ) | 175 | ) |
| 166 | val r3c = Rule.create( | 176 | val r3c = Rule.create( |
| 167 | ID(v"K1", v"Q"), | 177 | ID(v"K1", v"Q"), |
| 168 | QM(v"K1"), | 178 | QM(v"K1"), |
| 169 | ID(v"K2", v"S"), | 179 | ID(v"K2", v"S"), |
| 170 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), | 180 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), |
| 171 | skolem(v"S", variables :+ v"U" :+ v"V"), | 181 | RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), |
| 172 | ID(v"K3", v"T"), | 182 | ID(v"K3", v"T"), |
| 173 | FilterAtom.create(FunctionCall.equal(v"K1", v"K3")), | 183 | FilterAtom.create(FunctionCall.equal(v"K1", v"K3")), |
| 174 | skolem(v"T", variables :+ v"V" :+ v"W"), | 184 | RSA.Skolem(v"T", variables :+ v"V" :+ v"W"), |
| 175 | skolem(v"Q", variables :+ v"U" :+ v"W") | 185 | RSA.Skolem(v"Q", variables :+ v"U" :+ v"W") |
| 176 | ) | 186 | ) |
| 177 | 187 | ||
| 178 | /** Detects forks in the canonical model. | 188 | /** Detects forks in the canonical model. |
| @@ -180,49 +190,55 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 180 | * @note corresponds to rules 4x in Table 3. | 190 | * @note corresponds to rules 4x in Table 3. |
| 181 | */ | 191 | */ |
| 182 | val r4a = for { | 192 | val r4a = for { |
| 183 | role1 <- query.atoms filter (_.isRoleAssertion) | 193 | role1 <- queryBody filter (_.isRoleAssertion) |
| 184 | index1 = query.bounded indexOf (role1.getArguments get 2) | 194 | index1 = query.bounded indexOf (role1.getArguments get 2) |
| 185 | if index1 >= 0 | 195 | if index1 >= 0 |
| 186 | role2 <- query.atoms filter (_.isRoleAssertion) | 196 | role2 <- queryBody filter (_.isRoleAssertion) |
| 187 | index2 = query.bounded indexOf (role2.getArguments get 2) | 197 | index2 = query.bounded indexOf (role2.getArguments get 2) |
| 188 | if index2 >= 0 | 198 | if index2 >= 0 |
| 189 | } yield Rule.create( | 199 | } yield Rule.create( |
| 190 | FK(v"K"), | 200 | FK(v"K"), |
| 191 | ID(v"K", v"S"), | 201 | ID(v"K", v"S"), |
| 192 | skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), | 202 | RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), |
| 193 | role1 << Forward, | 203 | role1 :: Forward, |
| 194 | role2 << Forward, | 204 | role2 :: Forward, |
| 195 | not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 0)) | 205 | not( |
| 206 | RSA.Congruent(tts)(role1.getArguments get 0, role2.getArguments get 0) | ||
| 207 | ) | ||
| 196 | ) | 208 | ) |
| 197 | val r4b = for { | 209 | val r4b = for { |
| 198 | role1 <- query.atoms filter (_.isRoleAssertion) | 210 | role1 <- queryBody filter (_.isRoleAssertion) |
| 199 | index1 = query.bounded indexOf (role1.getArguments get 2) | 211 | index1 = query.bounded indexOf (role1.getArguments get 2) |
| 200 | if index1 >= 0 | 212 | if index1 >= 0 |
| 201 | role2 <- query.atoms filter (_.isRoleAssertion) | 213 | role2 <- queryBody filter (_.isRoleAssertion) |
| 202 | index2 = query.bounded indexOf (role2.getArguments get 0) | 214 | index2 = query.bounded indexOf (role2.getArguments get 0) |
| 203 | if index2 >= 0 | 215 | if index2 >= 0 |
| 204 | } yield Rule.create( | 216 | } yield Rule.create( |
| 205 | FK(v"K"), | 217 | FK(v"K"), |
| 206 | ID(v"K", v"S"), | 218 | ID(v"K", v"S"), |
| 207 | skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), | 219 | RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), |
| 208 | role1 << Forward, | 220 | role1 :: Forward, |
| 209 | role2 << Backward, | 221 | role2 :: Backward, |
| 210 | not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 2)) | 222 | not( |
| 223 | RSA.Congruent(tts)(role1.getArguments get 0, role2.getArguments get 2) | ||
| 224 | ) | ||
| 211 | ) | 225 | ) |
| 212 | val r4c = for { | 226 | val r4c = for { |
| 213 | role1 <- query.atoms filter (_.isRoleAssertion) | 227 | role1 <- queryBody filter (_.isRoleAssertion) |
| 214 | index1 = query.bounded indexOf (role1.getArguments get 0) | 228 | index1 = query.bounded indexOf (role1.getArguments get 0) |
| 215 | if index1 >= 0 | 229 | if index1 >= 0 |
| 216 | role2 <- query.atoms filter (_.isRoleAssertion) | 230 | role2 <- queryBody filter (_.isRoleAssertion) |
| 217 | index2 = query.bounded indexOf (role2.getArguments get 0) | 231 | index2 = query.bounded indexOf (role2.getArguments get 0) |
| 218 | if index2 >= 0 | 232 | if index2 >= 0 |
| 219 | } yield Rule.create( | 233 | } yield Rule.create( |
| 220 | FK(v"K"), | 234 | FK(v"K"), |
| 221 | ID(v"K", v"S"), | 235 | ID(v"K", v"S"), |
| 222 | skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), | 236 | RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), |
| 223 | role1 << Backward, | 237 | role1 :: Backward, |
| 224 | role2 << Backward, | 238 | role2 :: Backward, |
| 225 | not(RSA.Congruent(role1.getArguments get 2, role2.getArguments get 2)) | 239 | not( |
| 240 | RSA.Congruent(tts)(role1.getArguments get 2, role2.getArguments get 2) | ||
| 241 | ) | ||
| 226 | ) | 242 | ) |
| 227 | 243 | ||
| 228 | /** Recursively propagates `rsa:ID` predicate. | 244 | /** Recursively propagates `rsa:ID` predicate. |
| @@ -230,12 +246,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 230 | * @note corresponds to rules 5x in Table 3. | 246 | * @note corresponds to rules 5x in Table 3. |
| 231 | */ | 247 | */ |
| 232 | val r5a = for { | 248 | val r5a = for { |
| 233 | role1 <- query.atoms filter (_.isRoleAssertion) | 249 | role1 <- queryBody filter (_.isRoleAssertion) |
| 234 | r1arg0 = role1.getArguments get 0 | 250 | r1arg0 = role1.getArguments get 0 |
| 235 | if query.bounded contains r1arg0 | 251 | if query.bounded contains r1arg0 |
| 236 | r1arg2 = role1.getArguments get 2 | 252 | r1arg2 = role1.getArguments get 2 |
| 237 | if query.bounded contains r1arg2 | 253 | if query.bounded contains r1arg2 |
| 238 | role2 <- query.atoms filter (_.isRoleAssertion) | 254 | role2 <- queryBody filter (_.isRoleAssertion) |
| 239 | r2arg0 = role2.getArguments get 0 | 255 | r2arg0 = role2.getArguments get 0 |
| 240 | if query.bounded contains r2arg0 | 256 | if query.bounded contains r2arg0 |
| 241 | r2arg2 = role2.getArguments get 2 | 257 | r2arg2 = role2.getArguments get 2 |
| @@ -243,17 +259,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 243 | } yield Rule.create( | 259 | } yield Rule.create( |
| 244 | ID(v"K", v"T"), | 260 | ID(v"K", v"T"), |
| 245 | ID(v"K", v"S"), | 261 | ID(v"K", v"S"), |
| 246 | skolem( | 262 | RSA.Skolem( |
| 247 | v"S", | 263 | v"S", |
| 248 | variables :+ | 264 | variables :+ |
| 249 | RSA(query.bounded indexOf r1arg2) :+ | 265 | RSA(query.bounded indexOf r1arg2) :+ |
| 250 | RSA(query.bounded indexOf r2arg2) | 266 | RSA(query.bounded indexOf r2arg2) |
| 251 | ), | 267 | ), |
| 252 | RSA.Congruent(r1arg0, r2arg0), | 268 | RSA.Congruent(tts)(r1arg0, r2arg0), |
| 253 | role1 << Forward, | 269 | role1 :: Forward, |
| 254 | role2 << Forward, | 270 | role2 :: Forward, |
| 255 | not(NI(r1arg0)), | 271 | not(NI(r1arg0)), |
| 256 | skolem( | 272 | RSA.Skolem( |
| 257 | v"T", | 273 | v"T", |
| 258 | variables :+ | 274 | variables :+ |
| 259 | RSA(query.bounded indexOf r1arg0) :+ | 275 | RSA(query.bounded indexOf r1arg0) :+ |
| @@ -261,12 +277,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 261 | ) | 277 | ) |
| 262 | ) | 278 | ) |
| 263 | val r5b = for { | 279 | val r5b = for { |
| 264 | role1 <- query.atoms filter (_.isRoleAssertion) | 280 | role1 <- queryBody filter (_.isRoleAssertion) |
| 265 | r1arg0 = role1.getArguments get 0 | 281 | r1arg0 = role1.getArguments get 0 |
| 266 | if query.bounded contains r1arg0 | 282 | if query.bounded contains r1arg0 |
| 267 | r1arg2 = role1.getArguments get 2 | 283 | r1arg2 = role1.getArguments get 2 |
| 268 | if query.bounded contains r1arg2 | 284 | if query.bounded contains r1arg2 |
| 269 | role2 <- query.atoms filter (_.isRoleAssertion) | 285 | role2 <- queryBody filter (_.isRoleAssertion) |
| 270 | r2arg0 = role2.getArguments get 0 | 286 | r2arg0 = role2.getArguments get 0 |
| 271 | if query.bounded contains r2arg0 | 287 | if query.bounded contains r2arg0 |
| 272 | r2arg2 = role2.getArguments get 2 | 288 | r2arg2 = role2.getArguments get 2 |
| @@ -274,17 +290,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 274 | } yield Rule.create( | 290 | } yield Rule.create( |
| 275 | ID(v"K", v"T"), | 291 | ID(v"K", v"T"), |
| 276 | ID(v"K", v"S"), | 292 | ID(v"K", v"S"), |
| 277 | skolem( | 293 | RSA.Skolem( |
| 278 | v"S", | 294 | v"S", |
| 279 | variables :+ | 295 | variables :+ |
| 280 | RSA(query.bounded indexOf r1arg2) :+ | 296 | RSA(query.bounded indexOf r1arg2) :+ |
| 281 | RSA(query.bounded indexOf r2arg0) | 297 | RSA(query.bounded indexOf r2arg0) |
| 282 | ), | 298 | ), |
| 283 | RSA.Congruent(r1arg0, r2arg2), | 299 | RSA.Congruent(tts)(r1arg0, r2arg2), |
| 284 | role1 << Forward, | 300 | role1 :: Forward, |
| 285 | role2 << Backward, | 301 | role2 :: Backward, |
| 286 | not(RSA.NI(r1arg0)), | 302 | not(NI(r1arg0)), |
| 287 | skolem( | 303 | RSA.Skolem( |
| 288 | v"T", | 304 | v"T", |
| 289 | variables :+ | 305 | variables :+ |
| 290 | RSA(query.bounded indexOf r1arg0) :+ | 306 | RSA(query.bounded indexOf r1arg0) :+ |
| @@ -292,12 +308,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 292 | ) | 308 | ) |
| 293 | ) | 309 | ) |
| 294 | val r5c = for { | 310 | val r5c = for { |
| 295 | role1 <- query.atoms filter (_.isRoleAssertion) | 311 | role1 <- queryBody filter (_.isRoleAssertion) |
| 296 | r1arg0 = role1.getArguments get 0 | 312 | r1arg0 = role1.getArguments get 0 |
| 297 | if query.bounded contains r1arg0 | 313 | if query.bounded contains r1arg0 |
| 298 | r1arg2 = role1.getArguments get 2 | 314 | r1arg2 = role1.getArguments get 2 |
| 299 | if query.bounded contains r1arg2 | 315 | if query.bounded contains r1arg2 |
| 300 | role2 <- query.atoms filter (_.isRoleAssertion) | 316 | role2 <- queryBody filter (_.isRoleAssertion) |
| 301 | r2arg0 = role2.getArguments get 0 | 317 | r2arg0 = role2.getArguments get 0 |
| 302 | if query.bounded contains r2arg0 | 318 | if query.bounded contains r2arg0 |
| 303 | r2arg2 = role2.getArguments get 2 | 319 | r2arg2 = role2.getArguments get 2 |
| @@ -305,17 +321,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 305 | } yield Rule.create( | 321 | } yield Rule.create( |
| 306 | ID(v"K", v"T"), | 322 | ID(v"K", v"T"), |
| 307 | ID(v"K", v"S"), | 323 | ID(v"K", v"S"), |
| 308 | skolem( | 324 | RSA.Skolem( |
| 309 | v"S", | 325 | v"S", |
| 310 | variables :+ | 326 | variables :+ |
| 311 | RSA(query.bounded indexOf r1arg0) :+ | 327 | RSA(query.bounded indexOf r1arg0) :+ |
| 312 | RSA(query.bounded indexOf r2arg0) | 328 | RSA(query.bounded indexOf r2arg0) |
| 313 | ), | 329 | ), |
| 314 | RSA.Congruent(r1arg2, r2arg2), | 330 | RSA.Congruent(tts)(r1arg2, r2arg2), |
| 315 | role1 << Backward, | 331 | role1 :: Backward, |
| 316 | role2 << Backward, | 332 | role2 :: Backward, |
| 317 | not(RSA.NI(r1arg2)), | 333 | not(NI(r1arg2)), |
| 318 | skolem( | 334 | RSA.Skolem( |
| 319 | v"T", | 335 | v"T", |
| 320 | variables :+ | 336 | variables :+ |
| 321 | RSA(query.bounded indexOf r1arg2) :+ | 337 | RSA(query.bounded indexOf r1arg2) :+ |
| @@ -332,38 +348,38 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 332 | * @note corresponds to rules 6,7x in Table 3. | 348 | * @note corresponds to rules 6,7x in Table 3. |
| 333 | */ | 349 | */ |
| 334 | val r6 = for { | 350 | val r6 = for { |
| 335 | role <- query.atoms filter (_.isRoleAssertion) | 351 | role <- queryBody filter (_.isRoleAssertion) |
| 336 | index0 = query.bounded indexOf (role.getArguments get 0) | 352 | index0 = query.bounded indexOf (role.getArguments get 0) |
| 337 | if index0 >= 0 | 353 | if index0 >= 0 |
| 338 | index2 = query.bounded indexOf (role.getArguments get 2) | 354 | index2 = query.bounded indexOf (role.getArguments get 2) |
| 339 | if index2 >= 0 | 355 | if index2 >= 0 |
| 340 | suffix <- Seq(Forward, Backward) | 356 | suffix <- Seq(Forward, Backward) |
| 341 | } yield Rule.create( | 357 | } yield Rule.create( |
| 342 | AQ(suffix, v"K1", v"Q"), | 358 | AQ(suffix)(v"K1", v"Q"), |
| 343 | ID(v"K1", v"S"), | 359 | ID(v"K1", v"S"), |
| 344 | skolem(v"S", variables :+ RSA(index0) :+ v"V"), | 360 | RSA.Skolem(v"S", variables :+ RSA(index0) :+ v"V"), |
| 345 | ID(v"K2", v"T"), | 361 | ID(v"K2", v"T"), |
| 346 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), | 362 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), |
| 347 | skolem(v"T", variables :+ RSA(index2) :+ v"W"), | 363 | RSA.Skolem(v"T", variables :+ RSA(index2) :+ v"W"), |
| 348 | role << suffix, | 364 | role :: suffix, |
| 349 | skolem(v"Q", variables :+ v"V" :+ v"W") | 365 | RSA.Skolem(v"Q", variables :+ v"V" :+ v"W") |
| 350 | ) | 366 | ) |
| 351 | val r7a = | 367 | val r7a = |
| 352 | for (suffix <- List(Forward, Backward)) | 368 | for (suffix <- List(Forward, Backward)) |
| 353 | yield Rule.create( | 369 | yield Rule.create( |
| 354 | TQ(suffix, v"K", v"S"), | 370 | TQ(suffix)(v"K", v"S"), |
| 355 | AQ(suffix, v"K", v"S") | 371 | AQ(suffix)(v"K", v"S") |
| 356 | ) | 372 | ) |
| 357 | val r7b = | 373 | val r7b = |
| 358 | for (suffix <- List(Forward, Backward)) | 374 | for (suffix <- List(Forward, Backward)) |
| 359 | yield Rule.create( | 375 | yield Rule.create( |
| 360 | TQ(suffix, v"K1", v"Q"), | 376 | TQ(suffix)(v"K1", v"Q"), |
| 361 | AQ(suffix, v"K1", v"S"), | 377 | AQ(suffix)(v"K1", v"S"), |
| 362 | skolem(v"S", variables :+ v"U" :+ v"V"), | 378 | RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), |
| 363 | TQ(suffix, v"K2", v"T"), | 379 | TQ(suffix)(v"K2", v"T"), |
| 364 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), | 380 | FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), |
| 365 | skolem(v"T", variables :+ v"V" :+ v"W"), | 381 | RSA.Skolem(v"T", variables :+ v"V" :+ v"W"), |
| 366 | skolem(v"Q", variables :+ v"U" :+ v"W") | 382 | RSA.Skolem(v"Q", variables :+ v"U" :+ v"W") |
| 367 | ) | 383 | ) |
| 368 | 384 | ||
| 369 | /** Flag spurious answers. | 385 | /** Flag spurious answers. |
| @@ -375,19 +391,16 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 375 | yield Rule.create( | 391 | yield Rule.create( |
| 376 | SP(v"K"), | 392 | SP(v"K"), |
| 377 | QM(v"K"), | 393 | QM(v"K"), |
| 378 | skolem(v"K", variables), | 394 | RSA.Skolem(v"K", variables), |
| 379 | not(RSA.Named(v)) | 395 | not(RSA.Named(tts)(v)) |
| 380 | ) | 396 | ) |
| 381 | val r8b = Rule.create( | 397 | val r8b = Rule.create(SP(v"K"), FK(v"K")) |
| 382 | SP(v"K"), | ||
| 383 | FK(v"K") | ||
| 384 | ) | ||
| 385 | val r8c = | 398 | val r8c = |
| 386 | for (suffix <- List(Forward, Backward)) | 399 | for (suffix <- List(Forward, Backward)) |
| 387 | yield Rule.create( | 400 | yield Rule.create( |
| 388 | SP(v"K"), | 401 | SP(v"K"), |
| 389 | TQ(suffix, v"K", v"S"), | 402 | TQ(suffix)(v"K", v"S"), |
| 390 | skolem(v"S", variables :+ v"V" :+ v"V") | 403 | RSA.Skolem(v"S", variables :+ v"V" :+ v"V") |
| 391 | ) | 404 | ) |
| 392 | 405 | ||
| 393 | /** Determine answers to the query | 406 | /** Determine answers to the query |
| @@ -405,11 +418,7 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 405 | * | 418 | * |
| 406 | * @note corresponds to rule 9 in Table 3. | 419 | * @note corresponds to rule 9 in Table 3. |
| 407 | */ | 420 | */ |
| 408 | val r9 = Rule.create( | 421 | val r9 = Rule.create(Ans(v"K"), QM(v"K"), not(SP(v"K"))) |
| 409 | Ans(v"K"), | ||
| 410 | QM(v"K"), | ||
| 411 | not(SP(v"K")) | ||
| 412 | ) | ||
| 413 | 422 | ||
| 414 | (r1 :: r3a ::: r3b :: r3c :: r4a ::: r4b ::: r4c ::: r5a ::: r5b ::: r5c ::: r6 ::: r7b ::: r7a ::: r8a ::: r8b :: r8c ::: r9 :: List()) | 423 | (r1 :: r3a ::: r3b :: r3c :: r4a ::: r4b ::: r4c ::: r5a ::: r5b ::: r5c ::: r6 ::: r7b ::: r7a ::: r8a ::: r8b :: r8c ::: r9 :: List()) |
| 415 | } | 424 | } |
| @@ -422,12 +431,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) | |||
| 422 | s""" | 431 | s""" |
| 423 | SELECT $answer | 432 | SELECT $answer |
| 424 | WHERE { | 433 | WHERE { |
| 425 | GRAPH <$graph> { ?K a rsa:Ans } . | 434 | GRAPH $target { ?K a ${RSA.ANS} } . |
| 426 | TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $answer $bounded ?K } . | 435 | TT ${TupleTableName.SKOLEM} { $answer $bounded ?K } . |
| 427 | } | 436 | } |
| 428 | """ | 437 | """ |
| 429 | } else { | 438 | } else { |
| 430 | s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" | 439 | s"ASK { GRAPH $target { ?X a ${RSA.ANS} } }" |
| 431 | } | 440 | } |
| 432 | } | 441 | } |
| 433 | 442 | ||
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala index d4b7876..ca77409 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | package uk.ac.ox.cs.rsacomb.implicits | 17 | package uk.ac.ox.cs.rsacomb.implicits |
| 18 | 18 | ||
| 19 | import tech.oxfordsemantic.jrdfox.logic.Datatype | 19 | import tech.oxfordsemantic.jrdfox.logic.Datatype |
| 20 | import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableName | ||
| 20 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | 21 | import tech.oxfordsemantic.jrdfox.logic.expression.{ |
| 21 | BlankNode, | 22 | BlankNode, |
| 22 | IRI => RDFoxIRI, | 23 | IRI => RDFoxIRI, |
| @@ -47,6 +48,9 @@ object RDFox { | |||
| 47 | implicit def stringToRdfoxIri(iri: String): RDFoxIRI = | 48 | implicit def stringToRdfoxIri(iri: String): RDFoxIRI = |
| 48 | RDFoxIRI.create(iri) | 49 | RDFoxIRI.create(iri) |
| 49 | 50 | ||
| 51 | implicit def iriToTupleTableName(iri: RDFoxIRI): TupleTableName = | ||
| 52 | TupleTableName.create(iri.getIRI) | ||
| 53 | |||
| 50 | /** Converst an OWLAPI datatype into an RDFox datatype. | 54 | /** Converst an OWLAPI datatype into an RDFox datatype. |
| 51 | * | 55 | * |
| 52 | * The builtin datatypes defined by the two systems do not match | 56 | * The builtin datatypes defined by the two systems do not match |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala index 37c70df..89777c4 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala | |||
| @@ -29,21 +29,6 @@ import uk.ac.ox.cs.rsacomb.RSAOntology | |||
| 29 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Nth} | 29 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Nth} |
| 30 | import uk.ac.ox.cs.rsacomb.util.{DataFactory, RDFoxUtil} | 30 | import uk.ac.ox.cs.rsacomb.util.{DataFactory, RDFoxUtil} |
| 31 | 31 | ||
| 32 | /* Is this the best way to determine if an atom is an RDF triple? | ||
| 33 | * Note that we can't use `getNumberOfArguments()` because is not | ||
| 34 | * "consistent": | ||
| 35 | * - for an atom created with `rdf(<term1>, <term2>, <term3>)`, | ||
| 36 | * `getNumberOfArguments` returns 3 | ||
| 37 | * - for an atom created with `Atom.create(<tupletablename>, <term1>, | ||
| 38 | * <term2>, <term3>)`, `getNumberOfArguments()` returns 3 | ||
| 39 | * | ||
| 40 | * This is probably because `Atom.rdf(...) is implemented as: | ||
| 41 | * ```scala | ||
| 42 | * def rdf(term1: Term, term2: Term, term3: Term): Atom = | ||
| 43 | * Atom.create(TupleTableName.create("rdfox:DefaultTriples"), term1, term2, term3) | ||
| 44 | * ``` | ||
| 45 | */ | ||
| 46 | |||
| 47 | object RSAAtom { | 32 | object RSAAtom { |
| 48 | 33 | ||
| 49 | implicit class RSAAtom(val atom: TupleTableAtom) { | 34 | implicit class RSAAtom(val atom: TupleTableAtom) { |
| @@ -62,25 +47,25 @@ object RSAAtom { | |||
| 62 | 47 | ||
| 63 | val isRoleAssertion: Boolean = isRDF && !isClassAssertion | 48 | val isRoleAssertion: Boolean = isRDF && !isClassAssertion |
| 64 | 49 | ||
| 65 | def <<(suffix: RSASuffix): TupleTableAtom = | 50 | // def <<(suffix: RSASuffix): TupleTableAtom = |
| 66 | if (isRDF) { | 51 | // if (isRDF) { |
| 67 | val subj = atom.getArguments.get(0) | 52 | // val subj = atom.getArguments.get(0) |
| 68 | val pred = atom.getArguments.get(1) | 53 | // val pred = atom.getArguments.get(1) |
| 69 | val obj = atom.getArguments.get(2) | 54 | // val obj = atom.getArguments.get(2) |
| 70 | if (isClassAssertion) { | 55 | // if (isClassAssertion) { |
| 71 | val obj1 = obj match { | 56 | // val obj1 = obj match { |
| 72 | case iri: IRI => IRI.create(iri.getIRI :: suffix) | 57 | // case iri: IRI => IRI.create(iri.getIRI :: suffix) |
| 73 | case other => other | 58 | // case other => other |
| 74 | } | 59 | // } |
| 75 | TupleTableAtom.create(tt, subj, pred, obj1) | 60 | // TupleTableAtom.create(tt, subj, pred, obj1) |
| 76 | } else { | 61 | // } else { |
| 77 | val pred1 = pred match { | 62 | // val pred1 = pred match { |
| 78 | case iri: IRI => IRI.create(iri.getIRI :: suffix) | 63 | // case iri: IRI => IRI.create(iri.getIRI :: suffix) |
| 79 | case other => other | 64 | // case other => other |
| 80 | } | 65 | // } |
| 81 | TupleTableAtom.create(tt, subj, pred1, obj) | 66 | // TupleTableAtom.create(tt, subj, pred1, obj) |
| 82 | } | 67 | // } |
| 83 | } else atom | 68 | // } else atom |
| 84 | 69 | ||
| 85 | // def reified(implicit | 70 | // def reified(implicit |
| 86 | // fresh: DataFactory | 71 | // fresh: DataFactory |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala index 424f2a0..282aa0b 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala | |||
| @@ -16,13 +16,13 @@ | |||
| 16 | 16 | ||
| 17 | package uk.ac.ox.cs.rsacomb.suffix | 17 | package uk.ac.ox.cs.rsacomb.suffix |
| 18 | 18 | ||
| 19 | import org.semanticweb.owlapi.model.{ | 19 | // import org.semanticweb.owlapi.model.{ |
| 20 | OWLPropertyExpression, | 20 | // OWLPropertyExpression, |
| 21 | OWLObjectInverseOf, | 21 | // OWLObjectInverseOf, |
| 22 | OWLObjectProperty | 22 | // OWLObjectProperty |
| 23 | } | 23 | // } |
| 24 | 24 | ||
| 25 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI} | 25 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI, Term} |
| 26 | import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} | 26 | import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} |
| 27 | 27 | ||
| 28 | object RSASuffix { | 28 | object RSASuffix { |
| @@ -37,7 +37,17 @@ class RSASuffix(val suffix: String => String) { | |||
| 37 | new RSASuffix(this.suffix andThen that.suffix) | 37 | new RSASuffix(this.suffix andThen that.suffix) |
| 38 | 38 | ||
| 39 | def ::(str: String): String = this suffix str | 39 | def ::(str: String): String = this suffix str |
| 40 | 40 | def ::(iri: IRI): IRI = IRI.create(this suffix iri.getIRI) | |
| 41 | def ::(tta: TupleTableAtom): TupleTableAtom = { | ||
| 42 | val ttn: TupleTableName = tta.getTupleTableName | ||
| 43 | tta.getArguments match { | ||
| 44 | case List(subj: Term, IRI.RDF_TYPE, obj: IRI) => | ||
| 45 | TupleTableAtom.create(ttn, subj, IRI.RDF_TYPE, obj :: this) | ||
| 46 | case List(subj: Term, pred: IRI, obj: Term) => | ||
| 47 | TupleTableAtom.create(ttn, subj, pred :: this, obj) | ||
| 48 | case _ => tta | ||
| 49 | } | ||
| 50 | } | ||
| 41 | } | 51 | } |
| 42 | 52 | ||
| 43 | case object Empty extends RSASuffix(identity) | 53 | case object Empty extends RSASuffix(identity) |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala index 40c5ced..5abb83c 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala | |||
| @@ -54,73 +54,35 @@ object RSA { | |||
| 54 | /** Creates a `rsacomb:<name>` IRI */ | 54 | /** Creates a `rsacomb:<name>` IRI */ |
| 55 | def apply(name: Any): IRI = | 55 | def apply(name: Any): IRI = |
| 56 | IRI.create( | 56 | IRI.create( |
| 57 | //Prefixes.decodeIRI("rsacomb:") + name.toString | ||
| 57 | Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString | 58 | Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString |
| 58 | ) | 59 | ) |
| 59 | 60 | ||
| 61 | /** Helper IRIs */ | ||
| 60 | val ANS = RSA("Ans") | 62 | val ANS = RSA("Ans") |
| 63 | val AQ = RSA("AQ") | ||
| 61 | val CONGRUENT = RSA("congruent") | 64 | val CONGRUENT = RSA("congruent") |
| 65 | val FK = RSA("FK") | ||
| 66 | val ID = RSA("ID") | ||
| 62 | val IN = RSA("In") | 67 | val IN = RSA("In") |
| 63 | val NAMED = RSA("Named") | 68 | val NAMED = RSA("Named") |
| 69 | val NI = RSA("NI") | ||
| 70 | val QM = RSA("QM") | ||
| 71 | val SP = RSA("SP") | ||
| 72 | val TQ = RSA("TQ") | ||
| 73 | |||
| 74 | def Named(tt: TupleTableName)(x: Term): TupleTableAtom = | ||
| 75 | TupleTableAtom.create(tt, x, IRI.RDF_TYPE, RSA.NAMED) | ||
| 76 | def Congruent(tt: TupleTableName)(x: Term, y: Term): TupleTableAtom = | ||
| 77 | TupleTableAtom.create(tt, x, RSA.CONGRUENT, y) | ||
| 78 | def Skolem(skolem: Term, terms: List[Term]): TupleTableAtom = | ||
| 79 | TupleTableAtom.create(TupleTableName.SKOLEM, terms :+ skolem) | ||
| 64 | 80 | ||
| 65 | // def In(t: Term)(implicit set: Term) = | 81 | // def In(t: Term)(implicit set: Term) = |
| 66 | // TupleTableAtom.rdf(t, RSA("In"), set) | 82 | // TupleTableAtom.rdf(t, RSA("In"), set) |
| 67 | 83 | ||
| 68 | // def NotIn(t: Term)(implicit set: Term) = Negation.create(In(t)(set)) | 84 | // def NotIn(t: Term)(implicit set: Term) = Negation.create(In(t)(set)) |
| 69 | 85 | ||
| 70 | def Congruent(t1: Term, t2: Term)(implicit graph: TupleTableName) = | ||
| 71 | TupleTableAtom.create(graph, t1, RSA.CONGRUENT, t2) | ||
| 72 | |||
| 73 | def Named(term: Term)(implicit graph: TupleTableName) = | ||
| 74 | TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA.NAMED) | ||
| 75 | |||
| 76 | def QM(implicit query: ConjunctiveQuery, graph: TupleTableName) = | ||
| 77 | TupleTableAtom.create(graph, RSA("QM") :: query.answer ::: query.bounded) | ||
| 78 | |||
| 79 | def ID(t1: Term, t2: Term)(implicit | ||
| 80 | query: ConjunctiveQuery, | ||
| 81 | graph: TupleTableName | ||
| 82 | ) = | ||
| 83 | TupleTableAtom.create( | ||
| 84 | graph, | ||
| 85 | RSA("ID") +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 86 | ) | ||
| 87 | |||
| 88 | // def Thing(t: Term) = | ||
| 89 | // TupleTableAtom.rdf(t, IRI.RDF_TYPE, IRI.THING) | ||
| 90 | |||
| 91 | def NI(term: Term)(implicit graph: TupleTableName) = | ||
| 92 | TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA("NI")) | ||
| 93 | |||
| 94 | def TQ(sx: RSASuffix, t1: Term, t2: Term)(implicit | ||
| 95 | query: ConjunctiveQuery, | ||
| 96 | graph: TupleTableName | ||
| 97 | ) = | ||
| 98 | TupleTableAtom.create( | ||
| 99 | graph, | ||
| 100 | RSA("TQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 101 | ) | ||
| 102 | |||
| 103 | def AQ(sx: RSASuffix, t1: Term, t2: Term)(implicit | ||
| 104 | query: ConjunctiveQuery, | ||
| 105 | graph: TupleTableName | ||
| 106 | ) = | ||
| 107 | TupleTableAtom.create( | ||
| 108 | graph, | ||
| 109 | RSA("AQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 | ||
| 110 | ) | ||
| 111 | |||
| 112 | def FK(implicit query: ConjunctiveQuery, graph: TupleTableName) = | ||
| 113 | TupleTableAtom.create(graph, RSA("FK") :: query.answer ::: query.bounded) | ||
| 114 | |||
| 115 | def SP(implicit q: ConjunctiveQuery, graph: TupleTableName) = | ||
| 116 | TupleTableAtom.create(graph, RSA("SP") :: q.answer ::: q.bounded) | ||
| 117 | |||
| 118 | def Ans(implicit q: ConjunctiveQuery, graph: TupleTableName) = | ||
| 119 | if (q.bcq) | ||
| 120 | TupleTableAtom.create(graph, RSA("blank"), IRI.RDF_TYPE, RSA.ANS) | ||
| 121 | else | ||
| 122 | TupleTableAtom.create(graph, RSA.ANS :: q.answer) | ||
| 123 | |||
| 124 | /* TODO: review after reworking the dependency graph construction */ | 86 | /* TODO: review after reworking the dependency graph construction */ |
| 125 | 87 | ||
| 126 | // private def atom(name: IRI, vars: List[Term]): TupleTableAtom = | 88 | // private def atom(name: IRI, vars: List[Term]): TupleTableAtom = |
