From e237c660994978588dea7c8d26043440986ba6df Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Tue, 17 Nov 2020 11:45:55 +0000 Subject: Unify use of RSASuffix This commit comes with minor fixes and code simplifications. --- src/main/scala/rsacomb/FilteringProgram.scala | 199 +++++++++++---------- src/main/scala/rsacomb/RDFTriple.scala | 131 ++++++++------ .../scala/rsacomb/RDFoxPropertyExprConverter.scala | 9 +- src/main/scala/rsacomb/RDFoxUtil.scala | 2 +- src/main/scala/rsacomb/RSASuffix.scala | 21 ++- 5 files changed, 203 insertions(+), 159 deletions(-) (limited to 'src') diff --git a/src/main/scala/rsacomb/FilteringProgram.scala b/src/main/scala/rsacomb/FilteringProgram.scala index 44960e5..af07ac3 100644 --- a/src/main/scala/rsacomb/FilteringProgram.scala +++ b/src/main/scala/rsacomb/FilteringProgram.scala @@ -27,8 +27,11 @@ import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{ import scala.collection.JavaConverters._ +import implicits.RSAAtom +import suffix.{RSASuffix, Forward, Backward} + class FilteringProgram(query: SelectQuery, constants: List[Term]) - extends RDFTriple { + extends RSAAtom { /* Makes mplicit conversion OWLAPI IRI <-> RDFox IRI available */ import RDFoxUtil._ @@ -86,6 +89,10 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) } private def generateFilteringProgram(): List[Rule] = { + // General purpose variables + val varU = Variable.create("U") + val varV = Variable.create("V") + val varW = Variable.create("W") // Query formula as a rule body val body = queryToBody(query.getQueryBody.getWherePattern) // Auxiliar predicates/helpers @@ -102,14 +109,14 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) ) def predNAMED(t1: Term): TupleTableAtom = TupleTableAtom.rdf(t1, IRI.RDF_TYPE, RSA.rsa("NAMED")) - def predTQ(sx: String, t1: Term, t2: Term) = + def predTQ(t1: Term, t2: Term, sx: RSASuffix) = TupleTableAtom.create( - TupleTableName.create(RSA.rsa(s"TQ_$sx").getIRI), + TupleTableName.create(RSA.rsa("TQ" :: sx).getIRI), (answer ++ bounded).appended(t1).appended(t2): _* ) - def predAQ(sx: String, t1: Term, t2: Term) = + def predAQ(t1: Term, t2: Term, sx: RSASuffix) = TupleTableAtom.create( - TupleTableName.create(RSA.rsa(s"AQ_$sx").getIRI), + TupleTableName.create(RSA.rsa("AQ" :: sx).getIRI), (answer ++ bounded).appended(t1).appended(t2): _* ) val predFK = @@ -140,13 +147,13 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) not(predNI(v)) ) val r3b = Rule.create( - predID(Variable.create("V"), Variable.create("U")), - predID(Variable.create("U"), Variable.create("V")) + predID(varV, varU), + predID(varU, varV) ) val r3c = Rule.create( - predID(Variable.create("U"), Variable.create("W")), - predID(Variable.create("U"), Variable.create("V")), - predID(Variable.create("V"), Variable.create("W")) + predID(varU, varW), + predID(varU, varV), + predID(varV, varW) ) /* Rules 4x */ @@ -157,8 +164,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) if bounded contains (role2.getArguments.get(2)) } yield Rule.create( predFK, - role1 suffix "f", - role2 suffix "f", + role1 << Forward, + role2 << Forward, predID( RSA.rsa(bounded.indexOf(role1.getArguments.get(2))), RSA.rsa(bounded.indexOf(role2.getArguments.get(2))) @@ -178,8 +185,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) if bounded contains (role2.getArguments.get(0)) } yield Rule.create( predFK, - role1 suffix "f", - role2 suffix "b", + role1 << Forward, + role2 << Backward, predID( RSA.rsa(bounded.indexOf(role1.getArguments.get(2))), RSA.rsa(bounded.indexOf(role2.getArguments.get(0))) @@ -199,8 +206,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) if bounded contains (role2.getArguments.get(0)) } yield Rule.create( predFK, - role1 suffix "b", - role2 suffix "b", + role1 << Backward, + role2 << Backward, predID( RSA.rsa(bounded.indexOf(role1.getArguments.get(0))), RSA.rsa(bounded.indexOf(role2.getArguments.get(0))) @@ -231,8 +238,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) RSA.rsa(bounded indexOf role1arg0), RSA.rsa(bounded indexOf role2arg0) ), - role1 suffix "f", - role2 suffix "f", + role1 << Forward, + role2 << Forward, predID( RSA.rsa(bounded indexOf role1arg2), RSA.rsa(bounded indexOf role2arg2) @@ -256,8 +263,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) RSA.rsa(bounded indexOf role1arg0), RSA.rsa(bounded indexOf role2arg2) ), - role1 suffix "f", - role2 suffix "b", + role1 << Forward, + role2 << Backward, predID( RSA.rsa(bounded indexOf role1arg2), RSA.rsa(bounded indexOf role2arg0) @@ -281,8 +288,8 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) RSA.rsa(bounded indexOf role1arg2), RSA.rsa(bounded indexOf role2arg2) ), - role1 suffix "b", - role2 suffix "b", + role1 << Backward, + role2 << Backward, predID( RSA.rsa(bounded indexOf role1arg0), RSA.rsa(bounded indexOf role2arg0) @@ -292,40 +299,38 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) ) /* Rules 6 */ - val r6 = for { - role <- body.filter(_.isRoleAssertion) - arg0 = role.getArguments.get(0) - arg2 = role.getArguments.get(2) - if bounded contains arg0 - if bounded contains arg2 - sx <- List("f", "b") - } yield Rule.create( - predAQ(sx, Variable.create("V"), Variable.create("W")), - role suffix sx, - predID( - RSA.rsa(bounded indexOf arg0), - Variable.create("V") - ), - predID( - RSA.rsa(bounded indexOf arg2), - Variable.create("W") + val r6 = { + for { + role <- body.filter(_.isRoleAssertion) + arg0 = role.getArguments.get(0) + arg2 = role.getArguments.get(2) + if bounded contains arg0 + if bounded contains arg2 + suffix <- Seq(Forward, Backward) + } yield Rule.create( + predAQ(varV, varW, suffix), + role << suffix, + predID(RSA.rsa(bounded indexOf arg0), varV), + predID(RSA.rsa(bounded indexOf arg2), varW) ) - ) + } /* Rules 7x */ - val r7a = - for (sx <- List("f", "b")) + val r7a = { + for (suffix <- List(Forward, Backward)) yield Rule.create( - predTQ(sx, Variable.create("U"), Variable.create("V")), - predAQ(sx, Variable.create("U"), Variable.create("V")) + predTQ(varU, varV, suffix), + predAQ(varU, varV, suffix) ) - val r7b = - for (r <- List("f", "b")) + } + val r7b = { + for (suffix <- List(Forward, Backward)) yield Rule.create( - predTQ(r, Variable.create("U"), Variable.create("W")), - predAQ(r, Variable.create("U"), Variable.create("V")), - predTQ(r, Variable.create("V"), Variable.create("W")) + predTQ(varU, varW, suffix), + predAQ(varU, varV, suffix), + predTQ(varV, varW, suffix) ) + } /* Rules 8x */ val r8a = @@ -333,65 +338,75 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) val r8b = Rule.create(predSP, predFK) val r8c = - for (sx <- List("f", "b")) + for (suffix <- List(Forward, Backward)) yield Rule.create( predSP, - predTQ(sx, Variable.create("V"), Variable.create("V")) + predTQ(varV, varV, suffix) ) /* Rule 9 */ val r9 = Rule.create(predANS, predQM, not(predSP)) - List.empty - .prepended(r9) - .prependedAll(r8c) - .prepended(r8b) - .prependedAll(r8a) - .prependedAll(r7b) - .prependedAll(r7a) - .prependedAll(r6) - .prependedAll(r5c) - .prependedAll(r5b) - .prependedAll(r5a) - .prependedAll(r4c) - .prependedAll(r4b) - .prependedAll(r4a) - .prepended(r3c) - .prepended(r3b) - .prependedAll(r3a) - .prepended(r1) - } + // List.empty + // .prepended(r9) + // .prependedAll(r8c) + // .prepended(r8b) + // .prependedAll(r8a) + // .prependedAll(r7b) + // .prependedAll(r7a) + // .prependedAll(r6) + // .prependedAll(r5c) + // .prependedAll(r5b) + // .prependedAll(r5a) + // .prependedAll(r4c) + // .prependedAll(r4b) + // .prependedAll(r4a) + // .prepended(r3c) + // .prepended(r3b) + // .prependedAll(r3a) + // .prepended(r1) - private def reifyTupleTableAtom( - atom: TupleTableAtom - ): (Option[BindAtom], List[TupleTableAtom]) = { - if (!atom.isRdfTriple) { - // Compute binding atom - val bvar = RSA.getFreshVariable() - val name = - Literal.create(atom.getTupleTableName.toString(), Datatype.XSD_STRING) - val args = atom.getArguments.asScala.toList.prepended(name) - val bind = BindAtom.create(FunctionCall.create("SKOLEM", args: _*), bvar) - // Compute reified atom - def reifiedIRI(i: Int) = atom.getTupleTableName.getName ++ s"_$i" - val atoms = atom.getArguments.asScala.toList.zipWithIndex - .map { case (t, i) => TupleTableAtom.rdf(bvar, reifiedIRI(i), t) } - (Some(bind), atoms) - } else { - (None, List(atom)) - } + r1 :: + r3a ::: r3b :: r3c :: + r4c ::: r4b ::: r4a ::: + r5c ::: r5b ::: r5a ::: + r6 ::: + r7b ::: r7a ::: + r8a ::: r8b :: r8c ::: + r9 :: + List() } + // private def reifyTupleTableAtom( + // atom: TupleTableAtom + // ): (Option[BindAtom], List[TupleTableAtom]) = { + // if (!atom.isRDF) { + // // Compute binding atom + // val bvar = RSA.getFreshVariable() + // val name = + // Literal.create(atom.getTupleTableName.toString(), Datatype.XSD_STRING) + // val args = atom.getArguments.asScala.toList.prepended(name) + // val bind = BindAtom.create(FunctionCall.create("SKOLEM", args: _*), bvar) + // // Compute reified atom + // def reifiedIRI(i: Int) = atom.getTupleTableName.getName ++ s"_$i" + // val atoms = atom.getArguments.asScala.toList.zipWithIndex + // .map { case (t, i) => TupleTableAtom.rdf(bvar, reifiedIRI(i), t) } + // (Some(bind), atoms) + // } else { + // (None, List(atom)) + // } + // } + private def reifyAtom(atom: Atom): (Option[BindAtom], List[Atom]) = { atom match { - case tta: TupleTableAtom => reifyTupleTableAtom(tta) - case other => (None, List(other)) + case atom: TupleTableAtom => atom.reified + case other => (None, List(other)) } } private def reifyBodyFormula(formula: BodyFormula): List[BodyFormula] = { formula match { - case atom: TupleTableAtom => reifyTupleTableAtom(atom)._2 + case atom: TupleTableAtom => atom.reified._2 case neg: Negation => { val (bs, as) = neg.getNegatedAtoms.asScala.toList.map(reifyAtom).unzip val bind = bs.flatten.map(_.getBoundVariable).asJava @@ -403,7 +418,7 @@ class FilteringProgram(query: SelectQuery, constants: List[Term]) } private def reifyRule(rule: Rule): Rule = { - val (bs, hs) = rule.getHead.asScala.toList.map(reifyTupleTableAtom).unzip + val (bs, hs) = rule.getHead.asScala.toList.map(_.reified).unzip val head: List[TupleTableAtom] = hs.flatten val bind: List[BodyFormula] = bs.flatten val body: List[BodyFormula] = diff --git a/src/main/scala/rsacomb/RDFTriple.scala b/src/main/scala/rsacomb/RDFTriple.scala index 4054d42..a65c168 100644 --- a/src/main/scala/rsacomb/RDFTriple.scala +++ b/src/main/scala/rsacomb/RDFTriple.scala @@ -1,60 +1,87 @@ -package rsacomb +package rsacomb.implicits -import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} +import tech.oxfordsemantic.jrdfox.logic.Datatype +import tech.oxfordsemantic.jrdfox.logic.expression.{Literal, FunctionCall} +import tech.oxfordsemantic.jrdfox.logic.datalog.{ + BindAtom, + TupleTableAtom, + TupleTableName +} import tech.oxfordsemantic.jrdfox.logic.expression.{IRI} +import scala.collection.JavaConverters._ -trait RDFTriple { - - implicit class RDFTriple(atom: TupleTableAtom) { - - /* 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("internal:triple"), term1, term2, term3) - * ``` - */ - def isRdfTriple: Boolean = - atom.getTupleTableName.getName.equals("internal:triple") - - def isClassAssertion: Boolean = - atom.isRdfTriple && atom.getArguments.get(1).equals(IRI.RDF_TYPE) - - def isRoleAssertion: Boolean = - atom.isRdfTriple && !atom.getArguments.get(1).equals(IRI.RDF_TYPE) - - def suffix(sx: String): TupleTableAtom = - if (this.isClassAssertion) { - val newclass = atom.getArguments.get(2) match { - case iri: IRI => IRI.create(s"${iri.getIRI}_$sx") - case other => other - } - TupleTableAtom.rdf( - atom.getArguments.get(0), - atom.getArguments.get(1), - newclass - ) - } else if (this.isRoleAssertion) { - val newrole = atom.getArguments.get(1) match { - case iri: IRI => IRI.create(s"${iri.getIRI}_$sx") - case other => other +import rsacomb.suffix.{RSASuffix, Nth} +import rsacomb.RSA + +/* 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("internal:triple"), term1, term2, term3) + * ``` + */ + +trait RSAAtom { + + implicit class RSAAtom(val atom: TupleTableAtom) { + + import rsacomb.RDFoxUtil.stringToRDFoxIRI + + val name: String = atom.getTupleTableName.getName + + val isRDF: Boolean = name == "internal:triple" + + val isClassAssertion: Boolean = { + isRDF && { + val pred = atom.getArguments.get(1) + pred == IRI.RDF_TYPE + } + } + + 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.rdf(subj, pred, obj1) + } else { + val pred1 = pred match { + case iri: IRI => IRI.create(iri.getIRI :: suffix) + case other => other + } + TupleTableAtom.rdf(subj, pred1, obj) } - TupleTableAtom.rdf( - atom.getArguments.get(0), - newrole, - atom.getArguments.get(2) - ) } else { - val newname = - TupleTableName.create(s"${atom.getTupleTableName.getName}_$sx") - TupleTableAtom.create(newname, atom.getArguments()) + val ttname = TupleTableName.create(name :: suffix) + TupleTableAtom.create(ttname, atom.getArguments()) + } + + lazy val reified: (Option[BindAtom], List[TupleTableAtom]) = + if (isRDF) { + (None, List(atom)) + } else { + val bvar = RSA.getFreshVariable() + val str = Literal.create(name, Datatype.XSD_STRING) + val args = atom.getArguments.asScala.toList + val skolem = FunctionCall.create("SKOLEM", str :: args: _*) + val bind = BindAtom.create(skolem, bvar) + val atoms = args.zipWithIndex + .map { case (t, i) => TupleTableAtom.rdf(bvar, name :: Nth(i), t) } + (Some(bind), atoms) } } diff --git a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala index ea1df2f..525ec62 100644 --- a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala +++ b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala @@ -20,15 +20,14 @@ class RDFoxPropertyExprConverter( import RDFoxUtil.owlapi2rdfox; override def visit(expr: OWLObjectProperty): List[TupleTableAtom] = { - //val pred = IRI.create(expr.getIRI.getIRIString ++ suffix.getSuffix) - val pred = IRI.create(expr :: suffix) + val base = expr.getIRI.getIRIString + val pred = IRI.create(base :: suffix) List(TupleTableAtom.rdf(term1, pred, term2)) } override def visit(expr: OWLObjectInverseOf): List[TupleTableAtom] = { - //expr.getInverse.getNamedProperty.getIRI.getIRIString ++ suffix.getSuffix ++ "_inv" - val pred = IRI.create(expr :: suffix + Inverse) - List(TupleTableAtom.rdf(term1, pred, term2)) + val visitor = new RDFoxPropertyExprConverter(term1, term2, suffix + Inverse) + expr.getInverse.accept(visitor) } def doDefault(expr: OWLPropertyExpression): List[TupleTableAtom] = List() diff --git a/src/main/scala/rsacomb/RDFoxUtil.scala b/src/main/scala/rsacomb/RDFoxUtil.scala index 45d97de..d391d41 100644 --- a/src/main/scala/rsacomb/RDFoxUtil.scala +++ b/src/main/scala/rsacomb/RDFoxUtil.scala @@ -25,7 +25,7 @@ object RDFoxUtil { RDFox_IRI.create(iri.getIRIString()) } - implicit def owlapi2rdfox(iri: String): RDFox_IRI = { + implicit def stringToRDFoxIRI(iri: String): RDFox_IRI = { RDFox_IRI.create(iri) } diff --git a/src/main/scala/rsacomb/RSASuffix.scala b/src/main/scala/rsacomb/RSASuffix.scala index 7650ae0..ce36b10 100644 --- a/src/main/scala/rsacomb/RSASuffix.scala +++ b/src/main/scala/rsacomb/RSASuffix.scala @@ -6,22 +6,25 @@ import org.semanticweb.owlapi.model.{ OWLObjectProperty } +import tech.oxfordsemantic.jrdfox.logic.expression.{IRI} +import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, TupleTableName} + +object RSASuffix { + + def apply(suffix: String => String): RSASuffix = new RSASuffix(suffix) + +} + class RSASuffix(val suffix: String => String) { - def +(other: RSASuffix): RSASuffix = - new RSASuffix((s: String) => other suffix (this suffix s)) + def +(that: RSASuffix): RSASuffix = + new RSASuffix(this.suffix andThen that.suffix) def ::(str: String): String = this suffix str - def ::(expr: OWLPropertyExpression): String = - expr match { - case e: OWLObjectProperty => e.getIRI.getIRIString :: this - case e: OWLObjectInverseOf => e.getInverse :: this - } - } -case object Empty extends RSASuffix((x) => x) +case object Empty extends RSASuffix(identity) case object Forward extends RSASuffix((s) => s"${s}_f") case object Backward extends RSASuffix((s) => s"${s}_b") case object Inverse extends RSASuffix((s) => s"${s}_inv") -- cgit v1.2.3