From 424d5d6fcabb410622907c095364903577014765 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Sat, 2 Oct 2021 09:15:43 +0100 Subject: Rework revides filtering program computation to use named graphs --- .../scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 7 +- .../rsacomb/filtering/NaiveFilteringProgram.scala | 143 ++++++++------ .../filtering/RevisedFilteringProgram.scala | 215 +++++++++++---------- .../uk/ac/ox/cs/rsacomb/implicits/RDFox.scala | 4 + .../uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala | 53 ++--- .../uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala | 24 ++- src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala | 70 ++----- 7 files changed, 254 insertions(+), 262 deletions(-) (limited to 'src') diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala index 6a3dca2..993e9df 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala @@ -545,7 +545,7 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) RDFoxUtil.addFacts( data, RSAOntology.CanonGraph, - (individuals ++ literals) map RSA.Named + (individuals ++ literals) map RSA.Named(RSAOntology.CanonGraph) ) data.evaluateUpdate( null, // the base IRI for the query (if null, a default is used) @@ -569,13 +569,12 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) queries map { 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) - - // We remove the rules, should we drop the tuple table as well? + // TODO: We remove the rules, should we drop the tuple table as well? data.clearRulesAxiomsExplicateFacts() /* Gather answers to the query */ diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala index 1777713..6174c9d 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala @@ -32,7 +32,7 @@ import tech.oxfordsemantic.jrdfox.logic.expression.{ Variable } import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery -import uk.ac.ox.cs.rsacomb.suffix.{Forward, Backward, Nth} +import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Forward, Backward, Nth} import uk.ac.ox.cs.rsacomb.util.{DataFactory, RSA, RDFoxUtil} /** Factory for [[uk.ac.ox.cs.rsacomb.FilteringProgram FilteringProgram]] */ @@ -95,10 +95,41 @@ class NaiveFilteringProgram( /** `TupleTableName`s for the source/targer named graphs */ val tts: TupleTableName = TupleTableName.create(source.getIRI) - implicit val ttt: TupleTableName = TupleTableName.create(target.getIRI) + val ttt: TupleTableName = TupleTableName.create(target.getIRI) /** Set of atoms in the body of the query */ - val queryBody: List[TupleTableAtom] = query.atoms(tts) + private val queryBody: List[TupleTableAtom] = query.atoms(tts) + + /** Helpers */ + private def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) + + private val QM: TupleTableAtom = + TupleTableAtom.create(ttt, RSA.QM :: query.answer ::: query.bounded) + private def ID(t1: Term, t2: Term) = + TupleTableAtom.create( + ttt, + RSA.ID +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) + private def NI(term: Term) = + TupleTableAtom.create(ttt, term, IRI.RDF_TYPE, RSA.NI) + private def TQ(sx: RSASuffix, t1: Term, t2: Term) = + TupleTableAtom.create( + ttt, + (RSA.TQ :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) + private def AQ(sx: RSASuffix, t1: Term, t2: Term) = + TupleTableAtom.create( + ttt, + (RSA.AQ :: sx) +: (query.answer ::: query.bounded) :+ t1 :+ t2 + ) + private val FK: TupleTableAtom = + TupleTableAtom.create(ttt, RSA.FK :: query.answer ::: query.bounded) + private val SP: TupleTableAtom = + TupleTableAtom.create(ttt, RSA.SP :: query.answer ::: query.bounded) + private def Ans = if (query.bcq) + TupleTableAtom.create(ttt, RSA("blank"), IRI.RDF_TYPE, RSA.ANS) + else + TupleTableAtom.create(ttt, RSA.ANS :: query.answer) /** Rule generating the instances of the predicate `rsa:NI`. * @@ -117,23 +148,20 @@ class NaiveFilteringProgram( */ val nis: Rule = Rule.create( - RSA.NI(varX), - RSA.Congruent(varX, varY)(tts), - RSA.Named(varY)(tts) + NI(varX), + RSA.Congruent(tts)(varX, varY), + RSA.Named(tts)(varY) ) /** Collection of filtering program rules. */ val rules: List[Rule] = nis :: { - /** Negates a [[tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom TupleTableAtom]] */ - def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) - /** Generates all possible, unfiltered answers. * * @note corresponds to rule 1 in Table 3 in the paper. */ - val r1 = Rule.create(RSA.QM, queryBody: _*) + val r1 = Rule.create(QM, queryBody: _*) /** Initializes instances of `rsa:ID`. * @@ -145,10 +173,10 @@ class NaiveFilteringProgram( */ val r3a = for ((v, i) <- query.bounded.zipWithIndex) - yield Rule.create(RSA.ID(RSA(i), RSA(i)), RSA.QM, not(RSA.NI(v))) - val r3b = Rule.create(RSA.ID(varV, varU), RSA.ID(varU, varV)) + yield Rule.create(ID(RSA(i), RSA(i)), QM, not(NI(v))) + val r3b = Rule.create(ID(varV, varU), ID(varU, varV)) val r3c = - Rule.create(RSA.ID(varU, varW), RSA.ID(varU, varV), RSA.ID(varV, varW)) + Rule.create(ID(varU, varW), ID(varU, varV), ID(varV, varW)) /** Detects forks in the canonical model. * @@ -162,10 +190,10 @@ class NaiveFilteringProgram( index2 = query.bounded indexOf (role2.getArguments get 2) if index2 >= 0 } yield Rule.create( - RSA.FK, - RSA.ID(RSA(index1), RSA(index2)), - role1 << Forward, - role2 << Forward, + FK, + ID(RSA(index1), RSA(index2)), + role1 :: Forward, + role2 :: Forward, not( TupleTableAtom.create( tts, @@ -183,10 +211,10 @@ class NaiveFilteringProgram( index2 = query.bounded indexOf (role2.getArguments get 0) if index2 >= 0 } yield Rule.create( - RSA.FK, - RSA.ID(RSA(index1), RSA(index2)), - role1 << Forward, - role2 << Backward, + FK, + ID(RSA(index1), RSA(index2)), + role1 :: Forward, + role2 :: Backward, not( TupleTableAtom.create( tts, @@ -204,10 +232,10 @@ class NaiveFilteringProgram( index2 = query.bounded indexOf (role2.getArguments get 0) if index2 >= 0 } yield Rule.create( - RSA.FK, - RSA.ID(RSA(index1), RSA(index2)), - role1 << Backward, - role2 << Backward, + FK, + ID(RSA(index1), RSA(index2)), + role1 :: Backward, + role2 :: Backward, not( TupleTableAtom.create( tts, @@ -234,18 +262,18 @@ class NaiveFilteringProgram( r2arg2 = role2.getArguments get 2 if query.bounded contains r2arg2 } yield Rule.create( - RSA.ID( + ID( RSA(query.bounded indexOf r1arg0), RSA(query.bounded indexOf r2arg0) ), - RSA.ID( + ID( RSA(query.bounded indexOf r1arg2), RSA(query.bounded indexOf r2arg2) ), TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg0), - role1 << Forward, - role2 << Forward, - not(RSA.NI(r1arg0)) + role1 :: Forward, + role2 :: Forward, + not(NI(r1arg0)) ) val r5b = for { role1 <- queryBody filter (_.isRoleAssertion) @@ -259,18 +287,18 @@ class NaiveFilteringProgram( r2arg2 = role2.getArguments get 2 if query.bounded contains r2arg2 } yield Rule.create( - RSA.ID( + ID( RSA(query.bounded indexOf r1arg0), RSA(query.bounded indexOf r2arg2) ), - RSA.ID( + ID( RSA(query.bounded indexOf r1arg2), RSA(query.bounded indexOf r2arg0) ), TupleTableAtom.create(tts, r1arg0, RSA.CONGRUENT, r2arg2), - role1 << Forward, - role2 << Backward, - not(RSA.NI(r1arg0)) + role1 :: Forward, + role2 :: Backward, + not(NI(r1arg0)) ) val r5c = for { role1 <- queryBody filter (_.isRoleAssertion) @@ -284,18 +312,18 @@ class NaiveFilteringProgram( r2arg2 = role2.getArguments get 2 if query.bounded contains r2arg2 } yield Rule.create( - RSA.ID( + ID( RSA(query.bounded indexOf r1arg2), RSA(query.bounded indexOf r2arg2) ), - RSA.ID( + ID( RSA(query.bounded indexOf r1arg0), RSA(query.bounded indexOf r2arg0) ), TupleTableAtom.create(tts, r1arg2, RSA.CONGRUENT, r2arg2), - role1 << Backward, - role2 << Backward, - not(RSA.NI(r1arg2)) + role1 :: Backward, + role2 :: Backward, + not(NI(r1arg2)) ) /** Detect cycles in the canonical model. @@ -314,23 +342,23 @@ class NaiveFilteringProgram( if index2 >= 0 suffix <- Seq(Forward, Backward) } yield Rule.create( - RSA.AQ(suffix, varV, varW), - role << suffix, - RSA.ID(RSA(index0), varV), - RSA.ID(RSA(index2), varW) + AQ(suffix, varV, varW), + role :: suffix, + ID(RSA(index0), varV), + ID(RSA(index2), varW) ) val r7a = for (suffix <- List(Forward, Backward)) yield Rule.create( - RSA.TQ(suffix, varU, varV), - RSA.AQ(suffix, varU, varV) + TQ(suffix, varU, varV), + AQ(suffix, varU, varV) ) val r7b = for (suffix <- List(Forward, Backward)) yield Rule.create( - RSA.TQ(suffix, varU, varW), - RSA.AQ(suffix, varU, varV), - RSA.TQ(suffix, varV, varW) + TQ(suffix, varU, varW), + AQ(suffix, varU, varV), + TQ(suffix, varV, varW) ) /** Flag spurious answers. @@ -340,19 +368,14 @@ class NaiveFilteringProgram( val r8a = for (v <- query.answer) yield Rule.create( - RSA.SP, - RSA.QM, - not( - TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED) - ) + SP, + QM, + not(TupleTableAtom.create(tts, v, IRI.RDF_TYPE, RSA.NAMED)) ) - val r8b = Rule.create(RSA.SP, RSA.FK) + val r8b = Rule.create(SP, FK) val r8c = for (suffix <- List(Forward, Backward)) - yield Rule.create( - RSA.SP, - RSA.TQ(suffix, varV, varV) - ) + yield Rule.create(SP, TQ(suffix, varV, varV)) /** Determine answers to the query * @@ -369,7 +392,7 @@ class NaiveFilteringProgram( * * @note corresponds to rule 9 in Table 3. */ - val r9 = Rule.create(RSA.Ans, RSA.QM, not(RSA.SP)) + val r9 = Rule.create(Ans, QM, not(SP)) (r1 :: r3a ::: r3b :: r3c :: diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala index 5d11369..f059bcd 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala @@ -54,8 +54,12 @@ object RevisedFilteringProgram { * * @param query CQ to be converted into logic rules. */ - def apply(query: ConjunctiveQuery): RevisedFilteringProgram = - new RevisedFilteringProgram(query) + def apply( + source: IRI, + target: IRI, + query: ConjunctiveQuery + ): RevisedFilteringProgram = + new RevisedFilteringProgram(source, target, query) } @@ -66,8 +70,11 @@ object RevisedFilteringProgram { * * Instances can be created using the companion object. */ -class RevisedFilteringProgram(val query: ConjunctiveQuery) - extends FilteringProgram { +class RevisedFilteringProgram( + val source: IRI, + val target: IRI, + val query: ConjunctiveQuery +) extends FilteringProgram { import RDFoxDSL._ @@ -76,45 +83,47 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) */ import uk.ac.ox.cs.rsacomb.implicits.RSAAtom._ + /** 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. */ implicit private[this] val _query = query - /** Helpers */ + /** `TupleTableName`s for the source/targer named graphs */ + val tts: TupleTableName = TupleTableName.create(source.getIRI) + val ttt: TupleTableName = TupleTableName.create(target.getIRI) + + /** Set of atoms in the body of the query */ + private val queryBody: List[TupleTableAtom] = query.atoms(tts) - //private def v(name: String): Term = Variable.create(s"${name}i") + /** Helpers */ private def not(atom: TupleTableAtom): BodyFormula = Negation.create(atom) - private def named(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA.NAMED) - private def congruent(x: Term, y: Term): TupleTableAtom = - TupleTableAtom.rdf(x, RSA.CONGRUENT, y) - private def skolem(skolem: Term, terms: List[Term]): TupleTableAtom = - TupleTableAtom.create(TupleTableName.SKOLEM, (terms :+ skolem): _*) private def QM(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("QM")) + TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.QM) private def FK(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("FK")) + TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.FK) private def SP(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("SP")) + TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.SP) private def NI(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("NI")) + TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.NI) private def Ans(x: Term): TupleTableAtom = - TupleTableAtom.rdf(x, IRI.RDF_TYPE, RSA("Ans")) + TupleTableAtom.create(ttt, x, IRI.RDF_TYPE, RSA.ANS) private def ID(x: Term, y: Term): TupleTableAtom = - TupleTableAtom.rdf(x, RSA("ID"), y) - private def AQ(suffix: RSASuffix, x: Term, y: Term): TupleTableAtom = - TupleTableAtom.rdf(x, RSA("AQ"), y) << suffix - private def TQ(suffix: RSASuffix, x: Term, y: Term): TupleTableAtom = - TupleTableAtom.rdf(x, RSA("TQ"), y) << suffix + TupleTableAtom.create(ttt, x, RSA.ID, y) + private def AQ(suffix: RSASuffix)(x: Term, y: Term): TupleTableAtom = + TupleTableAtom.create(ttt, x, RSA.AQ :: suffix, y) + private def TQ(suffix: RSASuffix)(x: Term, y: Term): TupleTableAtom = + TupleTableAtom.create(ttt, x, RSA.TQ :: suffix, y) /** Rule generating the instances of the predicate `rsa:NI`. * * According to the original paper, the set of `rsa:NI` is defined as * the set of constants that are equal (w.r.t. the congruence - * relation represented by `rsa:Congruent`) to a constant in the + * relation represented by `rsacomb:Congruent`) to a constant in the * original ontology. * * @note that the set of `rsa:Named` constants is always a subset of @@ -125,7 +134,8 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) * predicate, this is not feasible, and the instances are instead * generate in the filtering program using a logic rule. */ - val nis: Rule = Rule.create(NI(v"X"), named(v"Y"), congruent(v"X", v"Y")) + val nis: Rule = + Rule.create(NI(v"X"), RSA.Named(tts)(v"Y"), RSA.Congruent(tts)(v"X", v"Y")) /** Collection of filtering program rules. */ val rules: List[Rule] = @@ -138,7 +148,7 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) * @note corresponds to rule 1 in Table 3 in the paper. */ val r1 = - Rule.create(QM(v"K"), (query.atoms :+ skolem(v"K", variables)): _*) + Rule.create(QM(v"K"), queryBody :+ RSA.Skolem(v"K", variables)) /** Initializes instances of `rsa:ID`. * @@ -153,26 +163,26 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) yield Rule.create( ID(v"K", v"S"), QM(v"K"), - skolem(v"K", variables), + RSA.Skolem(v"K", variables), not(NI(v)), - skolem(v"S", variables :+ RSA(i) :+ RSA(i)) + RSA.Skolem(v"S", variables :+ RSA(i) :+ RSA(i)) ) val r3b = Rule.create( ID(v"K", v"T"), ID(v"K", v"S"), - skolem(v"S", variables :+ v"U" :+ v"V"), - skolem(v"T", variables :+ v"V" :+ v"U") + RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), + RSA.Skolem(v"T", variables :+ v"V" :+ v"U") ) val r3c = Rule.create( ID(v"K1", v"Q"), QM(v"K1"), ID(v"K2", v"S"), FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), - skolem(v"S", variables :+ v"U" :+ v"V"), + RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), ID(v"K3", v"T"), FilterAtom.create(FunctionCall.equal(v"K1", v"K3")), - skolem(v"T", variables :+ v"V" :+ v"W"), - skolem(v"Q", variables :+ v"U" :+ v"W") + RSA.Skolem(v"T", variables :+ v"V" :+ v"W"), + RSA.Skolem(v"Q", variables :+ v"U" :+ v"W") ) /** Detects forks in the canonical model. @@ -180,49 +190,55 @@ class RevisedFilteringProgram(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( FK(v"K"), ID(v"K", v"S"), - skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), - role1 << Forward, - role2 << Forward, - not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 0)) + RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), + role1 :: Forward, + role2 :: Forward, + not( + RSA.Congruent(tts)(role1.getArguments get 0, 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( FK(v"K"), ID(v"K", v"S"), - skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), - role1 << Forward, - role2 << Backward, - not(RSA.Congruent(role1.getArguments get 0, role2.getArguments get 2)) + RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), + role1 :: Forward, + role2 :: Backward, + not( + RSA.Congruent(tts)(role1.getArguments get 0, 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( FK(v"K"), ID(v"K", v"S"), - skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), - role1 << Backward, - role2 << Backward, - not(RSA.Congruent(role1.getArguments get 2, role2.getArguments get 2)) + RSA.Skolem(v"S", variables :+ RSA(index1) :+ RSA(index2)), + role1 :: Backward, + role2 :: Backward, + not( + RSA.Congruent(tts)(role1.getArguments get 2, role2.getArguments get 2) + ) ) /** Recursively propagates `rsa:ID` predicate. @@ -230,12 +246,12 @@ class RevisedFilteringProgram(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 @@ -243,17 +259,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) } yield Rule.create( ID(v"K", v"T"), ID(v"K", v"S"), - skolem( + RSA.Skolem( v"S", variables :+ RSA(query.bounded indexOf r1arg2) :+ RSA(query.bounded indexOf r2arg2) ), - RSA.Congruent(r1arg0, r2arg0), - role1 << Forward, - role2 << Forward, + RSA.Congruent(tts)(r1arg0, r2arg0), + role1 :: Forward, + role2 :: Forward, not(NI(r1arg0)), - skolem( + RSA.Skolem( v"T", variables :+ RSA(query.bounded indexOf r1arg0) :+ @@ -261,12 +277,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) ) ) 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 @@ -274,17 +290,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) } yield Rule.create( ID(v"K", v"T"), ID(v"K", v"S"), - skolem( + RSA.Skolem( v"S", variables :+ RSA(query.bounded indexOf r1arg2) :+ RSA(query.bounded indexOf r2arg0) ), - RSA.Congruent(r1arg0, r2arg2), - role1 << Forward, - role2 << Backward, - not(RSA.NI(r1arg0)), - skolem( + RSA.Congruent(tts)(r1arg0, r2arg2), + role1 :: Forward, + role2 :: Backward, + not(NI(r1arg0)), + RSA.Skolem( v"T", variables :+ RSA(query.bounded indexOf r1arg0) :+ @@ -292,12 +308,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) ) ) 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 @@ -305,17 +321,17 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) } yield Rule.create( ID(v"K", v"T"), ID(v"K", v"S"), - skolem( + RSA.Skolem( v"S", variables :+ RSA(query.bounded indexOf r1arg0) :+ RSA(query.bounded indexOf r2arg0) ), - RSA.Congruent(r1arg2, r2arg2), - role1 << Backward, - role2 << Backward, - not(RSA.NI(r1arg2)), - skolem( + RSA.Congruent(tts)(r1arg2, r2arg2), + role1 :: Backward, + role2 :: Backward, + not(NI(r1arg2)), + RSA.Skolem( v"T", variables :+ RSA(query.bounded indexOf r1arg2) :+ @@ -332,38 +348,38 @@ class RevisedFilteringProgram(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( - AQ(suffix, v"K1", v"Q"), + AQ(suffix)(v"K1", v"Q"), ID(v"K1", v"S"), - skolem(v"S", variables :+ RSA(index0) :+ v"V"), + RSA.Skolem(v"S", variables :+ RSA(index0) :+ v"V"), ID(v"K2", v"T"), FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), - skolem(v"T", variables :+ RSA(index2) :+ v"W"), - role << suffix, - skolem(v"Q", variables :+ v"V" :+ v"W") + RSA.Skolem(v"T", variables :+ RSA(index2) :+ v"W"), + role :: suffix, + RSA.Skolem(v"Q", variables :+ v"V" :+ v"W") ) val r7a = for (suffix <- List(Forward, Backward)) yield Rule.create( - TQ(suffix, v"K", v"S"), - AQ(suffix, v"K", v"S") + TQ(suffix)(v"K", v"S"), + AQ(suffix)(v"K", v"S") ) val r7b = for (suffix <- List(Forward, Backward)) yield Rule.create( - TQ(suffix, v"K1", v"Q"), - AQ(suffix, v"K1", v"S"), - skolem(v"S", variables :+ v"U" :+ v"V"), - TQ(suffix, v"K2", v"T"), + TQ(suffix)(v"K1", v"Q"), + AQ(suffix)(v"K1", v"S"), + RSA.Skolem(v"S", variables :+ v"U" :+ v"V"), + TQ(suffix)(v"K2", v"T"), FilterAtom.create(FunctionCall.equal(v"K1", v"K2")), - skolem(v"T", variables :+ v"V" :+ v"W"), - skolem(v"Q", variables :+ v"U" :+ v"W") + RSA.Skolem(v"T", variables :+ v"V" :+ v"W"), + RSA.Skolem(v"Q", variables :+ v"U" :+ v"W") ) /** Flag spurious answers. @@ -375,19 +391,16 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) yield Rule.create( SP(v"K"), QM(v"K"), - skolem(v"K", variables), - not(RSA.Named(v)) + RSA.Skolem(v"K", variables), + not(RSA.Named(tts)(v)) ) - val r8b = Rule.create( - SP(v"K"), - FK(v"K") - ) + val r8b = Rule.create(SP(v"K"), FK(v"K")) val r8c = for (suffix <- List(Forward, Backward)) yield Rule.create( SP(v"K"), - TQ(suffix, v"K", v"S"), - skolem(v"S", variables :+ v"V" :+ v"V") + TQ(suffix)(v"K", v"S"), + RSA.Skolem(v"S", variables :+ v"V" :+ v"V") ) /** Determine answers to the query @@ -405,11 +418,7 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) * * @note corresponds to rule 9 in Table 3. */ - val r9 = Rule.create( - Ans(v"K"), - QM(v"K"), - not(SP(v"K")) - ) + val r9 = Rule.create(Ans(v"K"), QM(v"K"), not(SP(v"K"))) (r1 :: r3a ::: r3b :: r3c :: r4a ::: r4b ::: r4c ::: r5a ::: r5b ::: r5c ::: r6 ::: r7b ::: r7a ::: r8a ::: r8b :: r8c ::: r9 :: List()) } @@ -422,12 +431,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) s""" SELECT $answer WHERE { - GRAPH <$graph> { ?K a rsa:Ans } . - TT { $answer $bounded ?K } . + GRAPH $target { ?K a ${RSA.ANS} } . + TT ${TupleTableName.SKOLEM} { $answer $bounded ?K } . } """ } else { - s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" + s"ASK { GRAPH $target { ?X a ${RSA.ANS} } }" } } diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala index d4b7876..ca77409 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RDFox.scala @@ -17,6 +17,7 @@ package uk.ac.ox.cs.rsacomb.implicits import tech.oxfordsemantic.jrdfox.logic.Datatype +import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableName import tech.oxfordsemantic.jrdfox.logic.expression.{ BlankNode, IRI => RDFoxIRI, @@ -47,6 +48,9 @@ object RDFox { implicit def stringToRdfoxIri(iri: String): RDFoxIRI = RDFoxIRI.create(iri) + implicit def iriToTupleTableName(iri: RDFoxIRI): TupleTableName = + TupleTableName.create(iri.getIRI) + /** Converst an OWLAPI datatype into an RDFox datatype. * * The builtin datatypes defined by the two systems do not match diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala index 37c70df..89777c4 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala @@ -29,21 +29,6 @@ import uk.ac.ox.cs.rsacomb.RSAOntology import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Nth} import uk.ac.ox.cs.rsacomb.util.{DataFactory, RDFoxUtil} -/* Is this the best way to determine if an atom is an RDF triple? - * Note that we can't use `getNumberOfArguments()` because is not - * "consistent": - * - for an atom created with `rdf(, , )`, - * `getNumberOfArguments` returns 3 - * - for an atom created with `Atom.create(, , - * , )`, `getNumberOfArguments()` returns 3 - * - * This is probably because `Atom.rdf(...) is implemented as: - * ```scala - * def rdf(term1: Term, term2: Term, term3: Term): Atom = - * Atom.create(TupleTableName.create("rdfox:DefaultTriples"), term1, term2, term3) - * ``` - */ - object RSAAtom { implicit class RSAAtom(val atom: TupleTableAtom) { @@ -62,25 +47,25 @@ object RSAAtom { val isRoleAssertion: Boolean = isRDF && !isClassAssertion - def <<(suffix: RSASuffix): TupleTableAtom = - if (isRDF) { - val subj = atom.getArguments.get(0) - val pred = atom.getArguments.get(1) - val obj = atom.getArguments.get(2) - if (isClassAssertion) { - val obj1 = obj match { - case iri: IRI => IRI.create(iri.getIRI :: suffix) - case other => other - } - TupleTableAtom.create(tt, subj, pred, obj1) - } else { - val pred1 = pred match { - case iri: IRI => IRI.create(iri.getIRI :: suffix) - case other => other - } - TupleTableAtom.create(tt, subj, pred1, obj) - } - } else atom + // def <<(suffix: RSASuffix): TupleTableAtom = + // if (isRDF) { + // val subj = atom.getArguments.get(0) + // val pred = atom.getArguments.get(1) + // val obj = atom.getArguments.get(2) + // if (isClassAssertion) { + // val obj1 = obj match { + // case iri: IRI => IRI.create(iri.getIRI :: suffix) + // case other => other + // } + // TupleTableAtom.create(tt, subj, pred, obj1) + // } else { + // val pred1 = pred match { + // case iri: IRI => IRI.create(iri.getIRI :: suffix) + // case other => other + // } + // TupleTableAtom.create(tt, subj, pred1, obj) + // } + // } else atom // def reified(implicit // fresh: DataFactory diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala index 424f2a0..282aa0b 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/suffix/RSASuffix.scala @@ -16,13 +16,13 @@ package uk.ac.ox.cs.rsacomb.suffix -import org.semanticweb.owlapi.model.{ - OWLPropertyExpression, - OWLObjectInverseOf, - OWLObjectProperty -} +// import org.semanticweb.owlapi.model.{ +// OWLPropertyExpression, +// OWLObjectInverseOf, +// OWLObjectProperty +// } -import tech.oxfordsemantic.jrdfox.logic.expression.{IRI} +import tech.oxfordsemantic.jrdfox.logic.expression.{IRI, Term} import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} object RSASuffix { @@ -37,7 +37,17 @@ class RSASuffix(val suffix: String => String) { new RSASuffix(this.suffix andThen that.suffix) def ::(str: String): String = this suffix str - + def ::(iri: IRI): IRI = IRI.create(this suffix iri.getIRI) + def ::(tta: TupleTableAtom): TupleTableAtom = { + val ttn: TupleTableName = tta.getTupleTableName + tta.getArguments match { + case List(subj: Term, IRI.RDF_TYPE, obj: IRI) => + TupleTableAtom.create(ttn, subj, IRI.RDF_TYPE, obj :: this) + case List(subj: Term, pred: IRI, obj: Term) => + TupleTableAtom.create(ttn, subj, pred :: this, obj) + case _ => tta + } + } } case object Empty extends RSASuffix(identity) diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala index 40c5ced..5abb83c 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RSA.scala @@ -54,73 +54,35 @@ object RSA { /** Creates a `rsacomb:` IRI */ def apply(name: Any): IRI = IRI.create( + //Prefixes.decodeIRI("rsacomb:") + name.toString Prefixes.getPrefixIRIsByPrefixName.get("rsacomb:").getIRI + name.toString ) + /** Helper IRIs */ val ANS = RSA("Ans") + val AQ = RSA("AQ") val CONGRUENT = RSA("congruent") + val FK = RSA("FK") + val ID = RSA("ID") val IN = RSA("In") val NAMED = RSA("Named") + val NI = RSA("NI") + val QM = RSA("QM") + val SP = RSA("SP") + val TQ = RSA("TQ") + + def Named(tt: TupleTableName)(x: Term): TupleTableAtom = + TupleTableAtom.create(tt, x, IRI.RDF_TYPE, RSA.NAMED) + def Congruent(tt: TupleTableName)(x: Term, y: Term): TupleTableAtom = + TupleTableAtom.create(tt, x, RSA.CONGRUENT, y) + def Skolem(skolem: Term, terms: List[Term]): TupleTableAtom = + TupleTableAtom.create(TupleTableName.SKOLEM, terms :+ skolem) // 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)(implicit graph: TupleTableName) = - TupleTableAtom.create(graph, t1, RSA.CONGRUENT, t2) - - def Named(term: Term)(implicit graph: TupleTableName) = - TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA.NAMED) - - def QM(implicit query: ConjunctiveQuery, graph: TupleTableName) = - TupleTableAtom.create(graph, RSA("QM") :: query.answer ::: query.bounded) - - 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 NI(term: Term)(implicit graph: TupleTableName) = - TupleTableAtom.create(graph, term, IRI.RDF_TYPE, RSA("NI")) - - 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(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 query: ConjunctiveQuery, graph: TupleTableName) = - TupleTableAtom.create(graph, RSA("FK") :: query.answer ::: query.bounded) - - def SP(implicit q: ConjunctiveQuery, graph: TupleTableName) = - TupleTableAtom.create(graph, RSA("SP") :: q.answer ::: q.bounded) - - def Ans(implicit q: ConjunctiveQuery, graph: TupleTableName) = - if (q.bcq) - TupleTableAtom.create(graph, RSA("blank"), IRI.RDF_TYPE, RSA.ANS) - else - TupleTableAtom.create(graph, RSA.ANS :: q.answer) - /* TODO: review after reworking the dependency graph construction */ // private def atom(name: IRI, vars: List[Term]): TupleTableAtom = -- cgit v1.2.3