aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2020-09-08 18:43:40 +0200
committerFederico Igne <federico.igne@cs.ox.ac.uk>2020-09-08 18:43:40 +0200
commit932b0a794c06a224a96b265935a38a4c7b851c5e (patch)
tree2ea7562eefaf710ec6f685865ae7e466af70531d
parentcb5f08f7dc9c811488c499d5b5fa65e3451aff5e (diff)
downloadRSAComb-932b0a794c06a224a96b265935a38a4c7b851c5e.tar.gz
RSAComb-932b0a794c06a224a96b265935a38a4c7b851c5e.zip
Add full set of rules for filtering program
-rw-r--r--src/main/scala/rsacomb/FilteringProgram.scala295
-rw-r--r--src/main/scala/rsacomb/RDFTriple.scala60
-rw-r--r--src/main/scala/rsacomb/RSA.scala5
-rw-r--r--src/main/scala/rsacomb/RSAOntology.scala105
4 files changed, 363 insertions, 102 deletions
diff --git a/src/main/scala/rsacomb/FilteringProgram.scala b/src/main/scala/rsacomb/FilteringProgram.scala
new file mode 100644
index 0000000..91c98d8
--- /dev/null
+++ b/src/main/scala/rsacomb/FilteringProgram.scala
@@ -0,0 +1,295 @@
1package rsacomb
2
3import tech.oxfordsemantic.jrdfox.logic._
4import scala.collection.JavaConverters._
5
6class FilteringProgram(query: Query, constants: List[Term]) extends RDFTriple {
7
8 private val bounded: List[Term] = this.getBoundedVariables
9 private val answer: List[Term] = query.getAnswerVariables.asScala.toList
10
11 val facts: List[Atom] = constants.map(named)
12 val rules: List[Rule] = this.generateFilteringProgram()
13
14 private def named(t: Term): Atom =
15 Atom.rdf(t, IRI.RDF_TYPE, RSA.internal("NAMED"))
16
17 private def getBoundedVariables: List[Variable] = List()
18
19 private def generateFilteringProgram(): List[Rule] = {
20 // Query formula as a rule body
21 val body = queryToBody(query.getQueryFormula)
22 // Auxiliar predicates/helpers
23 def not(atom: Atom): BodyFormula = Negation.create(atom)
24 val predQM =
25 Atom.create(
26 TupleTableName.create(RSA.internal("QM").getIRI),
27 (answer ++ bounded): _*
28 )
29 def predID(t1: Term, t2: Term) =
30 Atom.create(
31 TupleTableName.create(RSA.internal("ID").getIRI),
32 (answer ++ bounded).appended(t1).appended(t2): _*
33 )
34 def predNI(t1: Term): Atom =
35 Atom.rdf(t1, IRI.RDF_TYPE, RSA.internal("NI"))
36 def predTQ(sx: String, t1: Term, t2: Term) =
37 Atom.create(
38 TupleTableName.create(RSA.internal(s"TQ_$sx").getIRI),
39 (answer ++ bounded).appended(t1).appended(t2): _*
40 )
41 def predAQ(sx: String, t1: Term, t2: Term) =
42 Atom.create(
43 TupleTableName.create(RSA.internal(s"AQ_$sx").getIRI),
44 (answer ++ bounded).appended(t1).appended(t2): _*
45 )
46 val predFK =
47 Atom.create(
48 TupleTableName.create(RSA.internal("FK").getIRI),
49 (answer ++ bounded): _*
50 )
51 val predSP =
52 Atom.create(
53 TupleTableName.create(RSA.internal("SP").getIRI),
54 (answer ++ bounded): _*
55 )
56 val predANS =
57 Atom.create(
58 TupleTableName.create(RSA.internal("ANS").getIRI),
59 answer: _*
60 )
61
62 /* Rule 1 */
63 val r1 = Rule.create(predQM, body: _*)
64
65 /* Rules 3x */
66 val r3a =
67 for ((v, i) <- bounded.zipWithIndex)
68 yield Rule.create(
69 predID(RSA.internal(i), RSA.internal(i)),
70 predQM,
71 not(predNI(v))
72 )
73 val r3b = Rule.create(
74 predID(Variable.create("V"), Variable.create("U")),
75 predID(Variable.create("U"), Variable.create("V"))
76 )
77 val r3c = Rule.create(
78 predID(Variable.create("U"), Variable.create("W")),
79 predID(Variable.create("U"), Variable.create("V")),
80 predID(Variable.create("V"), Variable.create("W"))
81 )
82
83 /* Rules 4x */
84 val r4a = for {
85 role1 <- body.filter(_.isRoleAssertion)
86 if bounded contains (role1 getArgument 2)
87 role2 <- body.filter(_.isRoleAssertion)
88 if bounded contains (role2 getArgument 2)
89 } yield Rule.create(
90 predFK,
91 role1 suffix "_f",
92 role2 suffix "_f",
93 predID(
94 RSA.internal(bounded.indexOf(role1 getArgument 2)),
95 RSA.internal(bounded.indexOf(role2 getArgument 2))
96 ),
97 not(Atom.rdf(role1 getArgument 0, IRI.SAME_AS, role2 getArgument 0))
98 )
99 val r4b = for {
100 role1 <- body.filter(_.isRoleAssertion)
101 if bounded contains (role1 getArgument 2)
102 role2 <- body.filter(_.isRoleAssertion)
103 if bounded contains (role2 getArgument 0)
104 } yield Rule.create(
105 predFK,
106 role1 suffix "_f",
107 role2 suffix "_b",
108 predID(
109 RSA.internal(bounded.indexOf(role1 getArgument 2)),
110 RSA.internal(bounded.indexOf(role2 getArgument 0))
111 ),
112 not(Atom.rdf(role1 getArgument 0, IRI.SAME_AS, role2 getArgument 2))
113 )
114 val r4c = for {
115 role1 <- body.filter(_.isRoleAssertion)
116 if bounded contains (role1 getArgument 0)
117 role2 <- body.filter(_.isRoleAssertion)
118 if bounded contains (role2 getArgument 0)
119 } yield Rule.create(
120 predFK,
121 role1 suffix "_b",
122 role2 suffix "_b",
123 predID(
124 RSA.internal(bounded.indexOf(role1 getArgument 0)),
125 RSA.internal(bounded.indexOf(role2 getArgument 0))
126 ),
127 not(Atom.rdf(role1 getArgument 2, IRI.SAME_AS, role2 getArgument 2))
128 )
129
130 /* Rules 5x */
131 val r5a = for {
132 role1 <- body.filter(_.isRoleAssertion)
133 role1arg0 = role1 getArgument 0
134 role1arg2 = role1 getArgument 2
135 if bounded contains role1arg0
136 if bounded contains role1arg2
137 role2 <- body.filter(_.isRoleAssertion)
138 role2arg0 = role2 getArgument 0
139 role2arg2 = role2 getArgument 2
140 if bounded contains role2arg0
141 if bounded contains role2arg2
142 } yield Rule.create(
143 predID(
144 RSA.internal(bounded indexOf role1arg0),
145 RSA.internal(bounded indexOf role2arg0)
146 ),
147 role1 suffix "_f",
148 role2 suffix "_f",
149 predID(
150 RSA.internal(bounded indexOf role1arg2),
151 RSA.internal(bounded indexOf role2arg2)
152 ),
153 Atom.rdf(role1arg0, IRI.SAME_AS, role2arg0),
154 not(predNI(role1arg0))
155 )
156 val r5b = for {
157 role1 <- body.filter(_.isRoleAssertion)
158 role1arg0 = role1 getArgument 0
159 role1arg2 = role1 getArgument 2
160 if bounded contains role1arg0
161 if bounded contains role1arg2
162 role2 <- body.filter(_.isRoleAssertion)
163 role2arg0 = role2 getArgument 0
164 role2arg2 = role2 getArgument 2
165 if bounded contains role2arg0
166 if bounded contains role2arg2
167 } yield Rule.create(
168 predID(
169 RSA.internal(bounded indexOf role1arg0),
170 RSA.internal(bounded indexOf role2arg2)
171 ),
172 role1 suffix "_f",
173 role2 suffix "_b",
174 predID(
175 RSA.internal(bounded indexOf role1arg2),
176 RSA.internal(bounded indexOf role2arg0)
177 ),
178 Atom.rdf(role1arg0, IRI.SAME_AS, role2arg2),
179 not(predNI(role1arg0))
180 )
181 val r5c = for {
182 role1 <- body.filter(_.isRoleAssertion)
183 role1arg0 = role1 getArgument 0
184 role1arg2 = role1 getArgument 2
185 if bounded contains role1arg0
186 if bounded contains role1arg2
187 role2 <- body.filter(_.isRoleAssertion)
188 role2arg0 = role2 getArgument 0
189 role2arg2 = role2 getArgument 2
190 if bounded contains role2arg0
191 if bounded contains role2arg2
192 } yield Rule.create(
193 predID(
194 RSA.internal(bounded indexOf role1arg2),
195 RSA.internal(bounded indexOf role2arg2)
196 ),
197 role1 suffix "_b",
198 role2 suffix "_b",
199 predID(
200 RSA.internal(bounded indexOf role1arg0),
201 RSA.internal(bounded indexOf role2arg0)
202 ),
203 Atom.rdf(role1arg2, IRI.SAME_AS, role2arg2),
204 not(predNI(role1arg2))
205 )
206
207 /* Rules 6 */
208 val r6 = for {
209 role <- body.filter(_.isRoleAssertion)
210 arg0 = role getArgument 0
211 arg2 = role getArgument 2
212 if bounded contains arg0
213 if bounded contains arg2
214 sx <- List("_f", "_b")
215 } yield Rule.create(
216 predAQ(sx, Variable.create("V"), Variable.create("W")),
217 role suffix sx,
218 predID(
219 RSA.internal(bounded indexOf arg0),
220 RSA.internal(Variable.create("V"))
221 ),
222 predID(
223 RSA.internal(bounded indexOf arg2),
224 RSA.internal(Variable.create("W"))
225 )
226 )
227
228 /* Rules 7x */
229 val r7a =
230 for (sx <- List("f", "b"))
231 yield Rule.create(
232 predTQ(sx, Variable.create("U"), Variable.create("V")),
233 predAQ(sx, Variable.create("U"), Variable.create("V"))
234 )
235 val r7b =
236 for (r <- List("f", "b"))
237 yield Rule.create(
238 predTQ(r, Variable.create("U"), Variable.create("W")),
239 predAQ(r, Variable.create("U"), Variable.create("V")),
240 predTQ(r, Variable.create("V"), Variable.create("W"))
241 )
242
243 /* Rules 8x */
244 val r8a =
245 for (v <- answer) yield Rule.create(predSP, predQM, not(named(v)))
246 val r8b =
247 Rule.create(predSP, predFK)
248 val r8c =
249 for (sx <- List("_f", "_b"))
250 yield Rule.create(
251 predSP,
252 predTQ(sx, Variable.create("V"), Variable.create("V"))
253 )
254
255 /* Rule 9 */
256 val r9 = Rule.create(predANS, predQM, not(predSP))
257
258 List.empty
259 .prepended(r9)
260 .prependedAll(r8c)
261 .prepended(r8b)
262 .prependedAll(r8a)
263 .prependedAll(r7b)
264 .prependedAll(r7a)
265 .prependedAll(r6)
266 .prependedAll(r5c)
267 .prependedAll(r5b)
268 .prependedAll(r5a)
269 .prependedAll(r4c)
270 .prependedAll(r4b)
271 .prependedAll(r4a)
272 .prepended(r3c)
273 .prepended(r3b)
274 .prependedAll(r3a)
275 .prepended(r1)
276 }
277
278 /* NOTE: we are restricting to queries that contain conjunctions of
279 * atoms for the time being. This might need to be reviewed in the
280 * future.
281 */
282 private def queryToBody(body: Formula): List[Atom] =
283 body match {
284 case a: Atom => List(a);
285 case a: Conjunction =>
286 a.getConjuncts.asScala.toList.flatMap(queryToBody);
287 case _ => List()
288 }
289
290} // class FilteringProgram
291
292object FilteringProgram {
293 def apply(query: Query, constants: List[Term]): FilteringProgram =
294 new FilteringProgram(query, constants)
295}
diff --git a/src/main/scala/rsacomb/RDFTriple.scala b/src/main/scala/rsacomb/RDFTriple.scala
new file mode 100644
index 0000000..11ad6d4
--- /dev/null
+++ b/src/main/scala/rsacomb/RDFTriple.scala
@@ -0,0 +1,60 @@
1package rsacomb
2
3import tech.oxfordsemantic.jrdfox.logic.{Atom, IRI, TupleTableName}
4
5trait RDFTriple {
6
7 implicit class RDFTriple(atom: Atom) {
8
9 /* Is this the best way to determine if an atom is an RDF triple?
10 * Note that we can't use `getNumberOfArguments()` because is not
11 * "consistent":
12 * - for an atom created with `rdf(<term1>, <term2>, <term3>)`,
13 * `getNumberOfArguments` returns 3
14 * - for an atom created with `Atom.create(<tupletablename>, <term1>,
15 * <term2>, <term3>)`, `getNumberOfArguments()` returns 3
16 *
17 * This is probably because `Atom.rdf(...) is implemented as:
18 * ```scala
19 * def rdf(term1: Term, term2: Term, term3: Term): Atom =
20 * Atom.create(TupleTableName.create("internal:triple"), term1, term2, term3)
21 * ```
22 */
23 def isRdfTriple: Boolean =
24 atom.getTupleTableName.getIRI.equals("internal:triple")
25
26 def isClassAssertion: Boolean =
27 atom.isRdfTriple && atom.getArgument(1).equals(IRI.RDF_TYPE)
28
29 def isRoleAssertion: Boolean =
30 atom.isRdfTriple && !atom.getArgument(1).equals(IRI.RDF_TYPE)
31
32 def suffix(sx: String): Atom =
33 if (this.isClassAssertion) {
34 val newclass = atom.getArgument(2) match {
35 case iri: IRI => IRI.create(iri.getIRI.appendedAll(sx))
36 case other => other
37 }
38 Atom.rdf(
39 atom getArgument 0,
40 atom getArgument 1,
41 newclass
42 )
43 } else if (this.isRoleAssertion) {
44 val newrole = atom.getArgument(1) match {
45 case iri: IRI => IRI.create(iri.getIRI.appendedAll(sx))
46 case other => other
47 }
48 Atom.rdf(
49 atom getArgument 0,
50 newrole,
51 atom getArgument 2
52 )
53 } else {
54 val newname =
55 TupleTableName.create(atom.getTupleTableName.getIRI.appendedAll(sx))
56 Atom.create(newname, atom.getArguments())
57 }
58 }
59
60}
diff --git a/src/main/scala/rsacomb/RSA.scala b/src/main/scala/rsacomb/RSA.scala
index edd3758..9125f9f 100644
--- a/src/main/scala/rsacomb/RSA.scala
+++ b/src/main/scala/rsacomb/RSA.scala
@@ -50,9 +50,10 @@ object RSA extends RSAOntology {
50 val test_query = 50 val test_query =
51 Query.create(QueryType.SELECT, false, testAnswerVars, testFormula) 51 Query.create(QueryType.SELECT, false, testAnswerVars, testFormula)
52 52
53 def internal(name: String): IRI = 53 def internal(name: Any): IRI =
54 IRI.create( 54 IRI.create(
55 Prefixes.getPrefixIRIsByPrefixName.get("internal:").getIRI + name 55 Prefixes.getPrefixIRIsByPrefixName.get("internal:").getIRI
56 + name.toString
56 ) 57 )
57 58
58 // TODO: move this somewhere else... maybe an OntoUtils class or something. 59 // TODO: move this somewhere else... maybe an OntoUtils class or something.
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala
index e49d4ac..efd6e7f 100644
--- a/src/main/scala/rsacomb/RSAOntology.scala
+++ b/src/main/scala/rsacomb/RSAOntology.scala
@@ -28,7 +28,9 @@ 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) extends RSAAxiom { 31 implicit class RSAOntology(ontology: OWLOntology)
32 extends RSAAxiom
33 with RDFTriple {
32 34
33 /* Steps for RSA check 35 /* Steps for RSA check
34 * 1) convert ontology axioms into LP rules 36 * 1) convert ontology axioms into LP rules
@@ -224,28 +226,6 @@ trait RSAOntology {
224 .toList 226 .toList
225 } 227 }
226 228
227 // Is this the best way to determine if an atom is an RDF triple?
228 // Note that we can't use `getNumberOfArguments()` because is not
229 // "consistent":
230 // - for an atom created with `rdf(<term1>, <term2>, <term3>)`,
231 // `getNumberOfArguments` returns 3
232 // - for an atom created with `Atom.create(<tupletablename>, <term1>,
233 // <term2>, <term3>)`, `getNumberOfArguments()` returns 3
234 //
235 // This is probably because `Atom.rdf(...) is implemented as:
236 // ```scala
237 // def rdf(term1: Term, term2: Term, term3: Term): Atom =
238 // Atom.create(TupleTableName.create("internal:triple"), term1, term2, term3)
239 // ```
240 def isRdfTriple(atom: Atom): Boolean =
241 atom.getTupleTableName.getIRI.equals("internal:triple")
242
243 def isClassAssertion(atom: Atom): Boolean =
244 isRdfTriple(atom) && atom.getArgument(1).equals(IRI.RDF_TYPE)
245
246 def isRoleAssertion(atom: Atom): Boolean =
247 isRdfTriple(atom) && !atom.getArgument(1).equals(IRI.RDF_TYPE)
248
249 def reify( 229 def reify(
250 formula: BodyFormula, 230 formula: BodyFormula,
251 head: Boolean 231 head: Boolean
@@ -253,7 +233,7 @@ trait RSAOntology {
253 def default[A <: BodyFormula](x: A) = Unaltered(x) 233 def default[A <: BodyFormula](x: A) = Unaltered(x)
254 formula match { 234 formula match {
255 case a: Atom => { 235 case a: Atom => {
256 if (!isRdfTriple(a)) { 236 if (!a.isRdfTriple) {
257 if (head) { 237 if (head) {
258 val b = getBindAtom(a) 238 val b = getBindAtom(a)
259 ReifiedHead(b, reifyAtom(a, b.getBoundVariable)) 239 ReifiedHead(b, reifyAtom(a, b.getBoundVariable))
@@ -293,83 +273,8 @@ trait RSAOntology {
293 Rule.create(head.asJava, (skols ++ body).asJava) 273 Rule.create(head.asJava, (skols ++ body).asJava)
294 } 274 }
295 275
296 def formulaToRuleBody(body: Formula): List[BodyFormula] = {
297 body match {
298 case a: BodyFormula => List(a);
299 case a: Conjunction =>
300 a.getConjuncts().asScala.toList.flatMap(formulaToRuleBody(_));
301 case _ => List() /* We don't handle this for now */
302 }
303 }
304
305 val body = formulaToRuleBody(query.getQueryFormula)
306 val bounded: List[Term] = List()
307 val answer: List[Term] = query.getAnswerVariables.asScala.toList
308 def id(t1: Term, t2: Term) =
309 Atom.create(
310 TupleTableName.create("http://127.0.0.1/ID"),
311 (bounded ++ answer).appendedAll(List(t1, t2)).asJava
312 )
313 def tq(suffix: String, t1: Term, t2: Term) =
314 Atom.create(
315 TupleTableName.create(s"http://127.0.0.1/TQ$suffix"),
316 (bounded ++ answer).appendedAll(List(t1, t2)).asJava
317 )
318 def aq(suffix: String, t1: Term, t2: Term) =
319 Atom.create(
320 TupleTableName.create(s"http://127.0.0.1/AQ$suffix"),
321 (bounded ++ answer).appendedAll(List(t1, t2)).asJava
322 )
323 val qm =
324 Atom.create(TupleTableName.create("QM"), (bounded ++ answer).asJava)
325
326 /* Filtering program */
327 val rule1 = Rule.create(qm, body.asJava)
328 val rule3a =
329 for ((v, i) <- answer.zipWithIndex)
330 yield Rule.create(
331 id(
332 IRI.create(s"http://127.0.0.1/$i"),
333 IRI.create(s"http://127.0.0.1/$i")
334 ),
335 qm,
336 Negation.create(
337 Atom.rdf(v, IRI.RDF_TYPE, IRI.create("http://127.0.0.1/NI"))
338 )
339 )
340 val rule3b = Rule.create(
341 id(Variable.create("V"), Variable.create("U")),
342 id(Variable.create("U"), Variable.create("V"))
343 )
344 val rule3c = Rule.create(
345 id(Variable.create("U"), Variable.create("W")),
346 id(Variable.create("U"), Variable.create("V")),
347 id(Variable.create("V"), Variable.create("W"))
348 )
349 val rule7a =
350 for (r <- Seq("f", "b"))
351 yield Rule.create(
352 tq(r, Variable.create("U"), Variable.create("V")),
353 aq(r, Variable.create("U"), Variable.create("V"))
354 )
355 val rule7b =
356 for (r <- Seq("f", "b"))
357 yield Rule.create(
358 tq(r, Variable.create("U"), Variable.create("W")),
359 aq(r, Variable.create("U"), Variable.create("V")),
360 tq(r, Variable.create("V"), Variable.create("W"))
361 )
362
363 var rules: List[Rule] =
364 List.empty
365 .prependedAll(rule7b)
366 .prependedAll(rule7a)
367 .prepended(rule3c)
368 .prepended(rule3b)
369 .prependedAll(rule3a)
370 .prepended(rule1)
371
372 // DEBUG 276 // DEBUG
277 val rules = FilteringProgram(query, List()).rules
373 println("FILTERING PROGRAM:") 278 println("FILTERING PROGRAM:")
374 rules.map(skolemizeRule(_)).foreach(println(_)) 279 rules.map(skolemizeRule(_)).foreach(println(_))
375 280