From c86e7d32420adcc05546efa45b21e0e31d0f6c90 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Mon, 4 Oct 2021 18:01:50 +0100 Subject: Fix issue where not all roles where considered for top axiomatisation --- .../scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala | 2 +- .../scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 76 ++++++++++++---------- .../ox/cs/rsacomb/approximation/Lowerbound.scala | 7 +- .../ox/cs/rsacomb/approximation/Upperbound.scala | 2 + .../filtering/RevisedFilteringProgram.scala | 2 +- .../uk/ac/ox/cs/rsacomb/ontology/Ontology.scala | 8 ++- 6 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala index a39b9c0..bd3d3c3 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/CanonicalModel.scala @@ -68,7 +68,7 @@ class CanonicalModel(val ontology: RSAOntology, val graph: IRI) { */ val rolesAdditionalRules: List[Rule] = { val tt = TupleTableName.create(graph.getIRI) - ontology.roles + ontology.objroles .collect { case prop: OWLObjectProperty => prop } .flatMap((pred) => { val iri = pred.getIRI.getIRIString 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 afda25e..1ff466b 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala @@ -27,6 +27,7 @@ import org.semanticweb.owlapi.model.{OWLOntology, OWLAxiom, OWLLogicalAxiom} import org.semanticweb.owlapi.model.{ OWLClass, OWLClassExpression, + OWLDataProperty, OWLDataPropertyAssertionAxiom, OWLObjectProperty, OWLSubObjectPropertyOfAxiom, @@ -46,18 +47,20 @@ import tech.oxfordsemantic.jrdfox.client.{ } import tech.oxfordsemantic.jrdfox.Prefixes import tech.oxfordsemantic.jrdfox.logic.datalog.{ + BodyFormula, + FilterAtom, + Negation, Rule, TupleTableAtom, - TupleTableName, - Negation, - BodyFormula + TupleTableName } import tech.oxfordsemantic.jrdfox.logic.expression.{ - Term, - Variable, + FunctionCall, IRI, + Literal, Resource, - Literal + Term, + Variable } import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery @@ -122,9 +125,10 @@ object RSAOntology { ) def apply( + origin: OWLOntology, axioms: List[OWLLogicalAxiom], datafiles: List[os.Path] - ): RSAOntology = new RSAOntology(axioms, datafiles) + ): RSAOntology = new RSAOntology(origin, axioms, datafiles) // def apply( // ontofile: File, @@ -191,8 +195,11 @@ object RSAOntology { * @param ontology the input OWL2 ontology. * @param datafiles additinal data (treated as part of the ABox) */ -class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) - extends Ontology(axioms, datafiles) { +class RSAOntology( + origin: OWLOntology, + axioms: List[OWLLogicalAxiom], + datafiles: List[os.Path] +) extends Ontology(origin, axioms, datafiles) { /** Simplify conversion between OWLAPI and RDFox concepts */ import implicits.RDFox._ @@ -221,10 +228,9 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) /** Retrieve concepts/roles in the ontology */ val concepts: List[OWLClass] = ontology.getClassesInSignature().asScala.toList - val roles: List[OWLObjectPropertyExpression] = - axioms - .flatMap(_.objectPropertyExpressionsInSignature) - .distinct + val objroles: List[OWLObjectPropertyExpression] = + axioms.flatMap(_.objectPropertyExpressionsInSignature).distinct + val dataroles: List[OWLDataProperty] = origin.getDataPropertiesInSignature /** Unsafe roles of a given ontology. * @@ -358,14 +364,12 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) private val topAxioms: List[Rule] = { val varX = Variable.create("X") val varY = Variable.create("Y") + val varZ = Variable.create("Z") val graph = TupleTableName.create(RSAOntology.CanonGraph.getIRI) - concepts - .map(c => { - Rule.create( - TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), - TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, c.getIRI) - ) - }) ++ roles.map(r => { + Rule.create( + TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), + TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, varY) + ) :: objroles.map(r => { val name = r match { case x: OWLObjectProperty => x.getIRI.getIRIString case x: OWLObjectInverseOf => @@ -378,6 +382,15 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) ), List(TupleTableAtom.create(graph, varX, name, varY)) ) + }) ::: dataroles.map(r => { + val name = r.getIRI.getIRIString + Rule.create( + List( + TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), + TupleTableAtom.create(graph, varY, IRI.RDF_TYPE, IRI.THING) + ), + List(TupleTableAtom.create(graph, varX, name, varY)) + ) }) } @@ -542,22 +555,17 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) queries map _ask private lazy val _ask: ConjunctiveQuery => ConjunctiveQueryAnswers = { - /* Open connection with RDFox server */ val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) /* Upload data from data file */ RDFoxUtil.addData(data, RSAOntology.CanonGraph, datafiles: _*) - /* Top / equality axiomatization */ + + /* Top/equality axiomatization */ RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) Logger.write(topAxioms.mkString("\n"), "canonical_model.datalog") Logger.write(equalityAxioms.mkString("\n"), "canonical_model.datalog") - /* Generate `named` predicates */ - // TODO: do I need both to generate all NAMED atoms? - RDFoxUtil.addFacts( - data, - RSAOntology.CanonGraph, - (individuals ++ literals) map RSA.Named(RSAOntology.CanonGraph) - ) + + /* Introduce `rsacomb:Named` concept */ data.evaluateUpdate( null, // the base IRI for the query (if null, a default is used) RSA.Prefixes, @@ -572,25 +580,24 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) ) /* Add canonical model */ + Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" + RDFoxUtil.addFacts(data, RSAOntology.CanonGraph, this.canonicalModel.facts) Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}" Logger.write(canonicalModel.rules.mkString("\n"), "canonical_model.datalog") RDFoxUtil.addRules(data, this.canonicalModel.rules) - Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" - RDFoxUtil.addFacts(data, RSAOntology.CanonGraph, this.canonicalModel.facts) - - /* Close connection with RDFox server */ RDFoxUtil.closeConnection(server, data) (query => { - /* Open connection with RDFox server */ val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) + val filter = RSAOntology.filteringProgram(query) /* Add filtering program */ Logger print s"Filtering program rules: ${filter.rules.length}" Logger.write(filter.rules.mkString("\n"), s"filter${query.id}.datalog") RDFoxUtil.addRules(data, filter.rules) + // TODO: We remove the rules, should we drop the tuple table as well? data.clearRulesAxiomsExplicateFacts() @@ -600,7 +607,6 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) .map(new ConjunctiveQueryAnswers(query, query.variables, _)) .get - /* Close connection with RDFox server */ RDFoxUtil.closeConnection(server, data) answers diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Lowerbound.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Lowerbound.scala index 88732d5..e261bce 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Lowerbound.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Lowerbound.scala @@ -51,6 +51,7 @@ class Lowerbound(implicit fresh: DataFactory) def approximate(ontology: Ontology): RSAOntology = toRSA( new Ontology( + ontology.origin, ontology.axioms filter inALCHOIQ flatMap shift, ontology.datafiles ) @@ -218,7 +219,11 @@ class Lowerbound(implicit fresh: DataFactory) }.toList /* Remove axioms from approximated ontology */ - RSAOntology(ontology.axioms diff toDelete, ontology.datafiles) + RSAOntology( + ontology.origin, + ontology.axioms diff toDelete, + ontology.datafiles + ) } // val edges1 = Seq('A ~> 'B, 'B ~> 'C, 'C ~> 'D, 'D ~> 'H, 'H ~> diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala index 1ae7941..469d774 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala @@ -51,6 +51,7 @@ class Upperbound(implicit fresh: DataFactory) def approximate(ontology: Ontology): RSAOntology = toRSA( new Ontology( + ontology.origin, ontology.axioms flatMap toConjuncts, ontology.datafiles ) @@ -161,6 +162,7 @@ class Upperbound(implicit fresh: DataFactory) /* Substitute selected axioms with their "skolemized" version */ RSAOntology( + ontology.origin, ontology.axioms diff toSkolem concat skolemized, ontology.datafiles ) 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 f059bcd..94524be 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 @@ -42,7 +42,7 @@ object RDFoxDSL { import scala.collection.JavaConverters._ implicit class MyVariable(private val str: StringContext) extends AnyVal { - def v(args: Any*): Variable = Variable.create(s"${str.s(args: _*)}i") + def v(args: Any*): Variable = Variable.create(s"${str.s(args: _*)}") } } diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/ontology/Ontology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/ontology/Ontology.scala index ece6d15..0aceb01 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/ontology/Ontology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/ontology/Ontology.scala @@ -167,8 +167,8 @@ object Ontology { (graph, nodemap) } - def apply(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]): Ontology = - new Ontology(axioms, datafiles) + // def apply(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]): Ontology = + // new Ontology(axioms, datafiles) def apply(ontology: OWLOntology, datafiles: List[os.Path]): Ontology = { @@ -199,7 +199,7 @@ object Ontology { .collect(Collectors.toList()) .collect { case a: OWLLogicalAxiom => a } - Ontology(abox ::: tbox ::: rbox, datafiles) + new Ontology(ontology, abox ::: tbox ::: rbox, datafiles) } def apply(ontofile: os.Path, datafiles: List[os.Path]): Ontology = { @@ -215,6 +215,7 @@ object Ontology { * @param datafiles files containing ABox data. */ class Ontology( + val origin: OWLOntology, val axioms: List[OWLLogicalAxiom], val datafiles: List[os.Path] ) { @@ -293,6 +294,7 @@ class Ontology( */ def normalize(normalizer: Normalizer): Ontology = new Ontology( + origin, axioms flatMap normalizer.normalize, datafiles ) -- cgit v1.2.3