aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/uk/ac/ox/cs/rsacomb/converter
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-18 19:13:25 +0000
committerFederico Igne <federico.igne@cs.ox.ac.uk>2020-11-18 19:13:25 +0000
commit1efc189e90240c162b54cbc50362b46786643dad (patch)
tree9beabe0a2af7ba1674aea0060787782aa72e8a83 /src/main/scala/uk/ac/ox/cs/rsacomb/converter
parenta45aeff72b82bbc9a52f10929bf15b414c868525 (diff)
downloadRSAComb-1efc189e90240c162b54cbc50362b46786643dad.tar.gz
RSAComb-1efc189e90240c162b54cbc50362b46786643dad.zip
Reorganize project with Java-like folder structure
Diffstat (limited to 'src/main/scala/uk/ac/ox/cs/rsacomb/converter')
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala105
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala160
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala35
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxRuleShards.scala5
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala78
5 files changed, 383 insertions, 0 deletions
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
new file mode 100644
index 0000000..a8d1ffd
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxAxiomConverter.scala
@@ -0,0 +1,105 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import org.semanticweb.owlapi.model.{
4 OWLAxiom,
5 OWLSubClassOfAxiom,
6 OWLEquivalentClassesAxiom,
7 OWLObjectPropertyExpression
8}
9import org.semanticweb.owlapi.model.OWLAxiomVisitorEx
10
11import tech.oxfordsemantic.jrdfox.logic.datalog.{
12 Rule,
13 BodyFormula,
14 TupleTableAtom,
15 TupleTableName
16}
17import tech.oxfordsemantic.jrdfox.logic.expression.{
18 Term,
19 IRI,
20 Variable,
21 Literal
22}
23
24import scala.collection.JavaConverters._
25
26import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom
27import org.semanticweb.owlapi.model.OWLObjectProperty
28import org.semanticweb.owlapi.model.OWLClassAssertionAxiom
29
30import uk.ac.ox.cs.rsacomb.RSAOntology
31import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty}
32
33object RDFoxAxiomConverter {
34
35 def apply(
36 term: Term,
37 unsafe: List[OWLObjectPropertyExpression],
38 skolem: SkolemStrategy = SkolemStrategy.None,
39 suffix: RSASuffix = Empty
40 ): RDFoxAxiomConverter =
41 new RDFoxAxiomConverter(term, unsafe, skolem, suffix)
42
43} // object RDFoxAxiomConverter
44
45class RDFoxAxiomConverter(
46 term: Term,
47 unsafe: List[OWLObjectPropertyExpression],
48 skolem: SkolemStrategy,
49 suffix: RSASuffix
50) extends OWLAxiomVisitorEx[List[Rule]] {
51
52 override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = {
53 // Skolemization is needed only for the head of an axiom
54 val subVisitor =
55 new RDFoxClassExprConverter(term, unsafe, SkolemStrategy.None, suffix)
56 val superVisitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
57 // Each visitor returns a `RDFoxRuleShards`, a tuple (res,ext):
58 // - the `res` List is a list of atoms resulting from the conversion
59 // of the axiom.
60 // - for some Class Expressions appearing in the head of an Axiom,
61 // the conversion might produce atoms that need to appear in the
62 // body (and not in the head) of the rule. This is what the `ext`
63 // List is for.
64 val sub = axiom.getSubClass.accept(subVisitor)
65 val sup = axiom.getSuperClass.accept(superVisitor)
66 val head = sup.res.asJava
67 val body = (sub.res ++ sup.ext).asJava
68 List(Rule.create(head, body))
69 }
70
71 override def visit(axiom: OWLEquivalentClassesAxiom): List[Rule] = {
72 for {
73 axiom1 <- axiom.asPairwiseAxioms.asScala.toList
74 axiom2 <- axiom1.asOWLSubClassOfAxioms.asScala.toList
75 rule <- axiom2.accept(this)
76 } yield rule
77 }
78
79 override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = {
80 val term1 = RSAOntology.genFreshVariable()
81 val subVisitor =
82 new RDFoxPropertyExprConverter(term, term1, suffix)
83 val superVisitor = new RDFoxPropertyExprConverter(term, term1, suffix)
84 val body: List[BodyFormula] = axiom.getSubProperty.accept(subVisitor)
85 val head: List[TupleTableAtom] = axiom.getSuperProperty.accept(superVisitor)
86 List(Rule.create(head.asJava, body.asJava))
87 }
88
89 override def visit(axiom: OWLClassAssertionAxiom): List[Rule] = {
90 val ind = axiom.getIndividual
91 if (ind.isNamed) {
92 val term = IRI.create(ind.asOWLNamedIndividual().getIRI.getIRIString)
93 val cls = axiom.getClassExpression
94 val visitor =
95 new RDFoxClassExprConverter(term, unsafe, SkolemStrategy.None, suffix)
96 val shard = cls.accept(visitor)
97 List(Rule.create(shard.res.asJava, shard.ext.asJava))
98 } else {
99 List()
100 }
101 }
102
103 def doDefault(axiom: OWLAxiom): List[Rule] = List()
104
105} // 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
new file mode 100644
index 0000000..c151c9a
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxClassExprConverter.scala
@@ -0,0 +1,160 @@
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 OWLObjectIntersectionOf,
11 OWLObjectOneOf,
12 OWLObjectMaxCardinality
13}
14import org.semanticweb.owlapi.model.OWLClassExpressionVisitorEx
15import tech.oxfordsemantic.jrdfox.logic.Datatype
16import tech.oxfordsemantic.jrdfox.logic.datalog.{
17 BindAtom,
18 TupleTableName,
19 TupleTableAtom
20}
21import tech.oxfordsemantic.jrdfox.logic.expression.{
22 Term,
23 Literal,
24 Variable,
25 FunctionCall,
26 IRI
27}
28
29import org.semanticweb.owlapi.model.OWLObjectPropertyExpression
30import org.semanticweb.owlapi.model.OWLObjectProperty
31
32import uk.ac.ox.cs.rsacomb.RSAOntology
33import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty}
34import uk.ac.ox.cs.rsacomb.util.RSA
35
36object RDFoxClassExprConverter {
37
38 def apply(
39 term: Term,
40 unsafe: List[OWLObjectPropertyExpression] = List(),
41 skolem: SkolemStrategy = SkolemStrategy.None,
42 suffix: RSASuffix = Empty
43 ): RDFoxClassExprConverter =
44 new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
45
46 def merge(rules: List[RDFoxRuleShards]): RDFoxRuleShards = {
47 rules.foldLeft(RDFoxRuleShards(List(), List())) { (r1, r2) =>
48 RDFoxRuleShards(
49 r1.res ++ r2.res,
50 r1.ext ++ r2.ext
51 )
52 }
53 }
54
55} // object RDFoxClassExprConverter
56
57class RDFoxClassExprConverter(
58 term: Term,
59 unsafe: List[OWLObjectPropertyExpression],
60 skolem: SkolemStrategy,
61 suffix: RSASuffix
62) extends OWLClassExpressionVisitorEx[RDFoxRuleShards] {
63
64 import uk.ac.ox.cs.rsacomb.implicits.RDFox._
65
66 // OWLClass
67 override def visit(expr: OWLClass): RDFoxRuleShards = {
68 val iri: IRI = if (expr.isTopEntity()) IRI.THING else expr.getIRI()
69 val atom = List(TupleTableAtom.rdf(term, IRI.RDF_TYPE, iri))
70 RDFoxRuleShards(atom, List())
71 }
72
73 // OWLObjectIntersectionOf
74 override def visit(expr: OWLObjectIntersectionOf): RDFoxRuleShards = {
75 val visitor = new RDFoxClassExprConverter(term, unsafe, skolem, suffix)
76 // TODO: maybe using `flatMap` instead of `merge` + `map` works as well
77 RDFoxClassExprConverter.merge(
78 expr.asConjunctSet.asScala.toList
79 .map((e: OWLClassExpression) => e.accept(visitor))
80 )
81 }
82
83 // OWLObjectOneOf
84 override def visit(expr: OWLObjectOneOf): RDFoxRuleShards = {
85 val visitor = RDFoxClassExprConverter(term, unsafe, skolem, suffix)
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 SkolemStrategy.None => (List(), List(), y)
110 case SkolemStrategy.Constant(c) => (List(), List(), c)
111 case SkolemStrategy.ConstantRSA(c) => {
112 if (unsafe.contains(prop))
113 (List(RSA.PE(term, c), RSA.U(c)), List(), c)
114 else
115 (List(), List(), c)
116 }
117 case SkolemStrategy.Standard(f) => {
118 (
119 List(),
120 List(BindAtom.create(FunctionCall.create("SKOLEM", f, term), y)),
121 y
122 )
123 }
124 }
125 val classVisitor =
126 new RDFoxClassExprConverter(term1, unsafe, skolem, suffix)
127 val classResult = expr.getFiller.accept(classVisitor)
128 val propertyVisitor = new RDFoxPropertyExprConverter(term, term1, suffix)
129 val propertyResult = expr.getProperty.accept(propertyVisitor)
130 RDFoxRuleShards(
131 classResult.res ++ propertyResult ++ head,
132 classResult.ext ++ body
133 )
134 }
135
136 // OWLObjectMaxCardinality
137 override def visit(expr: OWLObjectMaxCardinality): RDFoxRuleShards = {
138 // TODO: again, no hardcoded variables
139 val vars =
140 List(RSAOntology.genFreshVariable(), RSAOntology.genFreshVariable())
141 val classResult = RDFoxClassExprConverter.merge(
142 vars
143 .map(new RDFoxClassExprConverter(_, unsafe, skolem, suffix))
144 .map(expr.getFiller.accept(_))
145 )
146 val propertyResult =
147 vars
148 .map(new RDFoxPropertyExprConverter(term, _, suffix))
149 .map(expr.getProperty.accept(_))
150 .flatten
151 RDFoxRuleShards(
152 List(TupleTableAtom.rdf(vars(0), IRI.SAME_AS, vars(1))),
153 classResult.res ++ propertyResult
154 )
155 }
156
157 def doDefault(expr: OWLClassExpression): RDFoxRuleShards =
158 RDFoxRuleShards(List(), List())
159
160} // class RDFoxClassExprConverter
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
new file mode 100644
index 0000000..94c7887
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxPropertyExprConverter.scala
@@ -0,0 +1,35 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import org.semanticweb.owlapi.model.{OWLPropertyExpression, OWLObjectProperty}
4import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx
5
6import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom
7import tech.oxfordsemantic.jrdfox.logic.expression.{Term, IRI, Literal}
8
9import org.semanticweb.owlapi.model.OWLObjectInverseOf
10
11import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Inverse}
12
13class RDFoxPropertyExprConverter(
14 term1: Term,
15 term2: Term,
16 suffix: RSASuffix
17) extends OWLPropertyExpressionVisitorEx[List[TupleTableAtom]] {
18
19 // Automatically converts OWLAPI types into RDFox equivalent types.
20 import uk.ac.ox.cs.rsacomb.implicits.RDFox._
21
22 override def visit(expr: OWLObjectProperty): List[TupleTableAtom] = {
23 val base = expr.getIRI.getIRIString
24 val pred = IRI.create(base :: suffix)
25 List(TupleTableAtom.rdf(term1, pred, term2))
26 }
27
28 override def visit(expr: OWLObjectInverseOf): List[TupleTableAtom] = {
29 val visitor = new RDFoxPropertyExprConverter(term1, term2, suffix + Inverse)
30 expr.getInverse.accept(visitor)
31 }
32
33 def doDefault(expr: OWLPropertyExpression): List[TupleTableAtom] = List()
34
35} // class RDFoxPropertyExprConverter
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxRuleShards.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxRuleShards.scala
new file mode 100644
index 0000000..c88cf3c
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/RDFoxRuleShards.scala
@@ -0,0 +1,5 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, BodyFormula}
4
5case class RDFoxRuleShards(res: List[TupleTableAtom], ext: List[BodyFormula])
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
new file mode 100644
index 0000000..0d72226
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/SkolemStrategy.scala
@@ -0,0 +1,78 @@
1package uk.ac.ox.cs.rsacomb.converter
2
3import tech.oxfordsemantic.jrdfox.logic.Datatype
4import tech.oxfordsemantic.jrdfox.logic.expression.{Literal, IRI}
5
6sealed trait SkolemStrategy
7
8object SkolemStrategy {
9 // TODO: might want to use something else other than `hashCode` as a
10 // function to generate a fresh function/constant
11
12 /* No skolemization at all.
13 *
14 * From
15 * ∃R.A ⊑ B
16 * to
17 * R(x,y), B(y) -> B(x)
18 */
19 case object None extends SkolemStrategy
20
21 /* Functional skolemization
22 *
23 * From
24 * A ⊑ ∃R.B
25 * to
26 * A(x) -> R(x,f(x)), B(f(x))
27 * for f, fresh function associated with the input axiom
28 *
29 * In RDFox this can represented combining the BIND operator with the
30 * SKOLEM operator as such:
31 * A(x), BIND(y, SKOLEM("f", x)) -> R(x,y), B(y)
32 * The first argument of a SKOLEM call is a literal string (ideally
33 * identifing the simulated function name).
34 *
35 * NOTE: this requirement for the SKOLEM operator is not enforced by
36 * RDFox, that will fail silently if omitted.
37 */
38 case class Standard(func: Literal) extends SkolemStrategy
39 object Standard {
40 def apply(axiom: String) =
41 new Standard(
42 Literal.create(genFunctionString(axiom), Datatype.XSD_STRING)
43 )
44 def genFunctionString(str: String) = "f_" ++ str.hashCode.toString
45 }
46
47 /* Constant skolemization
48 *
49 * From
50 * A ⊑ ∃R.B
51 * to
52 * A(y) -> R(x,c), B(c)
53 * for c, fresh constant associated with the input axiom
54 */
55 case class Constant(const: IRI) extends SkolemStrategy
56 object Constant {
57 def apply(axiom: String) =
58 new Constant(IRI.create(genConstantString(axiom)))
59 def genConstantString(str: String) = "c_" ++ str.hashCode.toString
60 }
61
62 /* (RSA) Constant skolemization
63 * This is a special skolemization option to introduce additional atoms for RSA
64 * checking algorithm.
65 *
66 * From
67 * A ⊑ ∃R.B
68 * to
69 * A(y) -> R(x,c), PE(x,c), B(c)
70 * for c, fresh constant associated with the input axiom and PE an internal predicate.
71 */
72 case class ConstantRSA(const: IRI) extends SkolemStrategy
73 object ConstantRSA {
74 def apply(axiom: String) =
75 new ConstantRSA(IRI.create(genConstantString(axiom)))
76 def genConstantString(str: String) = "c_" ++ str.hashCode.toString
77 }
78}