aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala')
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala291
1 files changed, 190 insertions, 101 deletions
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 30e1305..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}
27import org.semanticweb.owlapi.model.{ 27import 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,17 +47,20 @@ import tech.oxfordsemantic.jrdfox.client.{
46} 47}
47import tech.oxfordsemantic.jrdfox.Prefixes 48import tech.oxfordsemantic.jrdfox.Prefixes
48import tech.oxfordsemantic.jrdfox.logic.datalog.{ 49import tech.oxfordsemantic.jrdfox.logic.datalog.{
50 BodyFormula,
51 FilterAtom,
52 Negation,
49 Rule, 53 Rule,
50 TupleTableAtom, 54 TupleTableAtom,
51 Negation, 55 TupleTableName
52 BodyFormula
53} 56}
54import tech.oxfordsemantic.jrdfox.logic.expression.{ 57import tech.oxfordsemantic.jrdfox.logic.expression.{
55 Term, 58 FunctionCall,
56 Variable,
57 IRI, 59 IRI,
60 Literal,
58 Resource, 61 Resource,
59 Literal 62 Term,
63 Variable
60} 64}
61import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery 65import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery
62 66
@@ -81,30 +85,6 @@ import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA}
81import uk.ac.ox.cs.rsacomb.util.Logger 85import uk.ac.ox.cs.rsacomb.util.Logger
82import uk.ac.ox.cs.rsacomb.ontology.Ontology 86import uk.ac.ox.cs.rsacomb.ontology.Ontology
83 87
84object RSAUtil {
85
86 // implicit def axiomsToOntology(axioms: Seq[OWLAxiom]) = {
87 // val manager = OWLManager.createOWLOntologyManager()
88 // manager.createOntology(axioms.asJava)
89 // }
90
91 /** Manager instance to interface with OWLAPI */
92 val manager = OWLManager.createOWLOntologyManager()
93 val factory = manager.getOWLDataFactory()
94
95 /** Simple fresh variable/class generator */
96 private var counter = -1;
97 def genFreshVariable(): Variable = {
98 counter += 1
99 Variable.create(f"I$counter%05d")
100 }
101 def getFreshOWLClass(): OWLClass = {
102 counter += 1
103 factory.getOWLClass(s"X$counter")
104 }
105
106}
107
108object RSAOntology { 88object RSAOntology {
109 89
110 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ 90 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
@@ -115,6 +95,20 @@ object RSAOntology {
115 /** Name of the RDFox data store used for CQ answering */ 95 /** Name of the RDFox data store used for CQ answering */
116 private val DataStore = "answer_computation" 96 private val DataStore = "answer_computation"
117 97
98 /** Canonical model named graph */
99 private val CanonGraph: IRI =
100 RDFoxUtil.getNamedGraph(DataStore, "CanonicalModel")
101
102 /** Filtering program named graph
103 *
104 * @param query query associated with the returned named graph.
105 *
106 * @return named graph for the filtering program associated with the
107 * input query.
108 */
109 private def FilterGraph(query: ConjunctiveQuery): IRI =
110 RDFoxUtil.getNamedGraph(DataStore, s"Filter${query.id}")
111
118 /** Filtering program for a given query 112 /** Filtering program for a given query
119 * 113 *
120 * @param query the query to derive the filtering program 114 * @param query the query to derive the filtering program
@@ -122,15 +116,19 @@ object RSAOntology {
122 */ 116 */
123 def filteringProgram(query: ConjunctiveQuery): FilteringProgram = 117 def filteringProgram(query: ConjunctiveQuery): FilteringProgram =
124 Logger.timed( 118 Logger.timed(
125 FilteringProgram(FilterType.REVISED)(query), 119 {
120 val filter = FilteringProgram(FilterType.REVISED)
121 filter(CanonGraph, FilterGraph(query), query)
122 },
126 "Generating filtering program", 123 "Generating filtering program",
127 Logger.DEBUG 124 Logger.DEBUG
128 ) 125 )
129 126
130 def apply( 127 def apply(
128 origin: OWLOntology,
131 axioms: List[OWLLogicalAxiom], 129 axioms: List[OWLLogicalAxiom],
132 datafiles: List[File] 130 datafiles: List[os.Path]
133 ): RSAOntology = new RSAOntology(axioms, datafiles) 131 ): RSAOntology = new RSAOntology(origin, axioms, datafiles)
134 132
135 // def apply( 133 // def apply(
136 // ontofile: File, 134 // ontofile: File,
@@ -197,8 +195,11 @@ object RSAOntology {
197 * @param ontology the input OWL2 ontology. 195 * @param ontology the input OWL2 ontology.
198 * @param datafiles additinal data (treated as part of the ABox) 196 * @param datafiles additinal data (treated as part of the ABox)
199 */ 197 */
200class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) 198class RSAOntology(
201 extends Ontology(axioms, datafiles) { 199 origin: OWLOntology,
200 axioms: List[OWLLogicalAxiom],
201 datafiles: List[os.Path]
202) extends Ontology(origin, axioms, datafiles) {
202 203
203 /** Simplify conversion between OWLAPI and RDFox concepts */ 204 /** Simplify conversion between OWLAPI and RDFox concepts */
204 import implicits.RDFox._ 205 import implicits.RDFox._
@@ -227,10 +228,9 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File])
227 /** Retrieve concepts/roles in the ontology */ 228 /** Retrieve concepts/roles in the ontology */
228 val concepts: List[OWLClass] = 229 val concepts: List[OWLClass] =
229 ontology.getClassesInSignature().asScala.toList 230 ontology.getClassesInSignature().asScala.toList
230 val roles: List[OWLObjectPropertyExpression] = 231 val objroles: List[OWLObjectPropertyExpression] =
231 axioms 232 axioms.flatMap(_.objectPropertyExpressionsInSignature).distinct
232 .flatMap(_.objectPropertyExpressionsInSignature) 233 val dataroles: List[OWLDataProperty] = origin.getDataPropertiesInSignature
233 .distinct
234 234
235 /** Unsafe roles of a given ontology. 235 /** Unsafe roles of a given ontology.
236 * 236 *
@@ -364,21 +364,32 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File])
364 private val topAxioms: List[Rule] = { 364 private val topAxioms: List[Rule] = {
365 val varX = Variable.create("X") 365 val varX = Variable.create("X")
366 val varY = Variable.create("Y") 366 val varY = Variable.create("Y")
367 concepts 367 val varZ = Variable.create("Z")
368 .map(c => { 368 val graph = TupleTableName.create(RSAOntology.CanonGraph.getIRI)
369 Rule.create( 369 Rule.create(
370 RSA.Thing(varX), 370 TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING),
371 TupleTableAtom.rdf(varX, IRI.RDF_TYPE, c.getIRI) 371 TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, varY)
372 ) 372 ) :: objroles.map(r => {
373 }) ++ roles.map(r => {
374 val name = r match { 373 val name = r match {
375 case x: OWLObjectProperty => x.getIRI.getIRIString 374 case x: OWLObjectProperty => x.getIRI.getIRIString
376 case x: OWLObjectInverseOf => 375 case x: OWLObjectInverseOf =>
377 x.getInverse.getNamedProperty.getIRI.getIRIString :: Inverse 376 x.getInverse.getNamedProperty.getIRI.getIRIString :: Inverse
378 } 377 }
379 Rule.create( 378 Rule.create(
380 List(RSA.Thing(varX), RSA.Thing(varY)), 379 List(
381 List(TupleTableAtom.rdf(varX, name, varY)) 380 TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING),
381 TupleTableAtom.create(graph, varY, IRI.RDF_TYPE, IRI.THING)
382 ),
383 List(TupleTableAtom.create(graph, varX, name, varY))
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))
382 ) 393 )
383 }) 394 })
384 } 395 }
@@ -403,23 +414,31 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File])
403 val varX = Variable.create("X") 414 val varX = Variable.create("X")
404 val varY = Variable.create("Y") 415 val varY = Variable.create("Y")
405 val varZ = Variable.create("Z") 416 val varZ = Variable.create("Z")
406 List( 417 val graph = TupleTableName.create(RSAOntology.CanonGraph.getIRI)
418 // Equality properties
419 val properties = List(
407 // Reflexivity 420 // Reflexivity
408 Rule.create(RSA.Congruent(varX, varX), RSA.Thing(varX)), 421 Rule.create(
422 TupleTableAtom.create(graph, varX, RSA.CONGRUENT, varX),
423 TupleTableAtom.create(graph, varX, IRI.RDF_TYPE, IRI.THING)
424 ),
409 // Simmetry 425 // Simmetry
410 Rule.create(RSA.Congruent(varY, varX), RSA.Congruent(varX, varY)), 426 Rule.create(
427 TupleTableAtom.create(graph, varY, RSA.CONGRUENT, varX),
428 TupleTableAtom.create(graph, varX, RSA.CONGRUENT, varY)
429 ),
411 // Transitivity 430 // Transitivity
412 Rule.create( 431 Rule.create(
413 RSA.Congruent(varX, varZ), 432 TupleTableAtom.create(graph, varX, RSA.CONGRUENT, varZ),
414 RSA.Congruent(varX, varY), 433 TupleTableAtom.create(graph, varX, RSA.CONGRUENT, varY),
415 RSA.Congruent(varY, varZ) 434 TupleTableAtom.create(graph, varY, RSA.CONGRUENT, varZ)
416 ) 435 )
417 ) 436 )
418 } 437 }
419 438
420 /** Canonical model of the ontology */ 439 /** Canonical model of the ontology */
421 lazy val canonicalModel = Logger.timed( 440 lazy val canonicalModel = Logger.timed(
422 new CanonicalModel(this), 441 new CanonicalModel(this, RSAOntology.CanonGraph),
423 "Generating canonical model program", 442 "Generating canonical model program",
424 Logger.DEBUG 443 Logger.DEBUG
425 ) 444 )
@@ -520,73 +539,143 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File])
520 def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = 539 def unfold(axiom: OWLSubClassOfAxiom): Set[Term] =
521 this.self(axiom) | this.cycle(axiom) 540 this.self(axiom) | this.cycle(axiom)
522 541
523 /** Returns the answers to a query 542 /** Returns the answers to a single query
524 * 543 *
525 * @param query query to execute 544 * @param queries a sequence of conjunctive queries to answer.
526 * @return a collection of answers 545 * @return a collection of answers for each query.
527 */ 546 */
528 def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( 547 def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = this._ask(query)
529 {
530 val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore)
531 val canon = this.canonicalModel
532 val filter = RSAOntology.filteringProgram(query)
533 548
534 /* Upload data from data file */ 549 /** Returns the answers to a collection of queries
535 RDFoxUtil.addData(data, datafiles: _*) 550 *
536 551 * @param queries a sequence of conjunctive queries to answer.
537 RDFoxUtil printStatisticsFor data 552 * @return a collection of answers for each query.
553 */
554 def ask(queries: Seq[ConjunctiveQuery]): Seq[ConjunctiveQueryAnswers] =
555 queries map _ask
538 556
539 /* Top / equality axiomatization */ 557 private lazy val _ask: ConjunctiveQuery => ConjunctiveQueryAnswers = {
540 RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) 558 val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore)
541 559
542 /* Generate `named` predicates */ 560 /* Upload data from data file */
543 RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named) 561 RDFoxUtil.addData(data, RSAOntology.CanonGraph, datafiles: _*)
544 data.evaluateUpdate( 562
545 RSA.Prefixes, 563 /* Top/equality axiomatization */
546 "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }", 564 RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms)
547 new java.util.HashMap[String, String] 565 Logger.write(topAxioms.mkString("\n"), "canonical_model.datalog")
548 ) 566 Logger.write(equalityAxioms.mkString("\n"), "canonical_model.datalog")
567
568 /* Introduce `rsacomb:Named` concept */
569 data.evaluateUpdate(
570 null, // the base IRI for the query (if null, a default is used)
571 RSA.Prefixes,
572 s"""
573 INSERT {
574 GRAPH ${RSAOntology.CanonGraph} { ?X a ${RSA.NAMED} }
575 } WHERE {
576 GRAPH ${RSAOntology.CanonGraph} { ?X a ${IRI.THING} }
577 }
578 """,
579 new java.util.HashMap[String, String]
580 )
549 581
550 /* Add canonical model */ 582 /* Add canonical model */
551 Logger print s"Canonical model rules: ${canon.rules.length}" 583 Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}"
552 RDFoxUtil.addRules(data, canon.rules) 584 RDFoxUtil.addFacts(data, RSAOntology.CanonGraph, this.canonicalModel.facts)
585 Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}"
586 Logger.write(canonicalModel.rules.mkString("\n"), "canonical_model.datalog")
587 RDFoxUtil.addRules(data, this.canonicalModel.rules)
553 588
554 Logger print s"Canonical model facts: ${canon.facts.length}" 589 RDFoxUtil.closeConnection(server, data)
555 RDFoxUtil.addFacts(data, canon.facts)
556 590
557 RDFoxUtil printStatisticsFor data 591 (query => {
592 val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore)
558 593
559 //{ 594 val filter = RSAOntology.filteringProgram(query)
560 // import java.io.{PrintStream, FileOutputStream, File}
561 // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog"))
562 // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl"))
563 // RDFoxUtil.export(data, rules1, facts1)
564 // val rules2 = new PrintStream(new File("rules2-q34.dlog"))
565 // rules2.print(filter.rules.mkString("\n"))
566 //}
567 595
568 /* Add filtering program */ 596 /* Add filtering program */
569 Logger print s"Filtering program rules: ${filter.rules.length}" 597 Logger print s"Filtering program rules: ${filter.rules.length}"
598 Logger.write(filter.rules.mkString("\n"), s"filter${query.id}.datalog")
570 RDFoxUtil.addRules(data, filter.rules) 599 RDFoxUtil.addRules(data, filter.rules)
571 600
572 RDFoxUtil printStatisticsFor data 601 // TODO: We remove the rules, should we drop the tuple table as well?
602 data.clearRulesAxiomsExplicateFacts()
573 603
574 /* Gather answers to the query */ 604 /* Gather answers to the query */
575 val answers = { 605 val answers = RDFoxUtil
576 val ans = filter.answerQuery 606 .submitQuery(data, filter.answerQuery, RSA.Prefixes)
577 RDFoxUtil 607 .map(new ConjunctiveQueryAnswers(query, query.variables, _))
578 .submitQuery(data, ans, RSA.Prefixes) 608 .get
579 .map(new ConjunctiveQueryAnswers(query.bcq, query.variables, _))
580 .get
581 }
582 609
583 RDFoxUtil.closeConnection(server, data) 610 RDFoxUtil.closeConnection(server, data)
584 611
585 answers 612 answers
586 }, 613 })
587 "Answers computation", 614 }
588 Logger.DEBUG 615
589 ) 616 //def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed(
617 // {
618 // val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore)
619 // val canon = this.canonicalModel
620 // val filter = RSAOntology.filteringProgram(query)
621
622 // /* Upload data from data file */
623 // RDFoxUtil.addData(data, datafiles: _*)
624
625 // RDFoxUtil printStatisticsFor data
626
627 // /* Top / equality axiomatization */
628 // RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms)
629
630 // /* Generate `named` predicates */
631 // RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named)
632 // data.evaluateUpdate(
633 // null, // the base IRI for the query (if null, a default is used)
634 // RSA.Prefixes,
635 // "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }",
636 // new java.util.HashMap[String, String]
637 // )
638
639 // /* Add canonical model */
640 // Logger print s"Canonical model rules: ${canon.rules.length}"
641 // RDFoxUtil.addRules(data, canon.rules)
642
643 // Logger print s"Canonical model facts: ${canon.facts.length}"
644 // RDFoxUtil.addFacts(data, canon.facts)
645
646 // RDFoxUtil printStatisticsFor data
647
648 // //{
649 // // import java.io.{PrintStream, FileOutputStream, File}
650 // // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog"))
651 // // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl"))
652 // // RDFoxUtil.export(data, rules1, facts1)
653 // // val rules2 = new PrintStream(new File("rules2-q34.dlog"))
654 // // rules2.print(filter.rules.mkString("\n"))
655 // //}
656
657 // /* Add filtering program */
658 // Logger print s"Filtering program rules: ${filter.rules.length}"
659 // RDFoxUtil.addRules(data, filter.rules)
660
661 // RDFoxUtil printStatisticsFor data
662
663 // /* Gather answers to the query */
664 // val answers = {
665 // val ans = filter.answerQuery
666 // RDFoxUtil
667 // .submitQuery(data, ans, RSA.Prefixes)
668 // .map(new ConjunctiveQueryAnswers(query, query.variables, _))
669 // .get
670 // }
671
672 // RDFoxUtil.closeConnection(server, data)
673
674 // answers
675 // },
676 // "Answers computation",
677 // Logger.DEBUG
678 //)
590 679
591 /** Query the RDFox data store used for query answering. 680 /** Query the RDFox data store used for query answering.
592 * 681 *