diff options
author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-18 19:13:25 +0000 |
---|---|---|
committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-18 19:13:25 +0000 |
commit | 1efc189e90240c162b54cbc50362b46786643dad (patch) | |
tree | 9beabe0a2af7ba1674aea0060787782aa72e8a83 /src/main/scala/uk/ac/ox/cs/rsacomb/converter | |
parent | a45aeff72b82bbc9a52f10929bf15b414c868525 (diff) | |
download | RSAComb-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')
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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb.converter | ||
2 | |||
3 | import org.semanticweb.owlapi.model.{ | ||
4 | OWLAxiom, | ||
5 | OWLSubClassOfAxiom, | ||
6 | OWLEquivalentClassesAxiom, | ||
7 | OWLObjectPropertyExpression | ||
8 | } | ||
9 | import org.semanticweb.owlapi.model.OWLAxiomVisitorEx | ||
10 | |||
11 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
12 | Rule, | ||
13 | BodyFormula, | ||
14 | TupleTableAtom, | ||
15 | TupleTableName | ||
16 | } | ||
17 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
18 | Term, | ||
19 | IRI, | ||
20 | Variable, | ||
21 | Literal | ||
22 | } | ||
23 | |||
24 | import scala.collection.JavaConverters._ | ||
25 | |||
26 | import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom | ||
27 | import org.semanticweb.owlapi.model.OWLObjectProperty | ||
28 | import org.semanticweb.owlapi.model.OWLClassAssertionAxiom | ||
29 | |||
30 | import uk.ac.ox.cs.rsacomb.RSAOntology | ||
31 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty} | ||
32 | |||
33 | object 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 | |||
45 | class 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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb.converter | ||
2 | |||
3 | import scala.collection.JavaConverters._ | ||
4 | import java.util.stream.{Stream, Collectors} | ||
5 | |||
6 | import org.semanticweb.owlapi.model.{ | ||
7 | OWLClassExpression, | ||
8 | OWLClass, | ||
9 | OWLObjectSomeValuesFrom, | ||
10 | OWLObjectIntersectionOf, | ||
11 | OWLObjectOneOf, | ||
12 | OWLObjectMaxCardinality | ||
13 | } | ||
14 | import org.semanticweb.owlapi.model.OWLClassExpressionVisitorEx | ||
15 | import tech.oxfordsemantic.jrdfox.logic.Datatype | ||
16 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
17 | BindAtom, | ||
18 | TupleTableName, | ||
19 | TupleTableAtom | ||
20 | } | ||
21 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
22 | Term, | ||
23 | Literal, | ||
24 | Variable, | ||
25 | FunctionCall, | ||
26 | IRI | ||
27 | } | ||
28 | |||
29 | import org.semanticweb.owlapi.model.OWLObjectPropertyExpression | ||
30 | import org.semanticweb.owlapi.model.OWLObjectProperty | ||
31 | |||
32 | import uk.ac.ox.cs.rsacomb.RSAOntology | ||
33 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Empty} | ||
34 | import uk.ac.ox.cs.rsacomb.util.RSA | ||
35 | |||
36 | object 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 | |||
57 | class 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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb.converter | ||
2 | |||
3 | import org.semanticweb.owlapi.model.{OWLPropertyExpression, OWLObjectProperty} | ||
4 | import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx | ||
5 | |||
6 | import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom | ||
7 | import tech.oxfordsemantic.jrdfox.logic.expression.{Term, IRI, Literal} | ||
8 | |||
9 | import org.semanticweb.owlapi.model.OWLObjectInverseOf | ||
10 | |||
11 | import uk.ac.ox.cs.rsacomb.suffix.{RSASuffix, Inverse} | ||
12 | |||
13 | class 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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb.converter | ||
2 | |||
3 | import tech.oxfordsemantic.jrdfox.logic.datalog.{TupleTableAtom, BodyFormula} | ||
4 | |||
5 | case 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 @@ | |||
1 | package uk.ac.ox.cs.rsacomb.converter | ||
2 | |||
3 | import tech.oxfordsemantic.jrdfox.logic.Datatype | ||
4 | import tech.oxfordsemantic.jrdfox.logic.expression.{Literal, IRI} | ||
5 | |||
6 | sealed trait SkolemStrategy | ||
7 | |||
8 | object 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 | } | ||