aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <git@federicoigne.com>2021-10-01 16:16:31 +0100
committerFederico Igne <git@federicoigne.com>2021-10-01 16:16:31 +0100
commit360e10e686d144b918825939f48004aebc31b7f3 (patch)
tree38ab63b1da462bc683d526c22cd323ce8c0cbad4
parentbc37ee9293d8a4098edce2a77db6efa3d87b6dd2 (diff)
downloadRSAComb-360e10e686d144b918825939f48004aebc31b7f3.tar.gz
RSAComb-360e10e686d144b918825939f48004aebc31b7f3.zip
Rework naive filtering program computation to use named graphs
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala16
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala33
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala196
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala26
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala68
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala53
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala72
7 files changed, 298 insertions, 166 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 5a89bf9..6a3dca2 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
@@ -111,12 +111,13 @@ object RSAOntology {
111 * @param query the query to derive the filtering program 111 * @param query the query to derive the filtering program
112 * @return the filtering program for the given query 112 * @return the filtering program for the given query
113 */ 113 */
114 def filteringProgram( 114 def filteringProgram(query: ConjunctiveQuery): FilteringProgram =
115 graph: String,
116 query: ConjunctiveQuery
117 ): FilteringProgram =
118 Logger.timed( 115 Logger.timed(
119 FilteringProgram(FilterType.REVISED)(query), 116 {
117 val filter =
118 FilteringProgram(FilterType.REVISED, CanonGraph, FilterGraph(query))
119 filter(query)
120 },
120 "Generating filtering program", 121 "Generating filtering program",
121 Logger.DEBUG 122 Logger.DEBUG
122 ) 123 )
@@ -568,9 +569,8 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File])
568 569
569 queries map { query => 570 queries map { query =>
570 { 571 {
571 val filterNamedGraph = 572 //val graph = RSAOntology.FilterGraph(query)
572 s"http://cs.ox.ac.uk/isg/RSAComb#Filter${query.id}" 573 val filter = RSAOntology.filteringProgram(query)
573 val filter = RSAOntology.filteringProgram(filterNamedGraph, query)
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)
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala
index d6ad8c5..3015def 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala
@@ -17,25 +17,43 @@
17package uk.ac.ox.cs.rsacomb.filtering 17package uk.ac.ox.cs.rsacomb.filtering
18 18
19import tech.oxfordsemantic.jrdfox.logic.datalog.Rule 19import tech.oxfordsemantic.jrdfox.logic.datalog.Rule
20import tech.oxfordsemantic.jrdfox.logic.expression.IRI
20import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery 21import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery
21import uk.ac.ox.cs.rsacomb.util.Versioned 22import uk.ac.ox.cs.rsacomb.util.Versioned
22 23
24/** Type of filtering strategy.
25 *
26 * Mainly for testing different approaches and techniques.
27 */
23sealed trait FilterType 28sealed trait FilterType
24object FilterType { 29object FilterType {
25 case object NAIVE extends FilterType 30 case object NAIVE extends FilterType
26 case object REVISED extends FilterType 31 case object REVISED extends FilterType
27} 32}
28 33
34/** Filtering program trait */
29object FilteringProgram extends Versioned[FilterType] { 35object FilteringProgram extends Versioned[FilterType] {
30 36
31 import FilterType._ 37 import FilterType._
32 38
33 type Result = (ConjunctiveQuery) => FilteringProgram 39 type Result = (ConjunctiveQuery) => FilteringProgram
34 40
35 def apply(t: FilterType): (ConjunctiveQuery) => FilteringProgram = 41 /** Returns the right type of filtering program builder.
36 t match { 42 *
37 case NAIVE => NaiveFilteringProgram(_) 43 * @param filter type of filtering program.
38 case REVISED => RevisedFilteringProgram(_) 44 * @param source source named graph for the filtering program.
45 * @param target target named graph for the filtering program.
46 *
47 * @return the right type of filtering program builder.
48 */
49 def apply(
50 filter: FilterType,
51 source: IRI,
52 target: IRI
53 ): (ConjunctiveQuery) => FilteringProgram =
54 filter match {
55 case NAIVE => NaiveFilteringProgram(source, target, _)
56 case REVISED => RevisedFilteringProgram(source, target, _)
39 } 57 }
40} 58}
41 59
@@ -46,8 +64,11 @@ object FilteringProgram extends Versioned[FilterType] {
46 */ 64 */
47trait FilteringProgram { 65trait FilteringProgram {
48 66
49 /** Named graph used for filtering process */ 67 /** Source named graph for the filtering process */
50 val graph: String 68 val source: IRI
69
70 /** Target named graph for the filtering process */
71 val target: IRI
51 72
52 /** Query from which the filtering program is generated */ 73 /** Query from which the filtering program is generated */
53 val query: ConjunctiveQuery 74 val query: ConjunctiveQuery
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 3d9717c..1777713 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
@@ -21,23 +21,35 @@ import tech.oxfordsemantic.jrdfox.logic.Datatype
21import tech.oxfordsemantic.jrdfox.logic.datalog.{ 21import tech.oxfordsemantic.jrdfox.logic.datalog.{
22 Rule, 22 Rule,
23 TupleTableAtom, 23 TupleTableAtom,
24 TupleTableName,
24 BodyFormula, 25 BodyFormula,
25 Negation 26 Negation
26} 27}
27import tech.oxfordsemantic.jrdfox.logic.expression.{Term, Variable} 28import tech.oxfordsemantic.jrdfox.logic.expression.{
29 IRI,
30 Literal,
31 Term,
32 Variable
33}
28import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery 34import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery
29import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward} 35import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward, Nth}
30import uk.ac.ox.cs.rsacomb.util.{RSA, RDFoxUtil} 36import uk.ac.ox.cs.rsacomb.util.{DataFactory, RSA, RDFoxUtil}
31 37
32/** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ 38/** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */
33object NaiveFilteringProgram { 39object NaiveFilteringProgram {
34 40
35 /** Create a new FilteringProgram instance. 41 /** Create a new FilteringProgram instance.
36 * 42 *
43 * @param source source named graph for the filtering program.
44 * @param target target named graph for the filtering program.
37 * @param query CQ to be converted into logic rules. 45 * @param query CQ to be converted into logic rules.
38 */ 46 */
39 def apply(graph: String, query: ConjunctiveQuery): FilteringProgram = 47 def apply(
40 new NaiveFilteringProgram(graph, query) 48 source: IRI,
49 target: IRI,
50 query: ConjunctiveQuery
51 ): FilteringProgram =
52 new NaiveFilteringProgram(source, target, query)
41} 53}
42 54
43/** Filtering Program generator 55/** Filtering Program generator
@@ -47,14 +59,23 @@ object NaiveFilteringProgram {
47 * 59 *
48 * Instances can be created using the companion object. 60 * Instances can be created using the companion object.
49 */ 61 */
50class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) 62class NaiveFilteringProgram(
51 extends FilteringProgram { 63 val source: IRI,
64 val target: IRI,
65 val query: ConjunctiveQuery
66) extends FilteringProgram {
52 67
53 /** Extends capabilities of 68 /** Extends capabilities of
54 * [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]] 69 * [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]]
55 */ 70 */
56 import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._ 71 import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._
57 72
73 /** Simplify conversion to RDFox specific types */
74 import uk.ac.ox.cs.rsacomb.implicits.RDFox._
75
76 /** Simplify conversion between Java and Scala `List`s */
77 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
78
58 /** Implicit parameter used in RSA internal predicates. 79 /** Implicit parameter used in RSA internal predicates.
59 * 80 *
60 * @see [[uk.ac.ox.cs.rsacomb.util.RSA]] for more information. 81 * @see [[uk.ac.ox.cs.rsacomb.util.RSA]] for more information.
@@ -72,6 +93,13 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
72 private val varU = Variable.create("U") 93 private val varU = Variable.create("U")
73 private val varW = Variable.create("W") 94 private val varW = Variable.create("W")
74 95
96 /** `TupleTableName`s for the source/targer named graphs */
97 val tts: TupleTableName = TupleTableName.create(source.getIRI)
98 implicit val ttt: TupleTableName = TupleTableName.create(target.getIRI)
99
100 /** Set of atoms in the body of the query */
101 val queryBody: List[TupleTableAtom] = query.atoms(tts)
102
75 /** Rule generating the instances of the predicate `rsa:NI`. 103 /** Rule generating the instances of the predicate `rsa:NI`.
76 * 104 *
77 * According to the original paper, the set of `rsa:NI` is defined as 105 * According to the original paper, the set of `rsa:NI` is defined as
@@ -88,7 +116,11 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
88 * generate in the filtering program using a logic rule. 116 * generate in the filtering program using a logic rule.
89 */ 117 */
90 val nis: Rule = 118 val nis: Rule =
91 Rule.create(RSA.NI(varX), RSA.Congruent(varX, varY), RSA.Named(varY)) 119 Rule.create(
120 RSA.NI(varX),
121 RSA.Congruent(varX, varY)(tts),
122 RSA.Named(varY)(tts)
123 )
92 124
93 /** Collection of filtering program rules. */ 125 /** Collection of filtering program rules. */
94 val rules: List[Rule] = 126 val rules: List[Rule] =
@@ -101,7 +133,7 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
101 * 133 *
102 * @note corresponds to rule 1 in Table 3 in the paper. 134 * @note corresponds to rule 1 in Table 3 in the paper.
103 */ 135 */
104 val r1 = Rule.create(RSA.QM, query.atoms: _*) 136 val r1 = Rule.create(RSA.QM, queryBody: _*)
105 137
106 /** Initializes instances of `rsa:ID`. 138 /** Initializes instances of `rsa:ID`.
107 * 139 *
@@ -123,10 +155,10 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
123 * @note corresponds to rules 4x in Table 3. 155 * @note corresponds to rules 4x in Table 3.
124 */ 156 */
125 val r4a = for { 157 val r4a = for {
126 role1 <- query.atoms filter (_.isRoleAssertion) 158 role1 <- queryBody filter (_.isRoleAssertion)
127 index1 = query.bounded indexOf (role1.getArguments get 2) 159 index1 = query.bounded indexOf (role1.getArguments get 2)
128 if index1 >= 0 160 if index1 >= 0
129 role2 <- query.atoms filter (_.isRoleAssertion) 161 role2 <- queryBody filter (_.isRoleAssertion)
130 index2 = query.bounded indexOf (role2.getArguments get 2) 162 index2 = query.bounded indexOf (role2.getArguments get 2)
131 if index2 >= 0 163 if index2 >= 0
132 } yield Rule.create( 164 } yield Rule.create(
@@ -134,13 +166,20 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
134 RSA.ID(RSA(index1), RSA(index2)), 166 RSA.ID(RSA(index1), RSA(index2)),
135 role1 << Forward, 167 role1 << Forward,
136 role2 << Forward, 168 role2 << Forward,
137 not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 0)) 169 not(
170 TupleTableAtom.create(
171 tts,
172 role1.getArguments get 0,
173 RSA.CONGRUENT,
174 role2.getArguments get 0
175 )
176 )
138 ) 177 )
139 val r4b = for { 178 val r4b = for {
140 role1 <- query.atoms filter (_.isRoleAssertion) 179 role1 <- queryBody filter (_.isRoleAssertion)
141 index1 = query.bounded indexOf (role1.getArguments get 2) 180 index1 = query.bounded indexOf (role1.getArguments get 2)
142 if index1 >= 0 181 if index1 >= 0
143 role2 <- query.atoms filter (_.isRoleAssertion) 182 role2 <- queryBody filter (_.isRoleAssertion)
144 index2 = query.bounded indexOf (role2.getArguments get 0) 183 index2 = query.bounded indexOf (role2.getArguments get 0)
145 if index2 >= 0 184 if index2 >= 0
146 } yield Rule.create( 185 } yield Rule.create(
@@ -148,13 +187,20 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
148 RSA.ID(RSA(index1), RSA(index2)), 187 RSA.ID(RSA(index1), RSA(index2)),
149 role1 << Forward, 188 role1 << Forward,
150 role2 << Backward, 189 role2 << Backward,
151 not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 2)) 190 not(
191 TupleTableAtom.create(
192 tts,
193 role1.getArguments get 0,
194 RSA.CONGRUENT,
195 role2.getArguments get 2
196 )
197 )
152 ) 198 )
153 val r4c = for { 199 val r4c = for {
154 role1 <- query.atoms filter (_.isRoleAssertion) 200 role1 <- queryBody filter (_.isRoleAssertion)
155 index1 = query.bounded indexOf (role1.getArguments get 0) 201 index1 = query.bounded indexOf (role1.getArguments get 0)
156 if index1 >= 0 202 if index1 >= 0
157 role2 <- query.atoms filter (_.isRoleAssertion) 203 role2 <- queryBody filter (_.isRoleAssertion)
158 index2 = query.bounded indexOf (role2.getArguments get 0) 204 index2 = query.bounded indexOf (role2.getArguments get 0)
159 if index2 >= 0 205 if index2 >= 0
160 } yield Rule.create( 206 } yield Rule.create(
@@ -162,7 +208,14 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
162 RSA.ID(RSA(index1), RSA(index2)), 208 RSA.ID(RSA(index1), RSA(index2)),
163 role1 << Backward, 209 role1 << Backward,
164 role2 << Backward, 210 role2 << Backward,
165 not(RSA.Congruent(role1.getArguments get 2, role2.getArguments get 2)) 211 not(
212 TupleTableAtom.create(
213 tts,
214 role1.getArguments get 2,
215 RSA.CONGRUENT,
216 role2.getArguments get 2
217 )
218 )
166 ) 219 )
167 220
168 /** Recursively propagates `rsa:ID` predicate. 221 /** Recursively propagates `rsa:ID` predicate.
@@ -170,12 +223,12 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
170 * @note corresponds to rules 5x in Table 3. 223 * @note corresponds to rules 5x in Table 3.
171 */ 224 */
172 val r5a = for { 225 val r5a = for {
173 role1 <- query.atoms filter (_.isRoleAssertion) 226 role1 <- queryBody filter (_.isRoleAssertion)
174 r1arg0 = role1.getArguments get 0 227 r1arg0 = role1.getArguments get 0
175 if query.bounded contains r1arg0 228 if query.bounded contains r1arg0
176 r1arg2 = role1.getArguments get 2 229 r1arg2 = role1.getArguments get 2
177 if query.bounded contains r1arg2 230 if query.bounded contains r1arg2
178 role2 <- query.atoms filter (_.isRoleAssertion) 231 role2 <- queryBody filter (_.isRoleAssertion)
179 r2arg0 = role2.getArguments get 0 232 r2arg0 = role2.getArguments get 0
180 if query.bounded contains r2arg0 233 if query.bounded contains r2arg0
181 r2arg2 = role2.getArguments get 2 234 r2arg2 = role2.getArguments get 2
@@ -189,18 +242,18 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
189 RSA(query.bounded indexOf r1arg2), 242 RSA(query.bounded indexOf r1arg2),
190 RSA(query.bounded indexOf r2arg2) 243 RSA(query.bounded indexOf r2arg2)
191 ), 244 ),
192 RSA.Congruent(r1arg0, r2arg0), 245 TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg0),
193 role1 << Forward, 246 role1 << Forward,
194 role2 << Forward, 247 role2 << Forward,
195 not(RSA.NI(r1arg0)) 248 not(RSA.NI(r1arg0))
196 ) 249 )
197 val r5b = for { 250 val r5b = for {
198 role1 <- query.atoms filter (_.isRoleAssertion) 251 role1 <- queryBody filter (_.isRoleAssertion)
199 r1arg0 = role1.getArguments get 0 252 r1arg0 = role1.getArguments get 0
200 if query.bounded contains r1arg0 253 if query.bounded contains r1arg0
201 r1arg2 = role1.getArguments get 2 254 r1arg2 = role1.getArguments get 2
202 if query.bounded contains r1arg2 255 if query.bounded contains r1arg2
203 role2 <- query.atoms filter (_.isRoleAssertion) 256 role2 <- queryBody filter (_.isRoleAssertion)
204 r2arg0 = role2.getArguments get 0 257 r2arg0 = role2.getArguments get 0
205 if query.bounded contains r2arg0 258 if query.bounded contains r2arg0
206 r2arg2 = role2.getArguments get 2 259 r2arg2 = role2.getArguments get 2
@@ -214,18 +267,18 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
214 RSA(query.bounded indexOf r1arg2), 267 RSA(query.bounded indexOf r1arg2),
215 RSA(query.bounded indexOf r2arg0) 268 RSA(query.bounded indexOf r2arg0)
216 ), 269 ),
217 RSA.Congruent(r1arg0, r2arg2), 270 TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg2),
218 role1 << Forward, 271 role1 << Forward,
219 role2 << Backward, 272 role2 << Backward,
220 not(RSA.NI(r1arg0)) 273 not(RSA.NI(r1arg0))
221 ) 274 )
222 val r5c = for { 275 val r5c = for {
223 role1 <- query.atoms filter (_.isRoleAssertion) 276 role1 <- queryBody filter (_.isRoleAssertion)
224 r1arg0 = role1.getArguments get 0 277 r1arg0 = role1.getArguments get 0
225 if query.bounded contains r1arg0 278 if query.bounded contains r1arg0
226 r1arg2 = role1.getArguments get 2 279 r1arg2 = role1.getArguments get 2
227 if query.bounded contains r1arg2 280 if query.bounded contains r1arg2
228 role2 <- query.atoms filter (_.isRoleAssertion) 281 role2 <- queryBody filter (_.isRoleAssertion)
229 r2arg0 = role2.getArguments get 0 282 r2arg0 = role2.getArguments get 0
230 if query.bounded contains r2arg0 283 if query.bounded contains r2arg0
231 r2arg2 = role2.getArguments get 2 284 r2arg2 = role2.getArguments get 2
@@ -239,7 +292,7 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
239 RSA(query.bounded indexOf r1arg0), 292 RSA(query.bounded indexOf r1arg0),
240 RSA(query.bounded indexOf r2arg0) 293 RSA(query.bounded indexOf r2arg0)
241 ), 294 ),
242 RSA.Congruent(r1arg2, r2arg2), 295 TupleTableAtom.create(tts, r1arg2, RSA.CONGRUENT, r2arg2),
243 role1 << Backward, 296 role1 << Backward,
244 role2 << Backward, 297 role2 << Backward,
245 not(RSA.NI(r1arg2)) 298 not(RSA.NI(r1arg2))
@@ -254,14 +307,14 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
254 * @note corresponds to rules 6,7x in Table 3. 307 * @note corresponds to rules 6,7x in Table 3.
255 */ 308 */
256 val r6 = for { 309 val r6 = for {
257 role <- query.atoms filter (_.isRoleAssertion) 310 role <- queryBody filter (_.isRoleAssertion)
258 index0 = query.bounded indexOf (role.getArguments get 0) 311 index0 = query.bounded indexOf (role.getArguments get 0)
259 if index0 >= 0 312 if index0 >= 0
260 index2 = query.bounded indexOf (role.getArguments get 2) 313 index2 = query.bounded indexOf (role.getArguments get 2)
261 if index2 >= 0 314 if index2 >= 0
262 suffix <- Seq(Forward, Backward) 315 suffix <- Seq(Forward, Backward)
263 } yield Rule.create( 316 } yield Rule.create(
264 RSA.AQ(varV, varW, suffix), 317 RSA.AQ(suffix, varV, varW),
265 role << suffix, 318 role << suffix,
266 RSA.ID(RSA(index0), varV), 319 RSA.ID(RSA(index0), varV),
267 RSA.ID(RSA(index2), varW) 320 RSA.ID(RSA(index2), varW)
@@ -269,15 +322,15 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
269 val r7a = 322 val r7a =
270 for (suffix <- List(Forward, Backward)) 323 for (suffix <- List(Forward, Backward))
271 yield Rule.create( 324 yield Rule.create(
272 RSA.TQ(varU, varV, suffix), 325 RSA.TQ(suffix, varU, varV),
273 RSA.AQ(varU, varV, suffix) 326 RSA.AQ(suffix, varU, varV)
274 ) 327 )
275 val r7b = 328 val r7b =
276 for (suffix <- List(Forward, Backward)) 329 for (suffix <- List(Forward, Backward))
277 yield Rule.create( 330 yield Rule.create(
278 RSA.TQ(varU, varW, suffix), 331 RSA.TQ(suffix, varU, varW),
279 RSA.AQ(varU, varV, suffix), 332 RSA.AQ(suffix, varU, varV),
280 RSA.TQ(varV, varW, suffix) 333 RSA.TQ(suffix, varV, varW)
281 ) 334 )
282 335
283 /** Flag spurious answers. 336 /** Flag spurious answers.
@@ -286,13 +339,19 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
286 */ 339 */
287 val r8a = 340 val r8a =
288 for (v <- query.answer) 341 for (v <- query.answer)
289 yield Rule.create(RSA.SP, RSA.QM, not(RSA.Named(v))) 342 yield Rule.create(
343 RSA.SP,
344 RSA.QM,
345 not(
346 TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED)
347 )
348 )
290 val r8b = Rule.create(RSA.SP, RSA.FK) 349 val r8b = Rule.create(RSA.SP, RSA.FK)
291 val r8c = 350 val r8c =
292 for (suffix <- List(Forward, Backward)) 351 for (suffix <- List(Forward, Backward))
293 yield Rule.create( 352 yield Rule.create(
294 RSA.SP, 353 RSA.SP,
295 RSA.TQ(varV, varV, suffix) 354 RSA.TQ(suffix, varV, varV)
296 ) 355 )
297 356
298 /** Determine answers to the query 357 /** Determine answers to the query
@@ -318,9 +377,70 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery)
318 r5a ::: r5b ::: r5c ::: 377 r5a ::: r5b ::: r5c :::
319 r6 ::: r7b ::: r7a ::: 378 r6 ::: r7b ::: r7a :::
320 r8a ::: r8b :: r8c ::: 379 r8a ::: r8b :: r8c :::
321 r9 :: List()) map RDFoxUtil.reify 380 r9 :: List()) map reify
322 } 381 }
323 382
383 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.Rule Rule]].
384 *
385 * This is needed because RDFox supports only predicates of arity 1
386 * or 2, but the filtering program uses predicates with higher arity.
387 *
388 * @note we can perform a reification of the atoms thanks to the
389 * built-in `SKOLEM` funtion of RDFox.
390 */
391 def reify(rule: Rule): Rule = {
392 val (sk, as) = rule.getHead.map(reify).unzip
393 val head: List[TupleTableAtom] = as.flatten
394 val skolem: List[BodyFormula] = sk.flatten
395 val body: List[BodyFormula] = rule.getBody.map(reify).flatten
396 Rule.create(head, skolem ::: body)
397 }
398
399 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]]. */
400 private def reify(formula: BodyFormula): List[BodyFormula] = {
401 formula match {
402 case atom: TupleTableAtom => reify(atom)._2
403 case neg: Negation => {
404 val (sk, as) = neg.getNegatedAtoms
405 .map({
406 case a: TupleTableAtom => reify(a)
407 case a => (None, List(a))
408 })
409 .unzip
410 val skolem =
411 sk.flatten.map(_.getArguments.last).collect { case v: Variable => v }
412 val atoms = as.flatten
413 List(Negation.create(skolem, atoms))
414 }
415 case other => List(other)
416 }
417 }
418
419 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]]. */
420 private def reify(atom: TupleTableAtom)(implicit
421 fresh: DataFactory
422 ): (Option[TupleTableAtom], List[TupleTableAtom]) = {
423 if (atom.getArguments.length == 3) {
424 (None, List(atom))
425 } else {
426 val varS: Variable = fresh.getVariable
427 val (pred :: args): List[Term] = atom.getArguments
428 val name = pred.asInstanceOf[IRI].getIRI
429 val skolem = TupleTableAtom.create(
430 TupleTableName.SKOLEM,
431 Literal.create(name, Datatype.XSD_STRING) +: args :+ varS
432 )
433 val triple =
434 TupleTableAtom.create(atom.getTupleTableName, varS, IRI.RDF_TYPE, pred)
435 val triples = args.zipWithIndex
436 .map { case (a, i) =>
437 TupleTableAtom.create(atom.getTupleTableName, varS, name :: Nth(i), a)
438 }
439 (Some(skolem), triple :: triples)
440 }
441 }
442
324 val answerQuery = 443 val answerQuery =
325 RDFoxUtil.buildDescriptionQuery(graph, "Ans", query.answer.size) 444 RDFoxUtil.buildDescriptionQuery(target, RSA.ANS, query.answer.size)
445
326} 446}
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 ff48f1f..37c70df 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
@@ -82,18 +82,18 @@ object RSAAtom {
82 } 82 }
83 } else atom 83 } else atom
84 84
85 def reified(implicit 85 // def reified(implicit
86 fresh: DataFactory 86 // fresh: DataFactory
87 ): (Option[TupleTableAtom], List[TupleTableAtom]) = 87 // ): (Option[TupleTableAtom], List[TupleTableAtom]) =
88 if (isRDF) { 88 // if (isRDF) {
89 (None, List(atom)) 89 // (None, List(atom))
90 } else { 90 // } else {
91 val varS = fresh.getVariable 91 // val varS = fresh.getVariable
92 val skolem = RDFoxUtil.skolem(name, (args :+ varS): _*) 92 // val skolem = RDFoxUtil.skolem(name, (args :+ varS): _*)
93 val atom = TupleTableAtom.rdf(varS, IRI.RDF_TYPE, name) 93 // val atom = TupleTableAtom.rdf(varS, IRI.RDF_TYPE, name)
94 val atoms = args.zipWithIndex 94 // val atoms = args.zipWithIndex
95 .map { case (a, i) => TupleTableAtom.rdf(varS, name :: Nth(i), a) } 95 // .map { case (a, i) => TupleTableAtom.rdf(varS, name :: Nth(i), a) }
96 (Some(skolem), atom :: atoms) 96 // (Some(skolem), atom :: atoms)
97 } 97 // }
98 } 98 }
99} 99}
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala
index c405008..73da80f 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala
@@ -19,7 +19,7 @@ package uk.ac.ox.cs.rsacomb.sparql
19import java.util.{Map => JMap, HashMap => JHashMap} 19import java.util.{Map => JMap, HashMap => JHashMap}
20import tech.oxfordsemantic.jrdfox.Prefixes 20import tech.oxfordsemantic.jrdfox.Prefixes
21import tech.oxfordsemantic.jrdfox.client.DataStoreConnection 21import tech.oxfordsemantic.jrdfox.client.DataStoreConnection
22import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom 22import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName}
23import tech.oxfordsemantic.jrdfox.logic.expression.Variable 23import tech.oxfordsemantic.jrdfox.logic.expression.Variable
24import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{ 24import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{
25 ConjunctionPattern, 25 ConjunctionPattern,
@@ -99,37 +99,51 @@ class ConjunctiveQuery(
99 val bcq: Boolean = select.isEmpty && !query.getAllPossibleVariables 99 val bcq: Boolean = select.isEmpty && !query.getAllPossibleVariables
100 100
101 /** Returns the query body as a sequence of atoms (triples). */ 101 /** Returns the query body as a sequence of atoms (triples). */
102 val atoms: List[TupleTableAtom] = 102 def atoms(graph: TupleTableName): List[TupleTableAtom] =
103 where match { 103 where.collect { case c: ConjunctionPattern =>
104 case b: ConjunctionPattern => { 104 c.getConjuncts.collect { case t: TriplePattern =>
105 b.getConjuncts.toList.flatMap { conj: QueryPattern => 105 TupleTableAtom
106 conj match { 106 .create(graph, t.getSubject, t.getPredicate, t.getObject)
107 case c: TriplePattern =>
108 Seq(
109 TupleTableAtom.rdf(c.getSubject, c.getPredicate, c.getObject)
110 )
111 case _ => List()
112 }
113 }
114 } 107 }
115 case _ => List() 108 }.flatten
116 } 109 // where match {
110 // case b: ConjunctionPattern => {
111 // b.getConjuncts.toList.flatMap { conj: QueryPattern =>
112 // conj match {
113 // case c: TriplePattern =>
114 // Seq(
115 // TupleTableAtom.rdf(c.getSubject, c.getPredicate, c.getObject)
116 // )
117 // case _ => List()
118 // }
119 // }
120 // }
121 // case _ => List()
122 // }
117 123
118 /** Returns the full collection of variables involved in the query. */ 124 /** Returns the full collection of variables involved in the query. */
119 val variables: List[Variable] = (where match { 125 val variables: List[Variable] =
120 case b: ConjunctionPattern => { 126 where.collect { case c: ConjunctionPattern =>
121 b.getConjuncts.toList.flatMap { conj: QueryPattern => 127 c.getConjuncts.collect { case t: TriplePattern =>
122 conj match { 128 Set(t.getSubject, t.getPredicate, t.getObject).collect {
123 case c: TriplePattern => 129 case v: Variable => v
124 Set(c.getSubject, c.getPredicate, c.getObject).collect {
125 case v: Variable => v
126 }
127 case _ => List()
128 } 130 }
129 } 131 }
130 } 132 }.distinct
131 case _ => List() 133 // (where match {
132 }).distinct 134 // case b: ConjunctionPattern => {
135 // b.getConjuncts.toList.flatMap { conj: QueryPattern =>
136 // conj match {
137 // case c: TriplePattern =>
138 // Set(c.getSubject, c.getPredicate, c.getObject).collect {
139 // case v: Variable => v
140 // }
141 // case _ => List()
142 // }
143 // }
144 // }
145 // case _ => List()
146 // }).distinct
133 147
134 /** Returns the collection of answer variables in the query. */ 148 /** Returns the collection of answer variables in the query. */
135 val answer: List[Variable] = 149 val answer: List[Variable] =
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
index 568858c..217fa7f 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
@@ -342,8 +342,8 @@ object RDFoxUtil {
342 * @return a string containing a SPARQL query. 342 * @return a string containing a SPARQL query.
343 */ 343 */
344 def buildDescriptionQuery( 344 def buildDescriptionQuery(
345 graph: String, 345 graph: IRI,
346 pred: String, 346 pred: IRI,
347 arity: Int 347 arity: Int
348 ): String = { 348 ): String = {
349 if (arity > 0) { 349 if (arity > 0) {
@@ -351,55 +351,12 @@ object RDFoxUtil {
351 s""" 351 s"""
352 SELECT $variables 352 SELECT $variables
353 WHERE { 353 WHERE {
354 GRAPH <$graph> { ?K a rsa:$pred }. 354 GRAPH $graph { ?K a $pred }.
355 TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $variables ?K } . 355 TT ${TupleTableName.SKOLEM} { $variables ?K } .
356 } 356 }
357 """ 357 """
358 } else { 358 } else {
359 s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" 359 s"ASK { GRAPH $graph { ?X a $pred } }"
360 }
361 }
362
363 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.Rule Rule]].
364 *
365 * This is needed because RDFox supports only predicates of arity 1
366 * or 2, but the filtering program uses predicates with higher arity.
367 *
368 * @note we can perform a reification of the atoms thanks to the
369 * built-in `SKOLEM` funtion of RDFox.
370 */
371 def reify(rule: Rule): Rule = {
372 val (sk, as) = rule.getHead.map(_.reified).unzip
373 val head: List[TupleTableAtom] = as.flatten
374 val skolem: List[BodyFormula] = sk.flatten
375 val body: List[BodyFormula] = rule.getBody.map(reify).flatten
376 Rule.create(head, skolem ::: body)
377 }
378
379 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]].
380 *
381 * This is needed because RDFox supports only predicates of arity 1
382 * or 2, but the filtering program uses predicates with higher arity.
383 *
384 * @note we can perform a reification of the atoms thanks to the
385 * built-in `SKOLEM` funtion of RDFox.
386 */
387 private def reify(formula: BodyFormula): List[BodyFormula] = {
388 formula match {
389 case atom: TupleTableAtom => atom.reified._2
390 case neg: Negation => {
391 val (sk, as) = neg.getNegatedAtoms
392 .map({
393 case a: TupleTableAtom => a.reified
394 case a => (None, List(a))
395 })
396 .unzip
397 val skolem =
398 sk.flatten.map(_.getArguments.last).collect { case v: Variable => v }
399 val atoms = as.flatten
400 List(Negation.create(skolem, atoms))
401 }
402 case other => List(other)
403 } 360 }
404 } 361 }
405 362
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 96d3aa8..40c5ced 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
@@ -42,6 +42,9 @@ import scala.collection.JavaConverters._
42 42
43object RSA { 43object RSA {
44 44
45 /** Simplify conversion between Java and Scala `List`s */
46 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
47
45 /** Set of default prefixes to be included in all datastore operations */ 48 /** Set of default prefixes to be included in all datastore operations */
46 val Prefixes: Prefixes = new Prefixes() 49 val Prefixes: Prefixes = new Prefixes()
47 Prefixes.declarePrefix("rsacomb:", "http://www.cs.ox.ac.uk/isg/RSAComb#") 50 Prefixes.declarePrefix("rsacomb:", "http://www.cs.ox.ac.uk/isg/RSAComb#")
@@ -54,52 +57,69 @@ object RSA {
54 Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString 57 Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString
55 ) 58 )
56 59
57 val NAMED = RSA("Named") 60 val ANS = RSA("Ans")
58 val CONGRUENT = RSA("congruent") 61 val CONGRUENT = RSA("congruent")
59 val IN = RSA("In") 62 val IN = RSA("In")
63 val NAMED = RSA("Named")
60 64
61 // def In(t: Term)(implicit set: Term) = 65 // def In(t: Term)(implicit set: Term) =
62 // TupleTableAtom.rdf(t, RSA("In"), set) 66 // TupleTableAtom.rdf(t, RSA("In"), set)
63 67
64 // def NotIn(t: Term)(implicit set: Term) = Negation.create(In(t)(set)) 68 // def NotIn(t: Term)(implicit set: Term) = Negation.create(In(t)(set))
65 69
66 // def Congruent(t1: Term, t2: Term) = 70 def Congruent(t1: Term, t2: Term)(implicit graph: TupleTableName) =
67 // TupleTableAtom.rdf(t1, RSA("congruent"), t2) 71 TupleTableAtom.create(graph, t1, RSA.CONGRUENT, t2)
68 72
69 def QM(implicit q: ConjunctiveQuery) = 73 def Named(term: Term)(implicit graph: TupleTableName) =
70 atom(RSA("QM"), q.answer ::: q.bounded) 74 TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA.NAMED)
71 75
72 def ID(t1: Term, t2: Term)(implicit q: ConjunctiveQuery) = { 76 def QM(implicit query: ConjunctiveQuery, graph: TupleTableName) =
73 atom(RSA("ID"), (q.answer ::: q.bounded) :+ t1 :+ t2) 77 TupleTableAtom.create(graph, RSA("QM") :: query.answer ::: query.bounded)
74 }
75 78
76 def Named(t: Term) = 79 def ID(t1: Term, t2: Term)(implicit
77 TupleTableAtom.rdf(t, IRI.RDF_TYPE, RSA("Named")) 80 query: ConjunctiveQuery,
81 graph: TupleTableName
82 ) =
83 TupleTableAtom.create(
84 graph,
85 RSA("ID") +: (query.answer ::: query.bounded) :+ t1 :+ t2
86 )
78 87
79 def Thing(t: Term) = 88 // def Thing(t: Term) =
80 TupleTableAtom.rdf(t, IRI.RDF_TYPE, IRI.THING) 89 // TupleTableAtom.rdf(t, IRI.RDF_TYPE, IRI.THING)
81 90
82 def NI(t: Term) = 91 def NI(term: Term)(implicit graph: TupleTableName) =
83 TupleTableAtom.rdf(t, IRI.RDF_TYPE, RSA("NI")) 92 TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA("NI"))
84 93
85 def TQ(t1: Term, t2: Term, sx: RSASuffix)(implicit q: ConjunctiveQuery) = 94 def TQ(sx: RSASuffix, t1: Term, t2: Term)(implicit
86 atom(RSA("TQ" :: sx), (q.answer ::: q.bounded) :+ t1 :+ t2) 95 query: ConjunctiveQuery,
96 graph: TupleTableName
97 ) =
98 TupleTableAtom.create(
99 graph,
100 RSA("TQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2
101 )
87 102
88 def AQ(t1: Term, t2: Term, sx: RSASuffix)(implicit q: ConjunctiveQuery) = 103 def AQ(sx: RSASuffix, t1: Term, t2: Term)(implicit
89 atom(RSA("AQ" :: sx), (q.answer ::: q.bounded) :+ t1 :+ t2) 104 query: ConjunctiveQuery,
105 graph: TupleTableName
106 ) =
107 TupleTableAtom.create(
108 graph,
109 RSA("AQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2
110 )
90 111
91 def FK(implicit q: ConjunctiveQuery) = 112 def FK(implicit query: ConjunctiveQuery, graph: TupleTableName) =
92 atom(RSA("FK"), q.answer ::: q.bounded) 113 TupleTableAtom.create(graph, RSA("FK") :: query.answer ::: query.bounded)
93 114
94 def SP(implicit q: ConjunctiveQuery) = 115 def SP(implicit q: ConjunctiveQuery, graph: TupleTableName) =
95 atom(RSA("SP"), q.answer ::: q.bounded) 116 TupleTableAtom.create(graph, RSA("SP") :: q.answer ::: q.bounded)
96 117
97 def Ans(implicit q: ConjunctiveQuery) = { 118 def Ans(implicit q: ConjunctiveQuery, graph: TupleTableName) =
98 if (q.bcq) 119 if (q.bcq)
99 TupleTableAtom.rdf(RSA("blank"), IRI.RDF_TYPE, RSA("Ans")) 120 TupleTableAtom.create(graph, RSA("blank"), IRI.RDF_TYPE, RSA.ANS)
100 else 121 else
101 atom(RSA("Ans"), q.answer) 122 TupleTableAtom.create(graph, RSA.ANS :: q.answer)
102 }
103 123
104 /* TODO: review after reworking the dependency graph construction */ 124 /* TODO: review after reworking the dependency graph construction */
105 125