aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-24 11:41:08 +0000
committerFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-24 11:41:08 +0000
commitb7d9a8ffc8cc4a8949229b5bd3ada301878633d9 (patch)
tree8bf1ea5fcada85028fe754c902906d890546cd60
parentaeb5ad23e5f13952efdeaf4aec2e97a96b469655 (diff)
downloadRSAComb-b7d9a8ffc8cc4a8949229b5bd3ada301878633d9.tar.gz
RSAComb-b7d9a8ffc8cc4a8949229b5bd3ada301878633d9.zip
Rework filtering program generation
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/FilteringProgram.scala64
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala62
-rw-r--r--src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala343
3 files changed, 129 insertions, 340 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/FilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/FilteringProgram.scala
index 055cf2a..b70de66 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/FilteringProgram.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/FilteringProgram.scala
@@ -1,36 +1,18 @@
1package uk.ac.ox.cs.rsacomb 1package uk.ac.ox.cs.rsacomb
2 2
3//import scala.collection.JavaConverters._
3import tech.oxfordsemantic.jrdfox.logic.Datatype 4import tech.oxfordsemantic.jrdfox.logic.Datatype
4import tech.oxfordsemantic.jrdfox.logic.expression.{
5 Term,
6 IRI,
7 Variable,
8 Literal,
9 FunctionCall
10}
11import tech.oxfordsemantic.jrdfox.logic.datalog.{ 5import tech.oxfordsemantic.jrdfox.logic.datalog.{
12 Rule, 6 Rule,
13 TupleTableAtom, 7 TupleTableAtom,
14 BindAtom,
15 TupleTableName,
16 Atom,
17 BodyFormula, 8 BodyFormula,
18 Negation 9 Negation
19} 10}
20import tech.oxfordsemantic.jrdfox.logic.sparql.statement.{SelectQuery} 11import tech.oxfordsemantic.jrdfox.logic.expression.{Term, Variable}
21import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{
22 GroupGraphPattern,
23 ConjunctionPattern,
24 TriplePattern,
25 QueryPattern
26}
27
28import scala.collection.JavaConverters._
29
30import uk.ac.ox.cs.rsacomb.implicits.RSAAtom 12import uk.ac.ox.cs.rsacomb.implicits.RSAAtom
31import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Forward, Backward}
32import uk.ac.ox.cs.rsacomb.util.RSA
33import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery 13import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery
14import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward}
15import uk.ac.ox.cs.rsacomb.util.{RSA, RDFoxHelpers}
34 16
35/** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ 17/** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */
36object FilteringProgram { 18object FilteringProgram {
@@ -102,7 +84,7 @@ class FilteringProgram(query: ConjunctiveQuery, constants: List[Term])
102 * 84 *
103 * @note corresponds to rule 1 in Table 3 in the paper. 85 * @note corresponds to rule 1 in Table 3 in the paper.
104 */ 86 */
105 val r1 = reifyRule(Rule.create(RSA.QM, query.atoms: _*)) 87 val r1 = Rule.create(RSA.QM, query.atoms: _*)
106 88
107 /** Initializes instances of `rsa:Named`. 89 /** Initializes instances of `rsa:Named`.
108 * 90 *
@@ -325,39 +307,13 @@ class FilteringProgram(query: ConjunctiveQuery, constants: List[Term])
325 (r1 :: r2 ::: 307 (r1 :: r2 :::
326 r3a ::: r3b :: r3c :: 308 r3a ::: r3b :: r3c ::
327 r4a ::: r4b ::: r4c ::: 309 r4a ::: r4b ::: r4c :::
328 // r5c ::: r5b ::: r5a ::: 310 r5a ::: r5b ::: r5c :::
329 r6 ::: r7b ::: r7a ::: 311 r6 ::: r7b ::: r7a :::
330 r8a ::: r8b :: r8c ::: 312 r8a ::: r8b :: r8c :::
331 r9 :: List()) map reifyRule 313 r9 :: List()) map RDFoxHelpers.reify
332 } 314 }
333 315
334 private def reifyAtom(atom: Atom): (Option[BindAtom], List[Atom]) = { 316 /** Pretty-print filtering rule */
335 atom match { 317 override def toString(): String = rules mkString "\n"
336 case atom: TupleTableAtom => atom.reified
337 case other => (None, List(other))
338 }
339 }
340 318
341 private def reifyBodyFormula(formula: BodyFormula): List[BodyFormula] = { 319}
342 formula match {
343 case atom: TupleTableAtom => atom.reified._2
344 case neg: Negation => {
345 val (bs, as) = neg.getNegatedAtoms.asScala.toList.map(reifyAtom).unzip
346 val bind = bs.flatten.map(_.getBoundVariable).asJava
347 val atoms = as.flatten.asJava
348 List(Negation.create(bind, atoms))
349 }
350 case other => List(other)
351 }
352 }
353
354 private def reifyRule(rule: Rule): Rule = {
355 val (bs, hs) = rule.getHead.asScala.toList.map(_.reified).unzip
356 val head: List[TupleTableAtom] = hs.flatten
357 val bind: List[BodyFormula] = bs.flatten
358 val body: List[BodyFormula] =
359 rule.getBody.asScala.toList.map(reifyBodyFormula).flatten
360 Rule.create(head.asJava, (body ++ bind).asJava)
361 }
362
363} // class FilteringProgram
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
index 0f3a1cf..a05e416 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
@@ -8,12 +8,28 @@ import tech.oxfordsemantic.jrdfox.client.{
8 DataStoreConnection 8 DataStoreConnection
9} 9}
10import tech.oxfordsemantic.jrdfox.formats.SPARQLParser 10import tech.oxfordsemantic.jrdfox.formats.SPARQLParser
11import tech.oxfordsemantic.jrdfox.logic.expression.Resource 11import tech.oxfordsemantic.jrdfox.logic.datalog.{
12 Rule,
13 BodyFormula,
14 Negation,
15 TupleTableAtom,
16 TupleTableName
17}
18import tech.oxfordsemantic.jrdfox.logic.expression.{Resource}
12import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery 19import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery
13import uk.ac.ox.cs.rsacomb.suffix.Nth 20import uk.ac.ox.cs.rsacomb.suffix.Nth
21import uk.ac.ox.cs.rsacomb.implicits.RSAAtom
14 22
15/** A collection of helper methods for RDFox */ 23/** A collection of helper methods for RDFox */
16object RDFoxHelpers { 24object RDFoxHelpers extends RSAAtom {
25
26 /** Simplify conversion between Java and Scala `List`s */
27 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
28
29 /** Extends capabilities of
30 * [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]].
31 */
32 //import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._
17 33
18 /** Type alias for a collection of answers to a 34 /** Type alias for a collection of answers to a
19 * [[tech.oxfordsemantic.jrdfox.logic.sparql.statement.Query]]. 35 * [[tech.oxfordsemantic.jrdfox.logic.sparql.statement.Query]].
@@ -142,6 +158,48 @@ object RDFoxHelpers {
142 } 158 }
143 } 159 }
144 160
161 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.Rule Rule]].
162 *
163 * This is needed because RDFox supports only predicates of arity 1
164 * or 2, but the filtering program uses predicates with higher arity.
165 *
166 * @note we can perform a reification of the atoms thanks to the
167 * built-in `SKOLEM` funtion of RDFox.
168 */
169 def reify(rule: Rule): Rule = {
170 val (bs, as) = rule.getHead.map(_.reified).unzip
171 val head: List[TupleTableAtom] = as.flatten
172 val bind: List[BodyFormula] = bs.flatten
173 val body: List[BodyFormula] = rule.getBody.map(reify).flatten
174 Rule.create(head, bind ::: body)
175 }
176
177 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]].
178 *
179 * This is needed because RDFox supports only predicates of arity 1
180 * or 2, but the filtering program uses predicates with higher arity.
181 *
182 * @note we can perform a reification of the atoms thanks to the
183 * built-in `SKOLEM` funtion of RDFox.
184 */
185 private def reify(formula: BodyFormula): List[BodyFormula] = {
186 formula match {
187 case atom: TupleTableAtom => atom.reified._2
188 case neg: Negation => {
189 val (bs, as) = neg.getNegatedAtoms
190 .map({
191 case a: TupleTableAtom => a.reified
192 case a => (None, List(a))
193 })
194 .unzip
195 val bind = bs.flatten.map(_.getBoundVariable)
196 val atoms = as.flatten
197 List(Negation.create(bind, atoms))
198 }
199 case other => List(other)
200 }
201 }
202
145 /** Close an open connection to RDFox. 203 /** Close an open connection to RDFox.
146 * 204 *
147 * @param server server connection 205 * @param server server connection
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
index e9a20db..71c9a99 100644
--- a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
+++ b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
@@ -1,313 +1,88 @@
1package rsacomb 1package rsacomb
2 2
3import java.io.File
4import java.util.{ArrayList => JList}
5import org.scalatest.LoneElement
6import org.scalatest.Inspectors
7import org.scalatest.flatspec.AnyFlatSpec 3import org.scalatest.flatspec.AnyFlatSpec
8import org.scalatest.matchers.should.Matchers 4import org.scalatest.matchers.should.Matchers
9 5import tech.oxfordsemantic.jrdfox.logic.expression.IRI
10import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom
11import tech.oxfordsemantic.jrdfox.logic.expression.{Variable, IRI}
12import tech.oxfordsemantic.jrdfox.logic.sparql.statement.{Query, SelectQuery}
13import tech.oxfordsemantic.jrdfox.Prefixes
14
15import scala.collection.JavaConverters._
16
17import uk.ac.ox.cs.rsacomb.FilteringProgram 6import uk.ac.ox.cs.rsacomb.FilteringProgram
18import uk.ac.ox.cs.rsacomb.util.RDFoxHelpers 7import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery
19 8
20object FilteringProgramSpec { 9object FilteringProgramSpec {
21 10
22 val prefixes = new Prefixes() 11 val constants =
23 prefixes.declarePrefix( 12 List(IRI.create("_:iri1"), IRI.create("_:iri2"), IRI.create("_:iri3"))
24 ":",
25 "http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#"
26 )
27 prefixes.declarePrefix("rdf:", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
28 prefixes.declarePrefix("rdfs:", "http://www.w3.org/2000/01/rdf-schema#")
29 prefixes.declarePrefix("owl:", "http://www.w3.org/2002/07/owl#")
30
31 // DEBUG: Quick helper functions
32 def v(v: String): Variable = Variable.create(v)
33 def c(c: String): IRI = IRI.create(":" + c)
34
35 // QUERY 0
36
37 val query0 = RDFoxHelpers
38 .parseSelectQuery("""
39 SELECT ?subj
40 WHERE {
41 ?subj ?pred ?obj
42 }
43 """, prefixes)
44 .get
45
46 // val query0 = Query.create(
47 // QueryType.SELECT,
48 // false,
49 // List(v("subj")).asJava,
50 // Atom.rdf(v("subj"), v("pred"), v("obj"))
51 // )
52
53 // QUERY 1
54
55 val query1 = RDFoxHelpers
56 .parseSelectQuery("""
57 SELECT *
58 WHERE {
59 ?w a :Wellbore
60 }
61 """, prefixes)
62 .get
63
64 // val query1 = Query.create(
65 // QueryType.SELECT,
66 // false,
67 // List(v("w")).asJava,
68 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore"))
69 // )
70
71 // QUERY 2
72
73 val query2 = RDFoxHelpers
74 .parseSelectQuery(
75 """
76 SELECT *
77 WHERE {
78 ?w a :Wellbore ;
79 :wellboreDocument ?doc .
80 ?doc :hasURL ?document_hyperlink
81 }
82 """,
83 prefixes
84 )
85 .get
86 13
87 // val query2 = Query.create( 14 val cq0 = """
88 // QueryType.SELECT, 15 PREFIX : <http://example.com/rsa_example.owl#>
89 // false,
90 // List(v("w"), v("doc"), v("document_hyperlink")).asJava,
91 // Conjunction.create(
92 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
93 // Atom.rdf(v("w"), c("wellboreDocument"), v("doc")),
94 // Atom.rdf(v("doc"), c("hasURL"), v("document_hyperlink"))
95 // )
96 // )
97 16
98 // QUERY 3 17 SELECT ?X
99
100 val query3 = RDFoxHelpers
101 .parseSelectQuery(
102 """
103 SELECT ?wellbore ?formation_pressure
104 WHERE { 18 WHERE {
105 ?w a :Wellbore ; 19 ?X a :D ;
106 :name ?wellbore ; 20 :R ?Y .
107 :hasFormationPressure ?fp . 21 ?Y :S ?Z .
108 ?fp :valueInStandardUnit ?formation_pressure 22 ?Z a :D .
109 } 23 }
110 """, 24 """
111 prefixes
112 )
113 .get
114
115 // val query3 = Query.create(
116 // QueryType.SELECT,
117 // false,
118 // List(v("wellbore"), v("formation_pressure")).asJava,
119 // Conjunction.create(
120 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
121 // Atom.rdf(v("w"), c("name"), v("wellbore")),
122 // Atom.rdf(v("w"), c("hasFormationPressure"), v("fp")),
123 // Atom.rdf(v("fp"), c("valueInStandardUnit"), v("formation_pressure"))
124 // )
125 // )
126 25
127 // QUERY 4 26 val cq1 = """
27 PREFIX : <http://example.com/rsa_example.owl#>
128 28
129 val query4 = RDFoxHelpers 29 SELECT *
130 .parseSelectQuery(
131 """
132 SELECT *
133 WHERE { 30 WHERE {
134 ?w a :Wellbore ; 31 ?X a :D ;
135 :hasGeochemicalMeasurement ?measurement . 32 :R ?Y .
136 ?measurement :cgType ?cgtype ; 33 ?Y :S ?Z .
137 :peakName ?peakType ; 34 ?Z a :D .
138 :peakHeight ?peak_height ;
139 :peakAmount ?peak_amount
140 } 35 }
141 """, 36 """
142 prefixes
143 )
144 .get
145 37
146 // val query4 = Query.create( 38 val cq2 = """
147 // QueryType.SELECT, 39 PREFIX : <http://example.com/rsa_example.owl#>
148 // false,
149 // List(
150 // v("w"),
151 // v("measurement"),
152 // v("cgtype"),
153 // v("peakType"),
154 // v("peak_height"),
155 // v("peak_amount")
156 // ).asJava,
157 // Conjunction.create(
158 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
159 // Atom.rdf(v("w"), c("hasGeochemicalMeasurement"), v("measurement")),
160 // Atom.rdf(v("measurement"), c("cgType"), v("cgtype")),
161 // Atom.rdf(v("measurement"), c("peakName"), v("peakType")),
162 // Atom.rdf(v("measurement"), c("peakHeight"), v("peak_height")),
163 // Atom.rdf(v("measurement"), c("peakAmount"), v("peak_amount"))
164 // )
165 // )
166 40
167 // QUERY 5 41 SELECT ?X
168
169 val query5 = RDFoxHelpers
170 .parseSelectQuery(
171 """
172 SELECT ?wellbore ?unit_name ?discovery
173 WHERE { 42 WHERE {
174 ?w a :Wellbore ; 43 ?X a :D ;
175 :name ?wellbore ; 44 :R ?Y .
176 :hasWellboreInterval ?c_int ; 45 ?Y :S ?Z .
177 :hasWellboreInterval ?f_int . 46 ?Y :T ?W .
178 ?c_int :hasUnit ?c_unit . 47 ?Z a :D .
179 ?c_unit :name ?unit_name . 48 ?W a :D
180 ?f_int a :FluidZone ;
181 :name ?discovery ;
182 :overlapsWellboreInterval ?c_int
183 } 49 }
184 """, 50 """
185 prefixes
186 )
187 .get
188
189 // val query5 = Query.create(
190 // QueryType.SELECT,
191 // false,
192 // List(v("wellbore"), v("unit_name"), v("discovery")).asJava,
193 // Conjunction.create(
194 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
195 // Atom.rdf(v("w"), c("name"), v("wellbore")),
196 // Atom.rdf(v("w"), c("hasWellboreInterval"), v("c_int")),
197 // Atom.rdf(v("w"), c("hasWellboreInterval"), v("f_int")),
198 // Atom.rdf(v("c_int"), c("hasUnit"), v("c_unit")),
199 // Atom.rdf(v("c_unit"), c("name"), v("unit_name")),
200 // Atom.rdf(v("f_int"), IRI.RDF_TYPE, c("FluidZone")),
201 // Atom.rdf(v("f_int"), c("name"), v("discovery")),
202 // Atom.rdf(v("f_int"), c("overlapsWellboreInterval"), v("c_int"))
203 // )
204 // )
205 51
206 // QUERY 6 52 val bcq0 = """
53 PREFIX : <http://example.com/rsa_example.owl#>
207 54
208 val query6 = RDFoxHelpers 55 ASK {
209 .parseSelectQuery( 56 ?X a :D ;
210 """ 57 :R ?Y .
211 SELECT DISTINCT ?wellbore ?content 58 ?Y :S ?Z .
212 WHERE { 59 ?Z a :D .
213 ?w a :Wellbore ;
214 :name ?wellbore ;
215 :hasWellboreInterval ?int .
216 ?int a :FluidZone ;
217 :fluidZoneContent ?content
218 } 60 }
219 """, 61 """
220 prefixes
221 )
222 .get
223
224 // val query6 = Query.create(
225 // QueryType.SELECT,
226 // true,
227 // List(v("wellbore"), v("content")).asJava,
228 // Conjunction.create(
229 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
230 // Atom.rdf(v("w"), c("name"), v("wellbore")),
231 // Atom.rdf(v("w"), c("hasWellboreInterval"), v("int")),
232 // Atom.rdf(v("int"), IRI.RDF_TYPE, c("FluidZone")),
233 // Atom.rdf(v("int"), c("fluidZoneContent"), v("content"))
234 // )
235 // )
236
237 // QUERY 7
238
239 val query7 = RDFoxHelpers
240 .parseSelectQuery(
241 """
242 SELECT ?wName ?sample ?porosity ?top_depth_md ?bot_depth_md
243 WHERE {
244 ?w a :Wellbore ;
245 :name ?wName ;
246 :hasWellboreInterval ?z .
247 ?z :hasUnit ?u .
248 ?u :name ?strat_unit_name .
249 ?wellbore :hasWellboreInterval ?cored_int .
250 ?c :extractedFrom ?cored_int ;
251 :hasCoreSample ?sample .
252 ?sample :hasDepth ?sample_depth .
253 ?sample_depth
254 :inWellboreInterval ?z .
255 ?sample :hasPorosity ?p .
256 ?p :valueInStandardUnit ?porosity .
257 ?z :hasTopDepth ?top .
258 ?top a :MeasuredDepth ;
259 :valueInStandardUnit ?top_depth_md .
260 ?z :hasBottomDepth ?bot .
261 ?bot a :MeasuredDepth ;
262 :valueInStandardUnit ?bot_depth_md
263 }
264 """,
265 prefixes
266 )
267 .get
268
269 // val query7 = Query.create(
270 // QueryType.SELECT,
271 // false,
272 // List(
273 // v("wName"),
274 // v("sample"),
275 // v("porosity"),
276 // v("top_depth_md"),
277 // v("bot_depth_md")
278 // ).asJava,
279 // Conjunction.create(
280 // Atom.rdf(v("w"), IRI.RDF_TYPE, c("Wellbore")),
281 // Atom.rdf(v("w"), c("name"), v("wName")),
282 // Atom.rdf(v("w"), c("hasWellboreInterval"), v("z")),
283 // Atom.rdf(v("z"), c("hasUnit"), v("u")),
284 // Atom.rdf(v("u"), c("name"), v("strat_unit_name")),
285 // Atom.rdf(v("wellbore"), c("hasWellboreInterval"), v("cored_int")),
286 // Atom.rdf(v("c"), c("extractedFrom"), v("cored_int")),
287 // Atom.rdf(v("c"), c("hasCoreSample"), v("sample")),
288 // Atom.rdf(v("sample"), c("hasDepth"), v("sample_depth")),
289 // Atom.rdf(v("sample_depth"), c("inWellboreInterval"), v("z")),
290 // Atom.rdf(v("sample"), c("hasPorosity"), v("p")),
291 // Atom.rdf(v("p"), c("valueInStandardUnit"), v("porosity")),
292 // Atom.rdf(v("z"), c("hasTopDepth"), v("top")),
293 // Atom.rdf(v("top"), IRI.RDF_TYPE, c("MeasuredDepth")),
294 // Atom.rdf(v("top"), c("valueInStandardUnit"), v("top_depth_md")),
295 // Atom.rdf(v("z"), c("hasBottomDepth"), v("bot")),
296 // Atom.rdf(v("bot"), IRI.RDF_TYPE, c("MeasuredDepth")),
297 // Atom.rdf(v("bot"), c("valueInStandardUnit"), v("bot_depth_md"))
298 // )
299 // )
300
301 val queries =
302 List(query0, query1, query2, query3, query4, query5, query6, query7)
303} 62}
304 63
305class FilteringProgramSpec 64class FilteringProgramSpec extends AnyFlatSpec with Matchers {
306 extends AnyFlatSpec
307 with Matchers
308 with LoneElement
309 with Inspectors {
310 65
311 import FilteringProgramSpec._ 66 import FilteringProgramSpec._
312 67
68 "CQ 0" should "generate 30 rules" in {
69 val cq = ConjunctiveQuery(cq0).get
70 FilteringProgram(cq, constants).rules should have length 30
71 }
72
73 "CQ 1" should "generate 15 rules" in {
74 val cq = ConjunctiveQuery(cq1).get
75 FilteringProgram(cq, List()).rules should have length 15
76 }
77
78 "CQ 2" should "generate 51 rules" in {
79 val cq = ConjunctiveQuery(cq2).get
80 FilteringProgram(cq, List()).rules should have length 51
81 }
82
83 "BCQ 0" should "generate 46 rules" in {
84 val cq = ConjunctiveQuery(bcq0).get
85 FilteringProgram(cq, constants).rules should have length 46
86 }
87
313} 88}