From 360e10e686d144b918825939f48004aebc31b7f3 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Fri, 1 Oct 2021 16:16:31 +0100 Subject: Rework naive filtering program computation to use named graphs --- .../scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 16 +- .../ox/cs/rsacomb/filtering/FilteringProgram.scala | 33 +++- .../rsacomb/filtering/NaiveFilteringProgram.scala | 196 +++++++++++++++++---- .../uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala | 26 +-- .../ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala | 68 ++++--- .../scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala | 53 +----- src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala | 72 +++++--- 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 { * @param query the query to derive the filtering program * @return the filtering program for the given query */ - def filteringProgram( - graph: String, - query: ConjunctiveQuery - ): FilteringProgram = + def filteringProgram(query: ConjunctiveQuery): FilteringProgram = Logger.timed( - FilteringProgram(FilterType.REVISED)(query), + { + val filter = + FilteringProgram(FilterType.REVISED, CanonGraph, FilterGraph(query)) + filter(query) + }, "Generating filtering program", Logger.DEBUG ) @@ -568,9 +569,8 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) queries map { query => { - val filterNamedGraph = - s"http://cs.ox.ac.uk/isg/RSAComb#Filter${query.id}" - val filter = RSAOntology.filteringProgram(filterNamedGraph, query) + //val graph = RSAOntology.FilterGraph(query) + val filter = RSAOntology.filteringProgram(query) /* Add filtering program */ Logger print s"Filtering program rules: ${filter.rules.length}" 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 @@ package uk.ac.ox.cs.rsacomb.filtering import tech.oxfordsemantic.jrdfox.logic.datalog.Rule +import tech.oxfordsemantic.jrdfox.logic.expression.IRI import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery import uk.ac.ox.cs.rsacomb.util.Versioned +/** Type of filtering strategy. + * + * Mainly for testing different approaches and techniques. + */ sealed trait FilterType object FilterType { case object NAIVE extends FilterType case object REVISED extends FilterType } +/** Filtering program trait */ object FilteringProgram extends Versioned[FilterType] { import FilterType._ type Result = (ConjunctiveQuery) => FilteringProgram - def apply(t: FilterType): (ConjunctiveQuery) => FilteringProgram = - t match { - case NAIVE => NaiveFilteringProgram(_) - case REVISED => RevisedFilteringProgram(_) + /** Returns the right type of filtering program builder. + * + * @param filter type of filtering program. + * @param source source named graph for the filtering program. + * @param target target named graph for the filtering program. + * + * @return the right type of filtering program builder. + */ + def apply( + filter: FilterType, + source: IRI, + target: IRI + ): (ConjunctiveQuery) => FilteringProgram = + filter match { + case NAIVE => NaiveFilteringProgram(source, target, _) + case REVISED => RevisedFilteringProgram(source, target, _) } } @@ -46,8 +64,11 @@ object FilteringProgram extends Versioned[FilterType] { */ trait FilteringProgram { - /** Named graph used for filtering process */ - val graph: String + /** Source named graph for the filtering process */ + val source: IRI + + /** Target named graph for the filtering process */ + val target: IRI /** Query from which the filtering program is generated */ 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 import tech.oxfordsemantic.jrdfox.logic.datalog.{ Rule, TupleTableAtom, + TupleTableName, BodyFormula, Negation } -import tech.oxfordsemantic.jrdfox.logic.expression.{Term, Variable} +import tech.oxfordsemantic.jrdfox.logic.expression.{ + IRI, + Literal, + Term, + Variable +} import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery -import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward} -import uk.ac.ox.cs.rsacomb.util.{RSA, RDFoxUtil} +import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward, Nth} +import uk.ac.ox.cs.rsacomb.util.{DataFactory, RSA, RDFoxUtil} /** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ object NaiveFilteringProgram { /** Create a new FilteringProgram instance. * + * @param source source named graph for the filtering program. + * @param target target named graph for the filtering program. * @param query CQ to be converted into logic rules. */ - def apply(graph: String, query: ConjunctiveQuery): FilteringProgram = - new NaiveFilteringProgram(graph, query) + def apply( + source: IRI, + target: IRI, + query: ConjunctiveQuery + ): FilteringProgram = + new NaiveFilteringProgram(source, target, query) } /** Filtering Program generator @@ -47,14 +59,23 @@ object NaiveFilteringProgram { * * Instances can be created using the companion object. */ -class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) - extends FilteringProgram { +class NaiveFilteringProgram( + val source: IRI, + val target: IRI, + val query: ConjunctiveQuery +) extends FilteringProgram { /** Extends capabilities of * [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]] */ import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._ + /** Simplify conversion to RDFox specific types */ + import uk.ac.ox.cs.rsacomb.implicits.RDFox._ + + /** Simplify conversion between Java and Scala `List`s */ + import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ + /** Implicit parameter used in RSA internal predicates. * * @see [[uk.ac.ox.cs.rsacomb.util.RSA]] for more information. @@ -72,6 +93,13 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) private val varU = Variable.create("U") private val varW = Variable.create("W") + /** `TupleTableName`s for the source/targer named graphs */ + val tts: TupleTableName = TupleTableName.create(source.getIRI) + implicit val ttt: TupleTableName = TupleTableName.create(target.getIRI) + + /** Set of atoms in the body of the query */ + val queryBody: List[TupleTableAtom] = query.atoms(tts) + /** Rule generating the instances of the predicate `rsa:NI`. * * 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) * generate in the filtering program using a logic rule. */ val nis: Rule = - Rule.create(RSA.NI(varX), RSA.Congruent(varX, varY), RSA.Named(varY)) + Rule.create( + RSA.NI(varX), + RSA.Congruent(varX, varY)(tts), + RSA.Named(varY)(tts) + ) /** Collection of filtering program rules. */ val rules: List[Rule] = @@ -101,7 +133,7 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) * * @note corresponds to rule 1 in Table 3 in the paper. */ - val r1 = Rule.create(RSA.QM, query.atoms: _*) + val r1 = Rule.create(RSA.QM, queryBody: _*) /** Initializes instances of `rsa:ID`. * @@ -123,10 +155,10 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) * @note corresponds to rules 4x in Table 3. */ val r4a = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) index1 = query.bounded indexOf (role1.getArguments get 2) if index1 >= 0 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) index2 = query.bounded indexOf (role2.getArguments get 2) if index2 >= 0 } yield Rule.create( @@ -134,13 +166,20 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA.ID(RSA(index1), RSA(index2)), role1 << Forward, role2 << Forward, - not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 0)) + not( + TupleTableAtom.create( + tts, + role1.getArguments get 0, + RSA.CONGRUENT, + role2.getArguments get 0 + ) + ) ) val r4b = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) index1 = query.bounded indexOf (role1.getArguments get 2) if index1 >= 0 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) index2 = query.bounded indexOf (role2.getArguments get 0) if index2 >= 0 } yield Rule.create( @@ -148,13 +187,20 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA.ID(RSA(index1), RSA(index2)), role1 << Forward, role2 << Backward, - not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 2)) + not( + TupleTableAtom.create( + tts, + role1.getArguments get 0, + RSA.CONGRUENT, + role2.getArguments get 2 + ) + ) ) val r4c = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) index1 = query.bounded indexOf (role1.getArguments get 0) if index1 >= 0 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) index2 = query.bounded indexOf (role2.getArguments get 0) if index2 >= 0 } yield Rule.create( @@ -162,7 +208,14 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA.ID(RSA(index1), RSA(index2)), role1 << Backward, role2 << Backward, - not(RSA.Congruent(role1.getArguments get 2, role2.getArguments get 2)) + not( + TupleTableAtom.create( + tts, + role1.getArguments get 2, + RSA.CONGRUENT, + role2.getArguments get 2 + ) + ) ) /** Recursively propagates `rsa:ID` predicate. @@ -170,12 +223,12 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) * @note corresponds to rules 5x in Table 3. */ val r5a = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) r1arg0 = role1.getArguments get 0 if query.bounded contains r1arg0 r1arg2 = role1.getArguments get 2 if query.bounded contains r1arg2 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) r2arg0 = role2.getArguments get 0 if query.bounded contains r2arg0 r2arg2 = role2.getArguments get 2 @@ -189,18 +242,18 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA(query.bounded indexOf r1arg2), RSA(query.bounded indexOf r2arg2) ), - RSA.Congruent(r1arg0, r2arg0), + TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg0), role1 << Forward, role2 << Forward, not(RSA.NI(r1arg0)) ) val r5b = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) r1arg0 = role1.getArguments get 0 if query.bounded contains r1arg0 r1arg2 = role1.getArguments get 2 if query.bounded contains r1arg2 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) r2arg0 = role2.getArguments get 0 if query.bounded contains r2arg0 r2arg2 = role2.getArguments get 2 @@ -214,18 +267,18 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA(query.bounded indexOf r1arg2), RSA(query.bounded indexOf r2arg0) ), - RSA.Congruent(r1arg0, r2arg2), + TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg2), role1 << Forward, role2 << Backward, not(RSA.NI(r1arg0)) ) val r5c = for { - role1 <- query.atoms filter (_.isRoleAssertion) + role1 <- queryBody filter (_.isRoleAssertion) r1arg0 = role1.getArguments get 0 if query.bounded contains r1arg0 r1arg2 = role1.getArguments get 2 if query.bounded contains r1arg2 - role2 <- query.atoms filter (_.isRoleAssertion) + role2 <- queryBody filter (_.isRoleAssertion) r2arg0 = role2.getArguments get 0 if query.bounded contains r2arg0 r2arg2 = role2.getArguments get 2 @@ -239,7 +292,7 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) RSA(query.bounded indexOf r1arg0), RSA(query.bounded indexOf r2arg0) ), - RSA.Congruent(r1arg2, r2arg2), + TupleTableAtom.create(tts, r1arg2, RSA.CONGRUENT, r2arg2), role1 << Backward, role2 << Backward, not(RSA.NI(r1arg2)) @@ -254,14 +307,14 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) * @note corresponds to rules 6,7x in Table 3. */ val r6 = for { - role <- query.atoms filter (_.isRoleAssertion) + role <- queryBody filter (_.isRoleAssertion) index0 = query.bounded indexOf (role.getArguments get 0) if index0 >= 0 index2 = query.bounded indexOf (role.getArguments get 2) if index2 >= 0 suffix <- Seq(Forward, Backward) } yield Rule.create( - RSA.AQ(varV, varW, suffix), + RSA.AQ(suffix, varV, varW), role << suffix, RSA.ID(RSA(index0), varV), RSA.ID(RSA(index2), varW) @@ -269,15 +322,15 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) val r7a = for (suffix <- List(Forward, Backward)) yield Rule.create( - RSA.TQ(varU, varV, suffix), - RSA.AQ(varU, varV, suffix) + RSA.TQ(suffix, varU, varV), + RSA.AQ(suffix, varU, varV) ) val r7b = for (suffix <- List(Forward, Backward)) yield Rule.create( - RSA.TQ(varU, varW, suffix), - RSA.AQ(varU, varV, suffix), - RSA.TQ(varV, varW, suffix) + RSA.TQ(suffix, varU, varW), + RSA.AQ(suffix, varU, varV), + RSA.TQ(suffix, varV, varW) ) /** Flag spurious answers. @@ -286,13 +339,19 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) */ val r8a = for (v <- query.answer) - yield Rule.create(RSA.SP, RSA.QM, not(RSA.Named(v))) + yield Rule.create( + RSA.SP, + RSA.QM, + not( + TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED) + ) + ) val r8b = Rule.create(RSA.SP, RSA.FK) val r8c = for (suffix <- List(Forward, Backward)) yield Rule.create( RSA.SP, - RSA.TQ(varV, varV, suffix) + RSA.TQ(suffix, varV, varV) ) /** Determine answers to the query @@ -318,9 +377,70 @@ class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) r5a ::: r5b ::: r5c ::: r6 ::: r7b ::: r7a ::: r8a ::: r8b :: r8c ::: - r9 :: List()) map RDFoxUtil.reify + r9 :: List()) map reify } + /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.Rule Rule]]. + * + * This is needed because RDFox supports only predicates of arity 1 + * or 2, but the filtering program uses predicates with higher arity. + * + * @note we can perform a reification of the atoms thanks to the + * built-in `SKOLEM` funtion of RDFox. + */ + def reify(rule: Rule): Rule = { + val (sk, as) = rule.getHead.map(reify).unzip + val head: List[TupleTableAtom] = as.flatten + val skolem: List[BodyFormula] = sk.flatten + val body: List[BodyFormula] = rule.getBody.map(reify).flatten + Rule.create(head, skolem ::: body) + } + + /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]]. */ + private def reify(formula: BodyFormula): List[BodyFormula] = { + formula match { + case atom: TupleTableAtom => reify(atom)._2 + case neg: Negation => { + val (sk, as) = neg.getNegatedAtoms + .map({ + case a: TupleTableAtom => reify(a) + case a => (None, List(a)) + }) + .unzip + val skolem = + sk.flatten.map(_.getArguments.last).collect { case v: Variable => v } + val atoms = as.flatten + List(Negation.create(skolem, atoms)) + } + case other => List(other) + } + } + + /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]]. */ + private def reify(atom: TupleTableAtom)(implicit + fresh: DataFactory + ): (Option[TupleTableAtom], List[TupleTableAtom]) = { + if (atom.getArguments.length == 3) { + (None, List(atom)) + } else { + val varS: Variable = fresh.getVariable + val (pred :: args): List[Term] = atom.getArguments + val name = pred.asInstanceOf[IRI].getIRI + val skolem = TupleTableAtom.create( + TupleTableName.SKOLEM, + Literal.create(name, Datatype.XSD_STRING) +: args :+ varS + ) + val triple = + TupleTableAtom.create(atom.getTupleTableName, varS, IRI.RDF_TYPE, pred) + val triples = args.zipWithIndex + .map { case (a, i) => + TupleTableAtom.create(atom.getTupleTableName, varS, name :: Nth(i), a) + } + (Some(skolem), triple :: triples) + } + } + val answerQuery = - RDFoxUtil.buildDescriptionQuery(graph, "Ans", query.answer.size) + RDFoxUtil.buildDescriptionQuery(target, RSA.ANS, query.answer.size) + } 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 { } } else atom - def reified(implicit - fresh: DataFactory - ): (Option[TupleTableAtom], List[TupleTableAtom]) = - if (isRDF) { - (None, List(atom)) - } else { - val varS = fresh.getVariable - val skolem = RDFoxUtil.skolem(name, (args :+ varS): _*) - val atom = TupleTableAtom.rdf(varS, IRI.RDF_TYPE, name) - val atoms = args.zipWithIndex - .map { case (a, i) => TupleTableAtom.rdf(varS, name :: Nth(i), a) } - (Some(skolem), atom :: atoms) - } + // def reified(implicit + // fresh: DataFactory + // ): (Option[TupleTableAtom], List[TupleTableAtom]) = + // if (isRDF) { + // (None, List(atom)) + // } else { + // val varS = fresh.getVariable + // val skolem = RDFoxUtil.skolem(name, (args :+ varS): _*) + // val atom = TupleTableAtom.rdf(varS, IRI.RDF_TYPE, name) + // val atoms = args.zipWithIndex + // .map { case (a, i) => TupleTableAtom.rdf(varS, name :: Nth(i), a) } + // (Some(skolem), atom :: atoms) + // } } } 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 import java.util.{Map => JMap, HashMap => JHashMap} import tech.oxfordsemantic.jrdfox.Prefixes import tech.oxfordsemantic.jrdfox.client.DataStoreConnection -import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom +import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} import tech.oxfordsemantic.jrdfox.logic.expression.Variable import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{ ConjunctionPattern, @@ -99,37 +99,51 @@ class ConjunctiveQuery( val bcq: Boolean = select.isEmpty && !query.getAllPossibleVariables /** Returns the query body as a sequence of atoms (triples). */ - val atoms: List[TupleTableAtom] = - where match { - case b: ConjunctionPattern => { - b.getConjuncts.toList.flatMap { conj: QueryPattern => - conj match { - case c: TriplePattern => - Seq( - TupleTableAtom.rdf(c.getSubject, c.getPredicate, c.getObject) - ) - case _ => List() - } - } + def atoms(graph: TupleTableName): List[TupleTableAtom] = + where.collect { case c: ConjunctionPattern => + c.getConjuncts.collect { case t: TriplePattern => + TupleTableAtom + .create(graph, t.getSubject, t.getPredicate, t.getObject) } - case _ => List() - } + }.flatten + // where match { + // case b: ConjunctionPattern => { + // b.getConjuncts.toList.flatMap { conj: QueryPattern => + // conj match { + // case c: TriplePattern => + // Seq( + // TupleTableAtom.rdf(c.getSubject, c.getPredicate, c.getObject) + // ) + // case _ => List() + // } + // } + // } + // case _ => List() + // } /** Returns the full collection of variables involved in the query. */ - val variables: List[Variable] = (where match { - case b: ConjunctionPattern => { - b.getConjuncts.toList.flatMap { conj: QueryPattern => - conj match { - case c: TriplePattern => - Set(c.getSubject, c.getPredicate, c.getObject).collect { - case v: Variable => v - } - case _ => List() + val variables: List[Variable] = + where.collect { case c: ConjunctionPattern => + c.getConjuncts.collect { case t: TriplePattern => + Set(t.getSubject, t.getPredicate, t.getObject).collect { + case v: Variable => v } } - } - case _ => List() - }).distinct + }.distinct + // (where match { + // case b: ConjunctionPattern => { + // b.getConjuncts.toList.flatMap { conj: QueryPattern => + // conj match { + // case c: TriplePattern => + // Set(c.getSubject, c.getPredicate, c.getObject).collect { + // case v: Variable => v + // } + // case _ => List() + // } + // } + // } + // case _ => List() + // }).distinct /** Returns the collection of answer variables in the query. */ 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 { * @return a string containing a SPARQL query. */ def buildDescriptionQuery( - graph: String, - pred: String, + graph: IRI, + pred: IRI, arity: Int ): String = { if (arity > 0) { @@ -351,55 +351,12 @@ object RDFoxUtil { s""" SELECT $variables WHERE { - GRAPH <$graph> { ?K a rsa:$pred }. - TT { $variables ?K } . + GRAPH $graph { ?K a $pred }. + TT ${TupleTableName.SKOLEM} { $variables ?K } . } """ } else { - s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" - } - } - - /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.Rule Rule]]. - * - * This is needed because RDFox supports only predicates of arity 1 - * or 2, but the filtering program uses predicates with higher arity. - * - * @note we can perform a reification of the atoms thanks to the - * built-in `SKOLEM` funtion of RDFox. - */ - def reify(rule: Rule): Rule = { - val (sk, as) = rule.getHead.map(_.reified).unzip - val head: List[TupleTableAtom] = as.flatten - val skolem: List[BodyFormula] = sk.flatten - val body: List[BodyFormula] = rule.getBody.map(reify).flatten - Rule.create(head, skolem ::: body) - } - - /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]]. - * - * This is needed because RDFox supports only predicates of arity 1 - * or 2, but the filtering program uses predicates with higher arity. - * - * @note we can perform a reification of the atoms thanks to the - * built-in `SKOLEM` funtion of RDFox. - */ - private def reify(formula: BodyFormula): List[BodyFormula] = { - formula match { - case atom: TupleTableAtom => atom.reified._2 - case neg: Negation => { - val (sk, as) = neg.getNegatedAtoms - .map({ - case a: TupleTableAtom => a.reified - case a => (None, List(a)) - }) - .unzip - val skolem = - sk.flatten.map(_.getArguments.last).collect { case v: Variable => v } - val atoms = as.flatten - List(Negation.create(skolem, atoms)) - } - case other => List(other) + s"ASK { GRAPH $graph { ?X a $pred } }" } } 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._ object RSA { + /** Simplify conversion between Java and Scala `List`s */ + import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ + /** Set of default prefixes to be included in all datastore operations */ val Prefixes: Prefixes = new Prefixes() Prefixes.declarePrefix("rsacomb:", "http://www.cs.ox.ac.uk/isg/RSAComb#") @@ -54,52 +57,69 @@ object RSA { Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString ) - val NAMED = RSA("Named") + val ANS = RSA("Ans") val CONGRUENT = RSA("congruent") val IN = RSA("In") + val NAMED = RSA("Named") // def In(t: Term)(implicit set: Term) = // TupleTableAtom.rdf(t, RSA("In"), set) // def NotIn(t: Term)(implicit set: Term) = Negation.create(In(t)(set)) - // def Congruent(t1: Term, t2: Term) = - // TupleTableAtom.rdf(t1, RSA("congruent"), t2) + def Congruent(t1: Term, t2: Term)(implicit graph: TupleTableName) = + TupleTableAtom.create(graph, t1, RSA.CONGRUENT, t2) - def QM(implicit q: ConjunctiveQuery) = - atom(RSA("QM"), q.answer ::: q.bounded) + def Named(term: Term)(implicit graph: TupleTableName) = + TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA.NAMED) - def ID(t1: Term, t2: Term)(implicit q: ConjunctiveQuery) = { - atom(RSA("ID"), (q.answer ::: q.bounded) :+ t1 :+ t2) - } + def QM(implicit query: ConjunctiveQuery, graph: TupleTableName) = + TupleTableAtom.create(graph, RSA("QM") :: query.answer ::: query.bounded) - def Named(t: Term) = - TupleTableAtom.rdf(t, IRI.RDF_TYPE, RSA("Named")) + def ID(t1: Term, t2: Term)(implicit + query: ConjunctiveQuery, + graph: TupleTableName + ) = + TupleTableAtom.create( + graph, + RSA("ID") +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) - def Thing(t: Term) = - TupleTableAtom.rdf(t, IRI.RDF_TYPE, IRI.THING) + // def Thing(t: Term) = + // TupleTableAtom.rdf(t, IRI.RDF_TYPE, IRI.THING) - def NI(t: Term) = - TupleTableAtom.rdf(t, IRI.RDF_TYPE, RSA("NI")) + def NI(term: Term)(implicit graph: TupleTableName) = + TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA("NI")) - def TQ(t1: Term, t2: Term, sx: RSASuffix)(implicit q: ConjunctiveQuery) = - atom(RSA("TQ" :: sx), (q.answer ::: q.bounded) :+ t1 :+ t2) + def TQ(sx: RSASuffix, t1: Term, t2: Term)(implicit + query: ConjunctiveQuery, + graph: TupleTableName + ) = + TupleTableAtom.create( + graph, + RSA("TQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) - def AQ(t1: Term, t2: Term, sx: RSASuffix)(implicit q: ConjunctiveQuery) = - atom(RSA("AQ" :: sx), (q.answer ::: q.bounded) :+ t1 :+ t2) + def AQ(sx: RSASuffix, t1: Term, t2: Term)(implicit + query: ConjunctiveQuery, + graph: TupleTableName + ) = + TupleTableAtom.create( + graph, + RSA("AQ" :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) - def FK(implicit q: ConjunctiveQuery) = - atom(RSA("FK"), q.answer ::: q.bounded) + def FK(implicit query: ConjunctiveQuery, graph: TupleTableName) = + TupleTableAtom.create(graph, RSA("FK") :: query.answer ::: query.bounded) - def SP(implicit q: ConjunctiveQuery) = - atom(RSA("SP"), q.answer ::: q.bounded) + def SP(implicit q: ConjunctiveQuery, graph: TupleTableName) = + TupleTableAtom.create(graph, RSA("SP") :: q.answer ::: q.bounded) - def Ans(implicit q: ConjunctiveQuery) = { + def Ans(implicit q: ConjunctiveQuery, graph: TupleTableName) = if (q.bcq) - TupleTableAtom.rdf(RSA("blank"), IRI.RDF_TYPE, RSA("Ans")) + TupleTableAtom.create(graph, RSA("blank"), IRI.RDF_TYPE, RSA.ANS) else - atom(RSA("Ans"), q.answer) - } + TupleTableAtom.create(graph, RSA.ANS :: q.answer) /* TODO: review after reworking the dependency graph construction */ -- cgit v1.2.3