diff options
author | Federico Igne <git@federicoigne.com> | 2021-10-04 18:01:50 +0100 |
---|---|---|
committer | Federico Igne <git@federicoigne.com> | 2021-10-04 18:16:15 +0100 |
commit | c86e7d32420adcc05546efa45b21e0e31d0f6c90 (patch) | |
tree | d1f006a145b9830ca45383f510348fc049e4b72b | |
parent | 55e374c98c1446c612fecd78a352cc870755ef7c (diff) | |
download | RSAComb-c86e7d32420adcc05546efa45b21e0e31d0f6c90.tar.gz RSAComb-c86e7d32420adcc05546efa45b21e0e31d0f6c90.zip |
Fix issue where not all roles where considered for top axiomatisation
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) { | |||
68 | */ | 68 | */ |
69 | val rolesAdditionalRules: List[Rule] = { | 69 | val rolesAdditionalRules: List[Rule] = { |
70 | val tt = TupleTableName.create(graph.getIRI) | 70 | val tt = TupleTableName.create(graph.getIRI) |
71 | ontology.roles | 71 | ontology.objroles |
72 | .collect { case prop: OWLObjectProperty => prop } | 72 | .collect { case prop: OWLObjectProperty => prop } |
73 | .flatMap((pred) => { | 73 | .flatMap((pred) => { |
74 | val iri = pred.getIRI.getIRIString | 74 | 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} | |||
27 | import org.semanticweb.owlapi.model.{ | 27 | import org.semanticweb.owlapi.model.{ |
28 | OWLClass, | 28 | OWLClass, |
29 | OWLClassExpression, | 29 | OWLClassExpression, |
30 | OWLDataProperty, | ||
30 | OWLDataPropertyAssertionAxiom, | 31 | OWLDataPropertyAssertionAxiom, |
31 | OWLObjectProperty, | 32 | OWLObjectProperty, |
32 | OWLSubObjectPropertyOfAxiom, | 33 | OWLSubObjectPropertyOfAxiom, |
@@ -46,18 +47,20 @@ import tech.oxfordsemantic.jrdfox.client.{ | |||
46 | } | 47 | } |
47 | import tech.oxfordsemantic.jrdfox.Prefixes | 48 | import tech.oxfordsemantic.jrdfox.Prefixes |
48 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | 49 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ |
50 | BodyFormula, | ||
51 | FilterAtom, | ||
52 | Negation, | ||
49 | Rule, | 53 | Rule, |
50 | TupleTableAtom, | 54 | TupleTableAtom, |
51 | TupleTableName, | 55 | TupleTableName |
52 | Negation, | ||
53 | BodyFormula | ||
54 | } | 56 | } |
55 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | 57 | import tech.oxfordsemantic.jrdfox.logic.expression.{ |
56 | Term, | 58 | FunctionCall, |
57 | Variable, | ||
58 | IRI, | 59 | IRI, |
60 | Literal, | ||
59 | Resource, | 61 | Resource, |
60 | Literal | 62 | Term, |
63 | Variable | ||
61 | } | 64 | } |
62 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery | 65 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery |
63 | 66 | ||
@@ -122,9 +125,10 @@ object RSAOntology { | |||
122 | ) | 125 | ) |
123 | 126 | ||
124 | def apply( | 127 | def apply( |
128 | origin: OWLOntology, | ||
125 | axioms: List[OWLLogicalAxiom], | 129 | axioms: List[OWLLogicalAxiom], |
126 | datafiles: List[os.Path] | 130 | datafiles: List[os.Path] |
127 | ): RSAOntology = new RSAOntology(axioms, datafiles) | 131 | ): RSAOntology = new RSAOntology(origin, axioms, datafiles) |
128 | 132 | ||
129 | // def apply( | 133 | // def apply( |
130 | // ontofile: File, | 134 | // ontofile: File, |
@@ -191,8 +195,11 @@ object RSAOntology { | |||
191 | * @param ontology the input OWL2 ontology. | 195 | * @param ontology the input OWL2 ontology. |
192 | * @param datafiles additinal data (treated as part of the ABox) | 196 | * @param datafiles additinal data (treated as part of the ABox) |
193 | */ | 197 | */ |
194 | class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | 198 | class RSAOntology( |
195 | extends Ontology(axioms, datafiles) { | 199 | origin: OWLOntology, |
200 | axioms: List[OWLLogicalAxiom], | ||
201 | datafiles: List[os.Path] | ||
202 | ) extends Ontology(origin, axioms, datafiles) { | ||
196 | 203 | ||
197 | /** Simplify conversion between OWLAPI and RDFox concepts */ | 204 | /** Simplify conversion between OWLAPI and RDFox concepts */ |
198 | import implicits.RDFox._ | 205 | import implicits.RDFox._ |
@@ -221,10 +228,9 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
221 | /** Retrieve concepts/roles in the ontology */ | 228 | /** Retrieve concepts/roles in the ontology */ |
222 | val concepts: List[OWLClass] = | 229 | val concepts: List[OWLClass] = |
223 | ontology.getClassesInSignature().asScala.toList | 230 | ontology.getClassesInSignature().asScala.toList |
224 | val roles: List[OWLObjectPropertyExpression] = | 231 | val objroles: List[OWLObjectPropertyExpression] = |
225 | axioms | 232 | axioms.flatMap(_.objectPropertyExpressionsInSignature).distinct |
226 | .flatMap(_.objectPropertyExpressionsInSignature) | 233 | val dataroles: List[OWLDataProperty] = origin.getDataPropertiesInSignature |
227 | .distinct | ||
228 | 234 | ||
229 | /** Unsafe roles of a given ontology. | 235 | /** Unsafe roles of a given ontology. |
230 | * | 236 | * |
@@ -358,14 +364,12 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
358 | private val topAxioms: List[Rule] = { | 364 | private val topAxioms: List[Rule] = { |
359 | val varX = Variable.create("X") | 365 | val varX = Variable.create("X") |
360 | val varY = Variable.create("Y") | 366 | val varY = Variable.create("Y") |
367 | val varZ = Variable.create("Z") | ||
361 | val graph = TupleTableName.create(RSAOntology.CanonGraph.getIRI) | 368 | val graph = TupleTableName.create(RSAOntology.CanonGraph.getIRI) |
362 | concepts | 369 | Rule.create( |
363 | .map(c => { | 370 | TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), |
364 | Rule.create( | 371 | TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, varY) |
365 | TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), | 372 | ) :: objroles.map(r => { |
366 | TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, c.getIRI) | ||
367 | ) | ||
368 | }) ++ roles.map(r => { | ||
369 | val name = r match { | 373 | val name = r match { |
370 | case x: OWLObjectProperty => x.getIRI.getIRIString | 374 | case x: OWLObjectProperty => x.getIRI.getIRIString |
371 | case x: OWLObjectInverseOf => | 375 | case x: OWLObjectInverseOf => |
@@ -378,6 +382,15 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
378 | ), | 382 | ), |
379 | List(TupleTableAtom.create(graph, varX, name, varY)) | 383 | List(TupleTableAtom.create(graph, varX, name, varY)) |
380 | ) | 384 | ) |
385 | }) ::: dataroles.map(r => { | ||
386 | val name = r.getIRI.getIRIString | ||
387 | Rule.create( | ||
388 | List( | ||
389 | TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING), | ||
390 | TupleTableAtom.create(graph, varY, IRI.RDF_TYPE, IRI.THING) | ||
391 | ), | ||
392 | List(TupleTableAtom.create(graph, varX, name, varY)) | ||
393 | ) | ||
381 | }) | 394 | }) |
382 | } | 395 | } |
383 | 396 | ||
@@ -542,22 +555,17 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
542 | queries map _ask | 555 | queries map _ask |
543 | 556 | ||
544 | private lazy val _ask: ConjunctiveQuery => ConjunctiveQueryAnswers = { | 557 | private lazy val _ask: ConjunctiveQuery => ConjunctiveQueryAnswers = { |
545 | /* Open connection with RDFox server */ | ||
546 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) | 558 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) |
547 | 559 | ||
548 | /* Upload data from data file */ | 560 | /* Upload data from data file */ |
549 | RDFoxUtil.addData(data, RSAOntology.CanonGraph, datafiles: _*) | 561 | RDFoxUtil.addData(data, RSAOntology.CanonGraph, datafiles: _*) |
550 | /* Top / equality axiomatization */ | 562 | |
563 | /* Top/equality axiomatization */ | ||
551 | RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) | 564 | RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) |
552 | Logger.write(topAxioms.mkString("\n"), "canonical_model.datalog") | 565 | Logger.write(topAxioms.mkString("\n"), "canonical_model.datalog") |
553 | Logger.write(equalityAxioms.mkString("\n"), "canonical_model.datalog") | 566 | Logger.write(equalityAxioms.mkString("\n"), "canonical_model.datalog") |
554 | /* Generate `named` predicates */ | 567 | |
555 | // TODO: do I need both to generate all NAMED atoms? | 568 | /* Introduce `rsacomb:Named` concept */ |
556 | RDFoxUtil.addFacts( | ||
557 | data, | ||
558 | RSAOntology.CanonGraph, | ||
559 | (individuals ++ literals) map RSA.Named(RSAOntology.CanonGraph) | ||
560 | ) | ||
561 | data.evaluateUpdate( | 569 | data.evaluateUpdate( |
562 | null, // the base IRI for the query (if null, a default is used) | 570 | null, // the base IRI for the query (if null, a default is used) |
563 | RSA.Prefixes, | 571 | RSA.Prefixes, |
@@ -572,25 +580,24 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
572 | ) | 580 | ) |
573 | 581 | ||
574 | /* Add canonical model */ | 582 | /* Add canonical model */ |
583 | Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" | ||
584 | RDFoxUtil.addFacts(data, RSAOntology.CanonGraph, this.canonicalModel.facts) | ||
575 | Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}" | 585 | Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}" |
576 | Logger.write(canonicalModel.rules.mkString("\n"), "canonical_model.datalog") | 586 | Logger.write(canonicalModel.rules.mkString("\n"), "canonical_model.datalog") |
577 | RDFoxUtil.addRules(data, this.canonicalModel.rules) | 587 | RDFoxUtil.addRules(data, this.canonicalModel.rules) |
578 | 588 | ||
579 | Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" | ||
580 | RDFoxUtil.addFacts(data, RSAOntology.CanonGraph, this.canonicalModel.facts) | ||
581 | |||
582 | /* Close connection with RDFox server */ | ||
583 | RDFoxUtil.closeConnection(server, data) | 589 | RDFoxUtil.closeConnection(server, data) |
584 | 590 | ||
585 | (query => { | 591 | (query => { |
586 | /* Open connection with RDFox server */ | ||
587 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) | 592 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) |
593 | |||
588 | val filter = RSAOntology.filteringProgram(query) | 594 | val filter = RSAOntology.filteringProgram(query) |
589 | 595 | ||
590 | /* Add filtering program */ | 596 | /* Add filtering program */ |
591 | Logger print s"Filtering program rules: ${filter.rules.length}" | 597 | Logger print s"Filtering program rules: ${filter.rules.length}" |
592 | Logger.write(filter.rules.mkString("\n"), s"filter${query.id}.datalog") | 598 | Logger.write(filter.rules.mkString("\n"), s"filter${query.id}.datalog") |
593 | RDFoxUtil.addRules(data, filter.rules) | 599 | RDFoxUtil.addRules(data, filter.rules) |
600 | |||
594 | // TODO: We remove the rules, should we drop the tuple table as well? | 601 | // TODO: We remove the rules, should we drop the tuple table as well? |
595 | data.clearRulesAxiomsExplicateFacts() | 602 | data.clearRulesAxiomsExplicateFacts() |
596 | 603 | ||
@@ -600,7 +607,6 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]) | |||
600 | .map(new ConjunctiveQueryAnswers(query, query.variables, _)) | 607 | .map(new ConjunctiveQueryAnswers(query, query.variables, _)) |
601 | .get | 608 | .get |
602 | 609 | ||
603 | /* Close connection with RDFox server */ | ||
604 | RDFoxUtil.closeConnection(server, data) | 610 | RDFoxUtil.closeConnection(server, data) |
605 | 611 | ||
606 | answers | 612 | 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) | |||
51 | def approximate(ontology: Ontology): RSAOntology = | 51 | def approximate(ontology: Ontology): RSAOntology = |
52 | toRSA( | 52 | toRSA( |
53 | new Ontology( | 53 | new Ontology( |
54 | ontology.origin, | ||
54 | ontology.axioms filter inALCHOIQ flatMap shift, | 55 | ontology.axioms filter inALCHOIQ flatMap shift, |
55 | ontology.datafiles | 56 | ontology.datafiles |
56 | ) | 57 | ) |
@@ -218,7 +219,11 @@ class Lowerbound(implicit fresh: DataFactory) | |||
218 | }.toList | 219 | }.toList |
219 | 220 | ||
220 | /* Remove axioms from approximated ontology */ | 221 | /* Remove axioms from approximated ontology */ |
221 | RSAOntology(ontology.axioms diff toDelete, ontology.datafiles) | 222 | RSAOntology( |
223 | ontology.origin, | ||
224 | ontology.axioms diff toDelete, | ||
225 | ontology.datafiles | ||
226 | ) | ||
222 | } | 227 | } |
223 | 228 | ||
224 | // val edges1 = Seq('A ~> 'B, 'B ~> 'C, 'C ~> 'D, 'D ~> 'H, 'H ~> | 229 | // 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) | |||
51 | def approximate(ontology: Ontology): RSAOntology = | 51 | def approximate(ontology: Ontology): RSAOntology = |
52 | toRSA( | 52 | toRSA( |
53 | new Ontology( | 53 | new Ontology( |
54 | ontology.origin, | ||
54 | ontology.axioms flatMap toConjuncts, | 55 | ontology.axioms flatMap toConjuncts, |
55 | ontology.datafiles | 56 | ontology.datafiles |
56 | ) | 57 | ) |
@@ -161,6 +162,7 @@ class Upperbound(implicit fresh: DataFactory) | |||
161 | 162 | ||
162 | /* Substitute selected axioms with their "skolemized" version */ | 163 | /* Substitute selected axioms with their "skolemized" version */ |
163 | RSAOntology( | 164 | RSAOntology( |
165 | ontology.origin, | ||
164 | ontology.axioms diff toSkolem concat skolemized, | 166 | ontology.axioms diff toSkolem concat skolemized, |
165 | ontology.datafiles | 167 | ontology.datafiles |
166 | ) | 168 | ) |
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 { | |||
42 | import scala.collection.JavaConverters._ | 42 | import scala.collection.JavaConverters._ |
43 | 43 | ||
44 | implicit class MyVariable(private val str: StringContext) extends AnyVal { | 44 | implicit class MyVariable(private val str: StringContext) extends AnyVal { |
45 | def v(args: Any*): Variable = Variable.create(s"${str.s(args: _*)}i") | 45 | def v(args: Any*): Variable = Variable.create(s"${str.s(args: _*)}") |
46 | } | 46 | } |
47 | 47 | ||
48 | } | 48 | } |
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 { | |||
167 | (graph, nodemap) | 167 | (graph, nodemap) |
168 | } | 168 | } |
169 | 169 | ||
170 | def apply(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]): Ontology = | 170 | // def apply(axioms: List[OWLLogicalAxiom], datafiles: List[os.Path]): Ontology = |
171 | new Ontology(axioms, datafiles) | 171 | // new Ontology(axioms, datafiles) |
172 | 172 | ||
173 | def apply(ontology: OWLOntology, datafiles: List[os.Path]): Ontology = { | 173 | def apply(ontology: OWLOntology, datafiles: List[os.Path]): Ontology = { |
174 | 174 | ||
@@ -199,7 +199,7 @@ object Ontology { | |||
199 | .collect(Collectors.toList()) | 199 | .collect(Collectors.toList()) |
200 | .collect { case a: OWLLogicalAxiom => a } | 200 | .collect { case a: OWLLogicalAxiom => a } |
201 | 201 | ||
202 | Ontology(abox ::: tbox ::: rbox, datafiles) | 202 | new Ontology(ontology, abox ::: tbox ::: rbox, datafiles) |
203 | } | 203 | } |
204 | 204 | ||
205 | def apply(ontofile: os.Path, datafiles: List[os.Path]): Ontology = { | 205 | def apply(ontofile: os.Path, datafiles: List[os.Path]): Ontology = { |
@@ -215,6 +215,7 @@ object Ontology { | |||
215 | * @param datafiles files containing ABox data. | 215 | * @param datafiles files containing ABox data. |
216 | */ | 216 | */ |
217 | class Ontology( | 217 | class Ontology( |
218 | val origin: OWLOntology, | ||
218 | val axioms: List[OWLLogicalAxiom], | 219 | val axioms: List[OWLLogicalAxiom], |
219 | val datafiles: List[os.Path] | 220 | val datafiles: List[os.Path] |
220 | ) { | 221 | ) { |
@@ -293,6 +294,7 @@ class Ontology( | |||
293 | */ | 294 | */ |
294 | def normalize(normalizer: Normalizer): Ontology = | 295 | def normalize(normalizer: Normalizer): Ontology = |
295 | new Ontology( | 296 | new Ontology( |
297 | origin, | ||
296 | axioms flatMap normalizer.normalize, | 298 | axioms flatMap normalizer.normalize, |
297 | datafiles | 299 | datafiles |
298 | ) | 300 | ) |