From 6a29b16dee0592fdeb03b26ff87fd00d57555f78 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Wed, 30 Sep 2020 19:45:25 +0200 Subject: Add rule generation for unsafe T5 axioms for canonical model --- src/main/scala/rsacomb/CanonicalModel.scala | 28 ++++++++++++++-------- src/main/scala/rsacomb/Main.scala | 17 +++++++++++++ src/main/scala/rsacomb/RDFoxAxiomConverter.scala | 16 +++++++------ .../scala/rsacomb/RDFoxClassExprConverter.scala | 21 +++++++++------- .../scala/rsacomb/RDFoxPropertyExprConverter.scala | 15 +++++++----- src/main/scala/rsacomb/RSAOntology.scala | 5 ++-- src/main/scala/rsacomb/RSASuffix.scala | 20 ++++++++++++++++ 7 files changed, 88 insertions(+), 34 deletions(-) create mode 100644 src/main/scala/rsacomb/RSASuffix.scala (limited to 'src/main/scala') diff --git a/src/main/scala/rsacomb/CanonicalModel.scala b/src/main/scala/rsacomb/CanonicalModel.scala index 49c0c24..162bea1 100644 --- a/src/main/scala/rsacomb/CanonicalModel.scala +++ b/src/main/scala/rsacomb/CanonicalModel.scala @@ -25,19 +25,27 @@ object ProgramGenerator { Seq( Rule.create( Atom.rdf(varX, IRI.create(pred), varY), - Atom.rdf(varX, IRI.create(pred ++ "_f"), varY) + Atom.rdf(varX, IRI.create(pred ++ RSASuffix.Forward.getSuffix), varY) ), Rule.create( Atom.rdf(varX, IRI.create(pred), varY), - Atom.rdf(varX, IRI.create(pred ++ "_b"), varY) + Atom.rdf(varX, IRI.create(pred ++ RSASuffix.Backward.getSuffix), varY) ), Rule.create( - Atom.rdf(varY, IRI.create(pred ++ "_b" ++ "_inv"), varX), - Atom.rdf(varX, IRI.create(pred ++ "_f"), varY) + Atom.rdf( + varY, + IRI.create(pred ++ RSASuffix.Backward.getSuffix ++ "_inv"), + varX + ), + Atom.rdf(varX, IRI.create(pred ++ RSASuffix.Forward.getSuffix), varY) ), Rule.create( - Atom.rdf(varY, IRI.create(pred ++ "_f" ++ "_inv"), varX), - Atom.rdf(varX, IRI.create(pred ++ "_b"), varY) + Atom.rdf( + varY, + IRI.create(pred ++ RSASuffix.Forward.getSuffix ++ "_inv"), + varX + ), + Atom.rdf(varX, IRI.create(pred ++ RSASuffix.Backward.getSuffix), varY) ) ) } @@ -51,7 +59,7 @@ object ProgramGenerator { class ProgramGenerator( term: Term, unsafe: List[OWLObjectPropertyExpression] -) extends RDFoxAxiomConverter(term, SkolemStrategy.None, unsafe) +) extends RDFoxAxiomConverter(term, unsafe, SkolemStrategy.None, RSASuffix.None) with RSAAxiom { override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = { @@ -63,18 +71,18 @@ class ProgramGenerator( val visitor = new RDFoxAxiomConverter( term, + unsafe, SkolemStrategy.Standard(axiom.toString), - unsafe + RSASuffix.Forward ) axiom.accept(visitor) } else { - // TODO; Handle forks + List() } } else { // Fallback to standard OWL to LP translation super.visit(axiom) } - List() } override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = { diff --git a/src/main/scala/rsacomb/Main.scala b/src/main/scala/rsacomb/Main.scala index c6bd6a1..7900e19 100644 --- a/src/main/scala/rsacomb/Main.scala +++ b/src/main/scala/rsacomb/Main.scala @@ -52,6 +52,23 @@ object RSAComb extends App { /* Build canonical model */ //val tboxCanon = rsa.canonicalModel() + // DEBUG: print program to generate canonical model + { + import tech.oxfordsemantic.jrdfox.logic.{Variable} + import org.semanticweb.owlapi.model.parameters.Imports + import java.util.stream.{Collectors} + import scala.collection.JavaConverters._ + + val visitor = ProgramGenerator(Variable.create("x"), ontology.unsafeRoles) + val axioms = + ontology + .tboxAxioms(Imports.INCLUDED) + .collect(Collectors.toList()) + .asScala + println("Program to generate the canonical model:") + axioms.flatMap(_.accept(visitor)).foreach(println) + } + /* Load query */ val query = RDFoxUtil.parseQuery( "SELECT ?X WHERE {?X ?Y ?Z}" diff --git a/src/main/scala/rsacomb/RDFoxAxiomConverter.scala b/src/main/scala/rsacomb/RDFoxAxiomConverter.scala index d90c966..dab6765 100644 --- a/src/main/scala/rsacomb/RDFoxAxiomConverter.scala +++ b/src/main/scala/rsacomb/RDFoxAxiomConverter.scala @@ -23,24 +23,26 @@ object RDFoxAxiomConverter { def apply( term: Term, + unsafe: List[OWLObjectPropertyExpression], skolem: SkolemStrategy = SkolemStrategy.None, - unsafe: List[OWLObjectPropertyExpression] = List() + suffix: RSASuffix = RSASuffix.None ): RDFoxAxiomConverter = - new RDFoxAxiomConverter(term, skolem, unsafe) + new RDFoxAxiomConverter(term, unsafe, skolem, suffix) } // object RDFoxAxiomConverter class RDFoxAxiomConverter( term: Term, + unsafe: List[OWLObjectPropertyExpression], skolem: SkolemStrategy, - unsafe: List[OWLObjectPropertyExpression] + suffix: RSASuffix ) extends OWLAxiomVisitorEx[List[Rule]] { override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = { // Skolemization is needed only for the head of an axiom val subVisitor = - new RDFoxClassExprConverter(term, SkolemStrategy.None, unsafe) - val superVisitor = new RDFoxClassExprConverter(term, skolem, unsafe) + new RDFoxClassExprConverter(term, unsafe, SkolemStrategy.None, suffix) + val superVisitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix) // Each visitor returns a `RDFoxRuleShards`, a tuple (res,ext): // - the `res` List is a list of atoms resulting from the conversion // of the axiom. @@ -66,8 +68,8 @@ class RDFoxAxiomConverter( override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = { val term1 = RSA.getFreshVariable() val subVisitor = - new RDFoxPropertyExprConverter(term, term1, SkolemStrategy.None) - val superVisitor = new RDFoxPropertyExprConverter(term, term1, skolem) + new RDFoxPropertyExprConverter(term, term1, suffix) + val superVisitor = new RDFoxPropertyExprConverter(term, term1, suffix) val body: List[BodyFormula] = axiom.getSubProperty.accept(subVisitor) val head: List[Atom] = axiom.getSuperProperty.accept(superVisitor) List(Rule.create(head.asJava, body.asJava)) diff --git a/src/main/scala/rsacomb/RDFoxClassExprConverter.scala b/src/main/scala/rsacomb/RDFoxClassExprConverter.scala index a319d86..2029f0b 100644 --- a/src/main/scala/rsacomb/RDFoxClassExprConverter.scala +++ b/src/main/scala/rsacomb/RDFoxClassExprConverter.scala @@ -35,10 +35,11 @@ object RDFoxClassExprConverter { def apply( term: Term, + unsafe: List[OWLObjectPropertyExpression], skolem: SkolemStrategy = SkolemStrategy.None, - unsafe: List[OWLObjectPropertyExpression] = List() + suffix: RSASuffix = RSASuffix.None ): RDFoxClassExprConverter = - new RDFoxClassExprConverter(term, skolem, unsafe) + new RDFoxClassExprConverter(term, unsafe, skolem, suffix) def merge(rules: List[RDFoxRuleShards]): RDFoxRuleShards = { rules.foldLeft(RDFoxRuleShards(List(), List())) { (r1, r2) => @@ -53,8 +54,9 @@ object RDFoxClassExprConverter { class RDFoxClassExprConverter( term: Term, + unsafe: List[OWLObjectPropertyExpression], skolem: SkolemStrategy, - unsafe: List[OWLObjectPropertyExpression] + suffix: RSASuffix ) extends OWLClassExpressionVisitorEx[RDFoxRuleShards] { import RDFoxUtil.owlapi2rdfox; @@ -68,7 +70,7 @@ class RDFoxClassExprConverter( // OWLObjectIntersectionOf override def visit(expr: OWLObjectIntersectionOf): RDFoxRuleShards = { - val visitor = new RDFoxClassExprConverter(term, skolem, unsafe) + val visitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix) // TODO: maybe using `flatMap` instead of `merge` + `map` works as well RDFoxClassExprConverter.merge( expr.asConjunctSet.asScala.toList @@ -78,7 +80,7 @@ class RDFoxClassExprConverter( // OWLObjectOneOf override def visit(expr: OWLObjectOneOf): RDFoxRuleShards = { - val visitor = RDFoxClassExprConverter(term, skolem) + val visitor = RDFoxClassExprConverter(term, unsafe, skolem, suffix) // TODO: review nominal handling. Here we are taking "just" one val ind = expr.individuals .collect(Collectors.toList()) @@ -126,9 +128,10 @@ class RDFoxClassExprConverter( y ) } - val classVisitor = new RDFoxClassExprConverter(term1, skolem, unsafe) + val classVisitor = + new RDFoxClassExprConverter(term1, unsafe, skolem, suffix) val classResult = expr.getFiller.accept(classVisitor) - val propertyVisitor = new RDFoxPropertyExprConverter(term, term1, skolem) + val propertyVisitor = new RDFoxPropertyExprConverter(term, term1, suffix) val propertyResult = expr.getProperty.accept(propertyVisitor) RDFoxRuleShards( classResult.res ++ propertyResult ++ head, @@ -142,12 +145,12 @@ class RDFoxClassExprConverter( val vars = List(RSA.getFreshVariable(), RSA.getFreshVariable()) val classResult = RDFoxClassExprConverter.merge( vars - .map(new RDFoxClassExprConverter(_, skolem, unsafe)) + .map(new RDFoxClassExprConverter(_, unsafe, skolem, suffix)) .map(expr.getFiller.accept(_)) ) val propertyResult = vars - .map(new RDFoxPropertyExprConverter(term, _, skolem)) + .map(new RDFoxPropertyExprConverter(term, _, suffix)) .map(expr.getProperty.accept(_)) .flatten RDFoxRuleShards( diff --git a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala index 6eecdbf..ba151d0 100644 --- a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala +++ b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala @@ -5,24 +5,27 @@ import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx import tech.oxfordsemantic.jrdfox.logic.{Atom, Term, IRI, Literal} -import rsacomb.SkolemStrategy import org.semanticweb.owlapi.model.OWLObjectInverseOf class RDFoxPropertyExprConverter( term1: Term, term2: Term, - skolem: SkolemStrategy + suffix: RSASuffix ) extends OWLPropertyExpressionVisitorEx[List[Atom]] { // Automatically converts OWLAPI types into RDFox equivalent types. import RDFoxUtil.owlapi2rdfox; - override def visit(expr: OWLObjectProperty): List[Atom] = - List(Atom.rdf(term1, expr.getIRI, term2)) + override def visit(expr: OWLObjectProperty): List[Atom] = { + val pred = IRI.create(expr.getIRI.getIRIString ++ suffix.getSuffix) + List(Atom.rdf(term1, pred, term2)) + } override def visit(expr: OWLObjectInverseOf): List[Atom] = { - val name = expr.getInverse.getNamedProperty.getIRI.getIRIString; - List(Atom.rdf(term1, IRI.create(name ++ "_inv"), term2)) + val pred = IRI.create( + expr.getInverse.getNamedProperty.getIRI.getIRIString ++ suffix.getSuffix ++ "_inv" + ) + List(Atom.rdf(term1, pred, term2)) } def doDefault(expr: OWLPropertyExpression): List[Atom] = List() diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala index 4b872e5..79b8632 100644 --- a/src/main/scala/rsacomb/RSAOntology.scala +++ b/src/main/scala/rsacomb/RSAOntology.scala @@ -73,8 +73,9 @@ trait RSAOntology { axiom <- axioms visitor = new RDFoxAxiomConverter( RSA.getFreshVariable(), + unsafe, SkolemStrategy.ConstantRSA(axiom.toString), - unsafe + RSASuffix.None ) rule <- axiom.accept(visitor) } yield rule @@ -124,7 +125,7 @@ trait RSAOntology { graph.isAcyclic } - private def unsafeRoles: List[OWLObjectPropertyExpression] = { + lazy val unsafeRoles: List[OWLObjectPropertyExpression] = { // The reasoner is used to check unsafety condition for the ontology roles val factory = new StructuralReasonerFactory() val reasoner = factory.createReasoner(ontology) diff --git a/src/main/scala/rsacomb/RSASuffix.scala b/src/main/scala/rsacomb/RSASuffix.scala new file mode 100644 index 0000000..f15d01b --- /dev/null +++ b/src/main/scala/rsacomb/RSASuffix.scala @@ -0,0 +1,20 @@ +package rsacomb + +sealed trait RSASuffix { + def getSuffix: String; +} + +object RSASuffix { + + case object None extends RSASuffix { + def getSuffix: String = "" + } + + case object Forward extends RSASuffix { + def getSuffix: String = "_f" + } + + case object Backward extends RSASuffix { + def getSuffix: String = "_b" + } +} -- cgit v1.2.3