aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala')
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala32
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala21
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala134
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala191
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxConverter.scala12
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala45
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala3
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala29
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala53
9 files changed, 101 insertions, 419 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
index eaacedc..f54884f 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
@@ -64,23 +64,35 @@ object RSAComb extends App {
64 case Some(query) => { 64 case Some(query) => {
65 val answers = ontology ask query 65 val answers = ontology ask query
66 Logger.print(s"$answers", Logger.QUIET) 66 Logger.print(s"$answers", Logger.QUIET)
67 Logger print s"Number of answer: ${answers.length}" 67 Logger print s"Number of answer: ${answers.length} (${answers.lengthWithMultiplicity})"
68 68
69 val unfiltered = ontology askUnfiltered query 69 val unfiltered = ontology askUnfiltered query
70 val percentage = unfiltered match { 70 unfiltered map { u =>
71 case Some(u) => { 71 Logger.print(
72 s"Number of unfiltered answers: ${u.length} (${u.map(_._1).sum}).",
73 Logger.DEBUG
74 )
75 //u foreach println
76 val spurious = {
77 val sp =
78 RDFoxUtil.buildDescriptionQuery("SP", query.variables.length)
79 ontology.queryDataStore(query, sp, RSA.Prefixes)
80 }
81 spurious map { s =>
72 Logger.print( 82 Logger.print(
73 s"Number of spurious answers: ${u.length}.", 83 s"Number of spurious answers: ${s.length} (${s.map(_._1).sum})",
84 Logger.DEBUG
85 )
86 //s foreach println
87 val perc =
88 if (u.length > 0) (s.length / u.length.toFloat) * 100 else 0
89 Logger.print(
90 s"Percentage of spurious answers: $perc%",
74 Logger.DEBUG 91 Logger.DEBUG
75 ) 92 )
76 if (u.length > 0) (1 - answers.length / u.length) * 100 else 0
77 } 93 }
78 case None => 0 94
79 } 95 }
80 Logger.print(
81 s"Percentage of spurious answers: $percentage%",
82 Logger.DEBUG
83 )
84 } 96 }
85 case None => 97 case None =>
86 throw new RuntimeException("Submitted query is not conjunctive") 98 throw new RuntimeException("Submitted query is not conjunctive")
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 0f1cd5e..4ac5a77 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
@@ -24,7 +24,11 @@ import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory
24import org.semanticweb.owlapi.model.{IRI => OWLIRI} 24import org.semanticweb.owlapi.model.{IRI => OWLIRI}
25import uk.ac.manchester.cs.owl.owlapi.OWLObjectPropertyImpl 25import uk.ac.manchester.cs.owl.owlapi.OWLObjectPropertyImpl
26 26
27import tech.oxfordsemantic.jrdfox.client.{UpdateType, DataStoreConnection} 27import tech.oxfordsemantic.jrdfox.client.{
28 DataStoreConnection,
29 TransactionType,
30 UpdateType
31}
28import tech.oxfordsemantic.jrdfox.Prefixes 32import tech.oxfordsemantic.jrdfox.Prefixes
29import tech.oxfordsemantic.jrdfox.logic.datalog.{ 33import tech.oxfordsemantic.jrdfox.logic.datalog.{
30 Rule, 34 Rule,
@@ -352,22 +356,31 @@ class RSAOntology(val ontology: OWLOntology) {
352 val canon = this.canonicalModel 356 val canon = this.canonicalModel
353 val filter = this.filteringProgram(query) 357 val filter = this.filteringProgram(query)
354 358
359 //data.beginTransaction(TransactionType.READ_WRITE)
360
355 Logger print s"Canonical model: ${canon.rules.length} rules" 361 Logger print s"Canonical model: ${canon.rules.length} rules"
356 RDFoxUtil.addRules(data, this.canonicalModel.rules) 362 RDFoxUtil.addRules(data, this.canonicalModel.rules)
357 363
358 Logger print s"Canonical model: ${canon.facts.length} facts" 364 Logger print s"Canonical model: ${canon.facts.length} facts"
359 RDFoxUtil.addFacts(data, this.canonicalModel.facts) 365 RDFoxUtil.addFacts(data, this.canonicalModel.facts)
360 366
361 RDFoxUtil printStatisticsFor data 367 Logger print s"Filtering program: ${filter.facts.length} facts"
368 RDFoxUtil.addFacts(data, filter.facts)
362 369
363 Logger print s"Filtering program: ${filter.rules.length} rules" 370 Logger print s"Filtering program: ${filter.rules.length} rules"
364 RDFoxUtil.addRules(data, filter.rules) 371 RDFoxUtil.addRules(data, filter.rules)
365 372
366 Logger print s"Filtering program: ${filter.facts.length} facts" 373 //data.commitTransaction()
367 RDFoxUtil.addFacts(data, filter.facts)
368 374
369 RDFoxUtil printStatisticsFor data 375 RDFoxUtil printStatisticsFor data
370 376
377 //{
378 // import java.io.{FileOutputStream, File}
379 // val rules = new FileOutputStream(new File("rules2.dlog"))
380 // val facts = new FileOutputStream(new File("facts2.ttl"))
381 // RDFoxUtil.export(data, rules, facts)
382 //}
383
371 val answers = { 384 val answers = {
372 val ans = RDFoxUtil.buildDescriptionQuery("Ans", query.answer.size) 385 val ans = RDFoxUtil.buildDescriptionQuery("Ans", query.answer.size)
373 RDFoxUtil 386 RDFoxUtil
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala
deleted file mode 100644
index 1fbf28a..0000000
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala
+++ /dev/null
@@ -1,134 +0,0 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import org.semanticweb.owlapi.model.{
4 OWLAxiom,
5 OWLSubClassOfAxiom,
6 OWLEquivalentClassesAxiom,
7 OWLObjectPropertyExpression,
8 OWLObjectPropertyDomainAxiom,
9 OWLObjectPropertyRangeAxiom,
10 OWLDataPropertyDomainAxiom,
11 OWLDataPropertyRangeAxiom,
12 OWLInverseObjectPropertiesAxiom
13}
14import org.semanticweb.owlapi.model.OWLAxiomVisitorEx
15
16import tech.oxfordsemantic.jrdfox.logic.datalog.{
17 Rule,
18 BodyFormula,
19 TupleTableAtom,
20 TupleTableName
21}
22import tech.oxfordsemantic.jrdfox.logic.expression.{
23 Term,
24 IRI => RDFoxIRI,
25 Variable,
26 Literal
27}
28
29import scala.collection.JavaConverters._
30
31import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom
32import org.semanticweb.owlapi.model.OWLObjectProperty
33import org.semanticweb.owlapi.model.OWLClassAssertionAxiom
34
35import uk.ac.ox.cs.rsacomb.RSAOntology
36import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty}
37import uk.ac.manchester.cs.owl.owlapi.OWLSubClassOfAxiomImpl
38import uk.ac.manchester.cs.owl.owlapi.OWLObjectSomeValuesFromImpl
39import uk.ac.manchester.cs.owl.owlapi.OWLClassImpl
40import org.semanticweb.owlapi.model.IRI
41
42object RDFoxAxiomConverter {
43
44 def apply(
45 term: Term,
46 unsafe: List[OWLObjectPropertyExpression],
47 skolem: SkolemStrategy = NoSkolem,
48 suffix: RSASuffix = Empty
49 ): RDFoxAxiomConverter =
50 new RDFoxAxiomConverter(term, unsafe, skolem, suffix)
51
52} // object RDFoxAxiomConverter
53
54class RDFoxAxiomConverter(
55 term: Term,
56 unsafe: List[OWLObjectPropertyExpression],
57 skolem: SkolemStrategy,
58 suffix: RSASuffix
59) extends OWLAxiomVisitorEx[List[Rule]] {
60
61 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
62
63 override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = {
64 // Skolemization is needed only for the head of an axiom
65 val subVisitor =
66 new RDFoxClassExprConverter(term, unsafe, NoSkolem, suffix)
67 val superVisitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
68 // Each visitor returns a `RDFoxRuleShards`, a tuple (res,ext):
69 // - the `res` List is a list of atoms resulting from the conversion
70 // of the axiom.
71 // - for some Class Expressions appearing in the head of an Axiom,
72 // the conversion might produce atoms that need to appear in the
73 // body (and not in the head) of the rule. This is what the `ext`
74 // List is for.
75 val sub = axiom.getSubClass.accept(subVisitor)
76 val sup = axiom.getSuperClass.accept(superVisitor)
77 val head = sup.res.asJava
78 val body = (sub.res ++ sup.ext).asJava
79 List(Rule.create(head, body))
80 }
81
82 override def visit(axiom: OWLEquivalentClassesAxiom): List[Rule] = {
83 for {
84 axiom1 <- axiom.asPairwiseAxioms.asScala.toList
85 axiom2 <- axiom1.asOWLSubClassOfAxioms.asScala.toList
86 rule <- axiom2.accept(this)
87 } yield rule
88 }
89
90 override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = {
91 val term1 = RSAOntology.genFreshVariable()
92 val subVisitor =
93 new RDFoxPropertyExprConverter(term, term1, suffix)
94 val superVisitor = new RDFoxPropertyExprConverter(term, term1, suffix)
95 val body: List[BodyFormula] = axiom.getSubProperty.accept(subVisitor)
96 val head: List[TupleTableAtom] = axiom.getSuperProperty.accept(superVisitor)
97 List(Rule.create(head.asJava, body.asJava))
98 }
99
100 override def visit(axiom: OWLObjectPropertyDomainAxiom): List[Rule] =
101 axiom.asOWLSubClassOfAxiom.accept(this)
102
103 override def visit(axiom: OWLObjectPropertyRangeAxiom): List[Rule] = {
104 val term1 = RSAOntology.genFreshVariable()
105 val rangeVisitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
106 val range = axiom.getRange.accept(rangeVisitor)
107 val propertyVisitor = new RDFoxPropertyExprConverter(term1, term, suffix)
108 val prop = axiom.getProperty.accept(propertyVisitor)
109 List(Rule.create(range.res, range.ext ::: prop))
110 }
111
112 override def visit(axiom: OWLDataPropertyDomainAxiom): List[Rule] =
113 axiom.asOWLSubClassOfAxiom.accept(this)
114
115 override def visit(axiom: OWLInverseObjectPropertiesAxiom): List[Rule] =
116 axiom.asSubObjectPropertyOfAxioms.asScala.toList.flatMap(_.accept(this))
117
118 override def visit(axiom: OWLClassAssertionAxiom): List[Rule] = {
119 val ind = axiom.getIndividual
120 if (ind.isNamed) {
121 val term = RDFoxIRI.create(ind.asOWLNamedIndividual().getIRI.getIRIString)
122 val cls = axiom.getClassExpression
123 val visitor =
124 new RDFoxClassExprConverter(term, unsafe, NoSkolem, suffix)
125 val shard = cls.accept(visitor)
126 List(Rule.create(shard.res.asJava, shard.ext.asJava))
127 } else {
128 List()
129 }
130 }
131
132 def doDefault(axiom: OWLAxiom): List[Rule] = List()
133
134} // class RDFoxAxiomConverter
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala
deleted file mode 100644
index 9551c61..0000000
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala
+++ /dev/null
@@ -1,191 +0,0 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import scala.collection.JavaConverters._
4import java.util.stream.{Stream, Collectors}
5
6import org.semanticweb.owlapi.model.{
7 OWLClassExpression,
8 OWLClass,
9 OWLObjectSomeValuesFrom,
10 OWLDataSomeValuesFrom,
11 OWLObjectIntersectionOf,
12 OWLObjectOneOf,
13 OWLObjectMaxCardinality
14}
15import org.semanticweb.owlapi.model.OWLClassExpressionVisitorEx
16import tech.oxfordsemantic.jrdfox.logic.Datatype
17import tech.oxfordsemantic.jrdfox.logic.datalog.{
18 BindAtom,
19 TupleTableName,
20 TupleTableAtom
21}
22import tech.oxfordsemantic.jrdfox.logic.expression.{
23 Term,
24 Literal,
25 Variable,
26 FunctionCall,
27 IRI
28}
29
30import org.semanticweb.owlapi.model.OWLObjectPropertyExpression
31import org.semanticweb.owlapi.model.OWLObjectProperty
32
33import uk.ac.ox.cs.rsacomb.RSAOntology
34import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty}
35import uk.ac.ox.cs.rsacomb.util.RSA
36
37object RDFoxClassExprConverter {
38
39 def apply(
40 term: Term,
41 unsafe: List[OWLObjectPropertyExpression] = List(),
42 skolem: SkolemStrategy = NoSkolem,
43 suffix: RSASuffix = Empty
44 ): RDFoxClassExprConverter =
45 new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
46
47 def merge(rules: List[RDFoxRuleShards]): RDFoxRuleShards = {
48 rules.foldLeft(RDFoxRuleShards(List(), List())) { (r1, r2) =>
49 RDFoxRuleShards(
50 r1.res ++ r2.res,
51 r1.ext ++ r2.ext
52 )
53 }
54 }
55
56} // object RDFoxClassExprConverter
57
58class RDFoxClassExprConverter(
59 term: Term,
60 unsafe: List[OWLObjectPropertyExpression],
61 skolem: SkolemStrategy = NoSkolem,
62 suffix: RSASuffix = Empty
63) extends OWLClassExpressionVisitorEx[RDFoxRuleShards] {
64
65 import uk.ac.ox.cs.rsacomb.implicits.RDFox._
66
67 // OWLClass
68 override def visit(expr: OWLClass): RDFoxRuleShards = {
69 val iri: IRI = if (expr.isTopEntity()) IRI.THING else expr.getIRI()
70 val atom = List(TupleTableAtom.rdf(term, IRI.RDF_TYPE, iri))
71 RDFoxRuleShards(atom, List())
72 }
73
74 // OWLObjectIntersectionOf
75 override def visit(expr: OWLObjectIntersectionOf): RDFoxRuleShards = {
76 val visitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
77 // TODO: maybe using `flatMap` instead of `merge` + `map` works as well
78 RDFoxClassExprConverter.merge(
79 expr.asConjunctSet.asScala.toList
80 .map((e: OWLClassExpression) => e.accept(visitor))
81 )
82 }
83
84 // OWLObjectOneOf
85 override def visit(expr: OWLObjectOneOf): RDFoxRuleShards = {
86 // TODO: review nominal handling. Here we are taking "just" one
87 val ind = expr.individuals
88 .collect(Collectors.toList())
89 .asScala
90 .filter(_.isOWLNamedIndividual)
91 .head // restricts to proper "nominals"
92 .asOWLNamedIndividual
93 .getIRI
94 val atom = List(
95 TupleTableAtom.rdf(term, IRI.SAME_AS, ind)
96 )
97 RDFoxRuleShards(atom, List())
98 }
99
100 // OWLObjectSomeValuesFrom
101 override def visit(expr: OWLObjectSomeValuesFrom): RDFoxRuleShards = {
102 val y = RSAOntology.genFreshVariable()
103 // Here we are assuming a role name
104 val prop = expr.getProperty()
105 // Computes the result of rule skolemization. Depending on the used
106 // technique it might involve the introduction of additional atoms,
107 // and/or fresh constants and variables.
108 val (head, body, term1) = skolem match {
109 case NoSkolem => (List(), List(), y)
110 case c: Constant => (List(), List(), c.iri)
111 case s: Standard => {
112 (
113 List(),
114 List(
115 BindAtom.create(FunctionCall.create("SKOLEM", s.literal, term), y)
116 ),
117 y
118 )
119 }
120 }
121 val classVisitor =
122 new RDFoxClassExprConverter(term1, unsafe, skolem, suffix)
123 val classResult = expr.getFiller.accept(classVisitor)
124 val propertyVisitor = new RDFoxPropertyExprConverter(term, term1, suffix)
125 val propertyResult = expr.getProperty.accept(propertyVisitor)
126 RDFoxRuleShards(
127 classResult.res ++ propertyResult ++ head,
128 classResult.ext ++ body
129 )
130 }
131
132 /** Converts a [[org.semanticweb.owlapi.model.OWLDataSomeValuesFrom OWLDataSomeValuesFrom]]
133 *
134 * @note we assume the expression is "simple", meaning that the
135 * property involved is a role name or the inverse of a role name.
136 * This assumption will be lifted when we will deal with the
137 * normalization of the input ontology.
138 *
139 * @todo the "filler" of this OWL expression is currently ignored. We
140 * need to find a way (if any) to handle
141 * [[org.semanticweb.owlapi.model.OWLDataRange OWLDataRange]]
142 * in RDFox.
143 */
144 override def visit(expr: OWLDataSomeValuesFrom): RDFoxRuleShards = {
145 val y = RSAOntology.genFreshVariable()
146 val prop = expr.getProperty()
147 // Computes the result of rule skolemization. Depending on the used
148 // technique it might involve the introduction of additional atoms,
149 // and/or fresh constants and variables.
150 val (head, body, term1) = skolem match {
151 case NoSkolem => (List(), List(), y)
152 case c: Constant => (List(), List(), c.iri)
153 case s: Standard => {
154 (
155 List(),
156 List(
157 BindAtom.create(FunctionCall.create("SKOLEM", s.literal, term), y)
158 ),
159 y
160 )
161 }
162 }
163 val propertyVisitor = new RDFoxPropertyExprConverter(term, term1, suffix)
164 val propertyResult = expr.getProperty.accept(propertyVisitor)
165 RDFoxRuleShards(head ::: propertyResult, body)
166 }
167
168 // OWLObjectMaxCardinality
169 override def visit(expr: OWLObjectMaxCardinality): RDFoxRuleShards = {
170 val vars =
171 List(RSAOntology.genFreshVariable(), RSAOntology.genFreshVariable())
172 val classResult = RDFoxClassExprConverter.merge(
173 vars
174 .map(new RDFoxClassExprConverter(_, unsafe, skolem, suffix))
175 .map(expr.getFiller.accept(_))
176 )
177 val propertyResult =
178 vars
179 .map(new RDFoxPropertyExprConverter(term, _, suffix))
180 .map(expr.getProperty.accept(_))
181 .flatten
182 RDFoxRuleShards(
183 List(TupleTableAtom.rdf(vars(0), IRI.SAME_AS, vars(1))),
184 classResult.res ++ propertyResult
185 )
186 }
187
188 def doDefault(expr: OWLClassExpression): RDFoxRuleShards =
189 RDFoxRuleShards(List(), List())
190
191} // class RDFoxClassExprConverter
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxConverter.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxConverter.scala
index b4f5adb..845ec1f 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxConverter.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxConverter.scala
@@ -40,7 +40,7 @@ import tech.oxfordsemantic.jrdfox.logic.datalog.{
40import tech.oxfordsemantic.jrdfox.logic.expression.{Term, IRI, FunctionCall} 40import tech.oxfordsemantic.jrdfox.logic.expression.{Term, IRI, FunctionCall}
41import uk.ac.ox.cs.rsacomb.RSAOntology 41import uk.ac.ox.cs.rsacomb.RSAOntology
42import uk.ac.ox.cs.rsacomb.suffix.{Empty, Inverse, RSASuffix} 42import uk.ac.ox.cs.rsacomb.suffix.{Empty, Inverse, RSASuffix}
43import uk.ac.ox.cs.rsacomb.util.RSA 43import uk.ac.ox.cs.rsacomb.util.{RSA, RDFoxUtil}
44 44
45/** Horn-ALCHOIQ to RDFox axiom converter. 45/** Horn-ALCHOIQ to RDFox axiom converter.
46 * 46 *
@@ -328,10 +328,7 @@ trait RDFoxConverter {
328 val (bind, term1) = skolem match { 328 val (bind, term1) = skolem match {
329 case NoSkolem => (None, varX) 329 case NoSkolem => (None, varX)
330 case c: Constant => (None, c.iri) 330 case c: Constant => (None, c.iri)
331 case s: Standard => { 331 case s: Standard => (Some(RDFoxUtil.skolem(s.name, term, varX)), varX)
332 val func = FunctionCall.create("SKOLEM", s.literal, term)
333 (Some(BindAtom.create(func, varX)), varX)
334 }
335 } 332 }
336 val (res, ext) = convert(cls, term1, unsafe, skolem, suffix) 333 val (res, ext) = convert(cls, term1, unsafe, skolem, suffix)
337 val prop = convert(role, term, term1, suffix) 334 val prop = convert(role, term, term1, suffix)
@@ -359,10 +356,7 @@ trait RDFoxConverter {
359 val (bind, term1) = skolem match { 356 val (bind, term1) = skolem match {
360 case NoSkolem => (None, varX) 357 case NoSkolem => (None, varX)
361 case c: Constant => (None, c.iri) 358 case c: Constant => (None, c.iri)
362 case s: Standard => { 359 case s: Standard => (Some(RDFoxUtil.skolem(s.name, term, varX)), varX)
363 val func = FunctionCall.create("SKOLEM", s.literal, term)
364 (Some(BindAtom.create(func, varX)), varX)
365 }
366 } 360 }
367 val prop = convert(role, term, term1, suffix) 361 val prop = convert(role, term, term1, suffix)
368 (List(prop), bind.toList) 362 (List(prop), bind.toList)
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala
deleted file mode 100644
index 46a70fa..0000000
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala
+++ /dev/null
@@ -1,45 +0,0 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import org.semanticweb.owlapi.model.{
4 OWLAnnotationProperty,
5 OWLDataProperty,
6 OWLObjectInverseOf,
7 OWLObjectProperty,
8 OWLPropertyExpression
9}
10import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx
11
12import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom
13import tech.oxfordsemantic.jrdfox.logic.expression.{Term, IRI, Literal}
14
15import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Inverse}
16
17class RDFoxPropertyExprConverter(
18 term1: Term,
19 term2: Term,
20 suffix: RSASuffix
21) extends OWLPropertyExpressionVisitorEx[List[TupleTableAtom]] {
22
23 // Automatically converts OWLAPI types into RDFox equivalent types.
24 import uk.ac.ox.cs.rsacomb.implicits.RDFox._
25
26 override def visit(expr: OWLObjectProperty): List[TupleTableAtom] = {
27 val base = expr.getIRI.getIRIString
28 val pred = IRI.create(base :: suffix)
29 List(TupleTableAtom.rdf(term1, pred, term2))
30 }
31
32 override def visit(expr: OWLDataProperty): List[TupleTableAtom] = {
33 val base = expr.getIRI.getIRIString
34 val pred = IRI.create(base :: suffix)
35 List(TupleTableAtom.rdf(term1, pred, term2))
36 }
37
38 override def visit(expr: OWLObjectInverseOf): List[TupleTableAtom] = {
39 val visitor = new RDFoxPropertyExprConverter(term1, term2, suffix + Inverse)
40 expr.getInverse.accept(visitor)
41 }
42
43 def doDefault(expr: OWLPropertyExpression): List[TupleTableAtom] = List()
44
45} // class RDFoxPropertyExprConverter
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala
index 2142ff3..426a327 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala
@@ -53,8 +53,7 @@ case object NoSkolem extends SkolemStrategy {
53case class Standard(axiom: OWLAxiom)(implicit toString: (OWLAxiom) => String) 53case class Standard(axiom: OWLAxiom)(implicit toString: (OWLAxiom) => String)
54 extends SkolemStrategy { 54 extends SkolemStrategy {
55 def dup(_axiom: OWLAxiom): Standard = copy(axiom = _axiom)(toString) 55 def dup(_axiom: OWLAxiom): Standard = copy(axiom = _axiom)(toString)
56 lazy val literal = 56 lazy val name = s"f_${toString(axiom)}"
57 Literal.create(s"f_${toString(axiom)}", Datatype.XSD_STRING)
58} 57}
59 58
60/** Constant skolemization 59/** Constant skolemization
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala
index 615722b..9b04f0e 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/RSAAtom.scala
@@ -1,17 +1,17 @@
1package uk.ac.ox.cs.rsacomb.implicits 1package uk.ac.ox.cs.rsacomb.implicits
2 2
3import tech.oxfordsemantic.jrdfox.logic.Datatype 3import tech.oxfordsemantic.jrdfox.logic.Datatype
4import tech.oxfordsemantic.jrdfox.logic.expression.{Literal, FunctionCall} 4import tech.oxfordsemantic.jrdfox.logic.expression.{Literal, FunctionCall, Term}
5import tech.oxfordsemantic.jrdfox.logic.datalog.{ 5import tech.oxfordsemantic.jrdfox.logic.datalog.{
6 BindAtom, 6 BindAtom,
7 TupleTableAtom, 7 TupleTableAtom,
8 TupleTableName 8 TupleTableName
9} 9}
10import tech.oxfordsemantic.jrdfox.logic.expression.{IRI} 10import tech.oxfordsemantic.jrdfox.logic.expression.{IRI}
11import scala.collection.JavaConverters._
12 11
13import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Nth}
14import uk.ac.ox.cs.rsacomb.RSAOntology 12import uk.ac.ox.cs.rsacomb.RSAOntology
13import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Nth}
14import uk.ac.ox.cs.rsacomb.util.RDFoxUtil
15 15
16/* Is this the best way to determine if an atom is an RDF triple? 16/* Is this the best way to determine if an atom is an RDF triple?
17 * Note that we can't use `getNumberOfArguments()` because is not 17 * Note that we can't use `getNumberOfArguments()` because is not
@@ -24,7 +24,7 @@ import uk.ac.ox.cs.rsacomb.RSAOntology
24 * This is probably because `Atom.rdf(...) is implemented as: 24 * This is probably because `Atom.rdf(...) is implemented as:
25 * ```scala 25 * ```scala
26 * def rdf(term1: Term, term2: Term, term3: Term): Atom = 26 * def rdf(term1: Term, term2: Term, term3: Term): Atom =
27 * Atom.create(TupleTableName.create("internal:triple"), term1, term2, term3) 27 * Atom.create(TupleTableName.create("rdfox:DefaultTriples"), term1, term2, term3)
28 * ``` 28 * ```
29 */ 29 */
30 30
@@ -33,10 +33,14 @@ object RSAAtom {
33 implicit class RSAAtom(val atom: TupleTableAtom) { 33 implicit class RSAAtom(val atom: TupleTableAtom) {
34 34
35 import RDFox._ 35 import RDFox._
36 import JavaCollections._
36 37
37 val name: String = atom.getTupleTableName.getName 38 val name: String = atom.getTupleTableName.getName
38 39
39 val isRDF: Boolean = name == "internal:triple" 40 val args: List[Term] = atom.getArguments
41
42 val isRDF: Boolean =
43 name == "http://oxfordsemantic.tech/RDFox#DefaultTriples"
40 44
41 val isClassAssertion: Boolean = { 45 val isClassAssertion: Boolean = {
42 isRDF && { 46 isRDF && {
@@ -70,19 +74,16 @@ object RSAAtom {
70 TupleTableAtom.create(ttname, atom.getArguments()) 74 TupleTableAtom.create(ttname, atom.getArguments())
71 } 75 }
72 76
73 lazy val reified: (Option[BindAtom], List[TupleTableAtom]) = 77 lazy val reified: (Option[TupleTableAtom], List[TupleTableAtom]) =
74 if (isRDF) { 78 if (isRDF) {
75 (None, List(atom)) 79 (None, List(atom))
76 } else { 80 } else {
77 val bvar = RSAOntology.genFreshVariable() 81 val varS = RSAOntology.genFreshVariable()
78 val str = Literal.create(name, Datatype.XSD_STRING) 82 val skolem = RDFoxUtil.skolem(name, (args :+ varS): _*)
79 val args = atom.getArguments.asScala.toList 83 val atom = TupleTableAtom.rdf(varS, IRI.RDF_TYPE, name)
80 val skolem = FunctionCall.create("SKOLEM", str :: args: _*)
81 val bind = BindAtom.create(skolem, bvar)
82 val atoms = args.zipWithIndex 84 val atoms = args.zipWithIndex
83 .map { case (t, i) => TupleTableAtom.rdf(bvar, name :: Nth(i), t) } 85 .map { case (a, i) => TupleTableAtom.rdf(varS, name :: Nth(i), a) }
84 (Some(bind), atoms) 86 (Some(skolem), atom :: atoms)
85 } 87 }
86 } 88 }
87
88} 89}
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
index 76f720c..d072e48 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala
@@ -1,7 +1,6 @@
1package uk.ac.ox.cs.rsacomb.util 1package uk.ac.ox.cs.rsacomb.util
2 2
3import java.io.File 3import java.io.{OutputStream, File, StringReader}
4import java.io.StringReader
5import tech.oxfordsemantic.jrdfox.Prefixes 4import tech.oxfordsemantic.jrdfox.Prefixes
6import tech.oxfordsemantic.jrdfox.client.{ 5import tech.oxfordsemantic.jrdfox.client.{
7 ComponentInfo, 6 ComponentInfo,
@@ -11,6 +10,7 @@ import tech.oxfordsemantic.jrdfox.client.{
11 UpdateType 10 UpdateType
12} 11}
13import tech.oxfordsemantic.jrdfox.formats.SPARQLParser 12import tech.oxfordsemantic.jrdfox.formats.SPARQLParser
13import tech.oxfordsemantic.jrdfox.logic.Datatype
14import tech.oxfordsemantic.jrdfox.logic.datalog.{ 14import tech.oxfordsemantic.jrdfox.logic.datalog.{
15 Rule, 15 Rule,
16 BodyFormula, 16 BodyFormula,
@@ -18,7 +18,12 @@ import tech.oxfordsemantic.jrdfox.logic.datalog.{
18 TupleTableAtom, 18 TupleTableAtom,
19 TupleTableName 19 TupleTableName
20} 20}
21import tech.oxfordsemantic.jrdfox.logic.expression.{Resource} 21import tech.oxfordsemantic.jrdfox.logic.expression.{
22 Literal,
23 Resource,
24 Variable,
25 Term
26}
22import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery 27import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery
23import uk.ac.ox.cs.rsacomb.suffix.Nth 28import uk.ac.ox.cs.rsacomb.suffix.Nth
24import uk.ac.ox.cs.rsacomb.util.Logger 29import uk.ac.ox.cs.rsacomb.util.Logger
@@ -69,6 +74,13 @@ object RDFoxUtil {
69 (server, data) 74 (server, data)
70 } 75 }
71 76
77 /** Create a built-in `rdfox:SKOLEM` TupleTableAtom. */
78 def skolem(name: String, terms: Term*): TupleTableAtom =
79 TupleTableAtom.create(
80 TupleTableName.SKOLEM,
81 (Literal.create(name, Datatype.XSD_STRING) +: terms): _*
82 )
83
72 /** Prints statistics from RDFox datastore. 84 /** Prints statistics from RDFox datastore.
73 * 85 *
74 * Prints something only when Logger level is set to DEBUG or more. 86 * Prints something only when Logger level is set to DEBUG or more.
@@ -127,6 +139,26 @@ object RDFoxUtil {
127 query 139 query
128 } 140 }
129 141
142 /** Export data in `text/turtle`.
143 *
144 * @param data datastore connection from which to export data.
145 * @param rules output stream for rules
146 * @param facts output stream for facts
147 */
148 def export(
149 data: DataStoreConnection,
150 rules: OutputStream,
151 facts: OutputStream
152 ): Unit = {
153 data.exportData(Prefixes.s_emptyPrefixes, facts, "text/turtle", RDFoxOpts())
154 data.exportData(
155 Prefixes.s_emptyPrefixes,
156 rules,
157 "application/x.datalog",
158 RDFoxOpts()
159 )
160 }
161
130 /** Parse a SELECT query from a string in SPARQL format. 162 /** Parse a SELECT query from a string in SPARQL format.
131 * 163 *
132 * @param query the string containing the SPARQL query 164 * @param query the string containing the SPARQL query
@@ -218,7 +250,7 @@ object RDFoxUtil {
218 .map(i => s"?S rsa:${pred :: Nth(i)} ?X$i .") 250 .map(i => s"?S rsa:${pred :: Nth(i)} ?X$i .")
219 .mkString("WHERE {\n", "\n", "\n}") 251 .mkString("WHERE {\n", "\n", "\n}")
220 } else { 252 } else {
221 s"ASK { ?X a rsa:${pred :: Nth(0)} }" 253 s"ASK { ?X a rsa:$pred }"
222 } 254 }
223 } 255 }
224 256
@@ -231,11 +263,11 @@ object RDFoxUtil {
231 * built-in `SKOLEM` funtion of RDFox. 263 * built-in `SKOLEM` funtion of RDFox.
232 */ 264 */
233 def reify(rule: Rule): Rule = { 265 def reify(rule: Rule): Rule = {
234 val (bs, as) = rule.getHead.map(_.reified).unzip 266 val (sk, as) = rule.getHead.map(_.reified).unzip
235 val head: List[TupleTableAtom] = as.flatten 267 val head: List[TupleTableAtom] = as.flatten
236 val bind: List[BodyFormula] = bs.flatten 268 val skolem: List[BodyFormula] = sk.flatten
237 val body: List[BodyFormula] = rule.getBody.map(reify).flatten 269 val body: List[BodyFormula] = rule.getBody.map(reify).flatten
238 Rule.create(head, bind ::: body) 270 Rule.create(head, skolem ::: body)
239 } 271 }
240 272
241 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]]. 273 /** Reify a [[tech.oxfordsemantic.jrdfox.logic.datalog.BodyFormula BodyFormula]].
@@ -250,15 +282,16 @@ object RDFoxUtil {
250 formula match { 282 formula match {
251 case atom: TupleTableAtom => atom.reified._2 283 case atom: TupleTableAtom => atom.reified._2
252 case neg: Negation => { 284 case neg: Negation => {
253 val (bs, as) = neg.getNegatedAtoms 285 val (sk, as) = neg.getNegatedAtoms
254 .map({ 286 .map({
255 case a: TupleTableAtom => a.reified 287 case a: TupleTableAtom => a.reified
256 case a => (None, List(a)) 288 case a => (None, List(a))
257 }) 289 })
258 .unzip 290 .unzip
259 val bind = bs.flatten.map(_.getBoundVariable) 291 val skolem =
292 sk.flatten.map(_.getArguments.last).collect { case v: Variable => v }
260 val atoms = as.flatten 293 val atoms = as.flatten
261 List(Negation.create(bind, atoms)) 294 List(Negation.create(skolem, atoms))
262 } 295 }
263 case other => List(other) 296 case other => List(other)
264 } 297 }