From 1d257a9287480014a4664c7808222179b6d2ae1d Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Tue, 6 Oct 2020 19:15:17 +0200 Subject: Complete generation of logic program for the canonical model --- src/main/scala/rsacomb/CanonicalModel.scala | 52 +++++++++++++++++++---------- src/main/scala/rsacomb/Main.scala | 14 +------- src/main/scala/rsacomb/RSAAxiom.scala | 8 ++++- src/main/scala/rsacomb/RSAOntology.scala | 34 ++++++++++++++++++- 4 files changed, 75 insertions(+), 33 deletions(-) (limited to 'src/main/scala') diff --git a/src/main/scala/rsacomb/CanonicalModel.scala b/src/main/scala/rsacomb/CanonicalModel.scala index c957940..95eb556 100644 --- a/src/main/scala/rsacomb/CanonicalModel.scala +++ b/src/main/scala/rsacomb/CanonicalModel.scala @@ -29,12 +29,12 @@ object ProgramGenerator { new ProgramGenerator(ontology, term, unsafe) def generateRoleRules( - roles: List[OWLObjectPropertyExpression] + roles: Set[OWLObjectProperty] ): List[Rule] = { def additional(pred: String): Seq[Rule] = { val varX = Variable.create("X") val varY = Variable.create("Y") - Seq( + List( Rule.create( Atom.rdf(varX, IRI.create(pred), varY), Atom.rdf(varX, IRI.create(pred ++ RSASuffix.Forward.getSuffix), varY) @@ -62,10 +62,14 @@ object ProgramGenerator { ) } roles - .filter(_.isInstanceOf[OWLObjectProperty]) // Can we avoid this? - .map(_.asInstanceOf[OWLObjectProperty].getIRI.getIRIString) + .map(_.getIRI.getIRIString) .flatMap(additional) + .toList } + + def NIs(individuals: List[IRI]): List[Atom] = + individuals.map(Atom.rdf(_, IRI.RDF_TYPE, RSA.internal("NI"))) + } class ProgramGenerator( @@ -78,7 +82,7 @@ class ProgramGenerator( import RDFoxUtil._ - def rules1(axiom: OWLSubClassOfAxiom): (List[Rule], List[Atom]) = { + def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = { val unfold = ontology.cycle(axiom).toList // Fresh Variables val v0 = IRI.create("v0_" ++ axiom.hashCode.toString) @@ -112,13 +116,16 @@ class ProgramGenerator( .getIRI Atom.rdf(v0, IRI.RDF_TYPE, cls) } - ( - List( - Rule.create(roleRf, atomA, notIn(varX)), - Rule.create(atomB, atomA, notIn(varX)) - ), - unfold map notIn + // TODO: To be consistent with the specifics of the visitor we are + // returning facts as `Rule`s with true body. While this is correct + // there is an easier way to import facts into RDFox. Are we able to + // do that? + val facts = unfold.map(x => Rule.create(notIn(x))) + val rules = List( + Rule.create(roleRf, atomA, notIn(varX)), + Rule.create(atomB, atomA, notIn(varX)) ) + facts ++ rules } def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = { @@ -209,10 +216,7 @@ class ProgramGenerator( ) axiom.accept(visitor) } else { - val (r1, f1) = rules1(axiom) - val r2 = rules2(axiom) - val r3 = rules3(axiom) - r1 ++ r2 ++ r3 + rules1(axiom) ++ rules2(axiom) ++ rules3(axiom) } } else { // Fallback to standard OWL to LP translation @@ -221,9 +225,21 @@ class ProgramGenerator( } override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = { - // TODO: Generate additional rules for role inclusion - val additional = List() - super.visit(axiom) ++ additional + val varX = Variable.create("X") + val varY = Variable.create("Y") + val visitorF = new RDFoxAxiomConverter( + term, + unsafe, + SkolemStrategy.None, + RSASuffix.Forward + ) + val visitorB = new RDFoxAxiomConverter( + term, + unsafe, + SkolemStrategy.None, + RSASuffix.Backward + ) + axiom.accept(visitorB) ++ axiom.accept(visitorF) } } diff --git a/src/main/scala/rsacomb/Main.scala b/src/main/scala/rsacomb/Main.scala index 7900e19..5d92061 100644 --- a/src/main/scala/rsacomb/Main.scala +++ b/src/main/scala/rsacomb/Main.scala @@ -54,19 +54,7 @@ object RSAComb extends App { // 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) + ontology.canonicalModel.foreach(println) } /* Load query */ diff --git a/src/main/scala/rsacomb/RSAAxiom.scala b/src/main/scala/rsacomb/RSAAxiom.scala index 50dc37e..aca44b1 100644 --- a/src/main/scala/rsacomb/RSAAxiom.scala +++ b/src/main/scala/rsacomb/RSAAxiom.scala @@ -8,6 +8,7 @@ import org.semanticweb.owlapi.model.{ } import org.semanticweb.owlapi.model.{ OWLObjectPropertyExpression, + OWLSubObjectPropertyOfAxiom, OWLClass, OWLClassExpression, OWLObjectSomeValuesFrom, @@ -148,11 +149,16 @@ trait RSAAxiom { List() } + override def visit( + axiom: OWLSubObjectPropertyOfAxiom + ): List[OWLObjectPropertyExpression] = + List(axiom.getSubProperty(), axiom.getSuperProperty()) + def doDefault(axiom: OWLAxiom): List[OWLObjectPropertyExpression] = List() } /* Exposed methods */ - def objectPropertyExpressionsInSignature + lazy val objectPropertyExpressionsInSignature : List[OWLObjectPropertyExpression] = { val visitor = new RSAAxiomRoleExtractor() axiom.accept(visitor) diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala index 0acf2a6..e4348d8 100644 --- a/src/main/scala/rsacomb/RSAOntology.scala +++ b/src/main/scala/rsacomb/RSAOntology.scala @@ -46,12 +46,13 @@ trait RSAOntology { .toList } - private lazy val roles: Set[OWLObjectPropertyExpression] = + private val roles: Set[OWLObjectPropertyExpression] = { ontology .rboxAxioms(Imports.INCLUDED) .collect(Collectors.toSet()) .asScala .flatMap(_.objectPropertyExpressionsInSignature) + } // OWLAPI reasoner for same easier tasks private val reasoner = @@ -199,6 +200,37 @@ trait RSAOntology { (unsafe1 ++ unsafe2).toList } + lazy val canonicalModel: List[Rule] = { + // Compute program to generate canonical model + val tbox = + ontology + .tboxAxioms(Imports.INCLUDED) + .collect(Collectors.toList()) + .asScala + .toList + val rbox = + ontology + .rboxAxioms(Imports.INCLUDED) + .collect(Collectors.toList()) + .asScala + .toList + val axioms = tbox ++ rbox + val varX = Variable.create("X") + val visitor = ProgramGenerator(ontology, varX, unsafeRoles) + val facts = ProgramGenerator.NIs(individuals) + val rules1 = ProgramGenerator.generateRoleRules( + axioms + .flatMap( + _.objectPropertiesInSignature.collect(Collectors.toSet()).asScala + ) + .toSet + ) + val rules2 = axioms.flatMap(_.accept(visitor)) + + rules1 ++ rules2 + // Call RDFox to generate the canonical model + } + private def rsaGraph( data: DataStoreConnection ): Graph[Resource, UnDiEdge] = { -- cgit v1.2.3