blob: 50dc37ec0bd0cc4b7f983405a946f6605d268869 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
package rsacomb
/* Java imports */
import org.semanticweb.owlapi.model.{
OWLAxiom,
OWLSubClassOfAxiom,
OWLEquivalentClassesAxiom
}
import org.semanticweb.owlapi.model.{
OWLObjectPropertyExpression,
OWLClass,
OWLClassExpression,
OWLObjectSomeValuesFrom,
OWLObjectMaxCardinality
}
import org.semanticweb.owlapi.model.ClassExpressionType
import org.semanticweb.owlapi.model.{
OWLAxiomVisitorEx,
OWLClassExpressionVisitorEx
}
/* Wrapper trait for the implicit class `RSAAxiom`.
*/
trait RSAAxiom {
/* Identifies some of the axiom types in a Horn-ALCHOIQ ontology
* in normal form. Refer to the paper for more details on the
* chosen names.
*/
private sealed trait RSAAxiomType
private object RSAAxiomType {
case object T3 extends RSAAxiomType // ∃R.A ⊑ B
case object T3top extends RSAAxiomType // ∃R.⊤ ⊑ B
case object T4 extends RSAAxiomType // A ⊑ ≤1R.B
case object T5 extends RSAAxiomType // A ⊑ ∃R.B
}
/* Implements additional features on top of `OWLAxiom` from
* the OWLAPI.
*/
implicit class RSAAxiom(axiom: OWLAxiom) {
/* Detecting axiom types:
*
* In order to reason about role unsafety in Horn-ALCHOIQ
* ontologies we need to detect and filter axioms by their
* "type".
*
* This is a simple implementation following the Visitor
* pattern imposed by the OWLAPI.
*/
private class RSAAxiomTypeDetector(t: RSAAxiomType)
extends OWLAxiomVisitorEx[Boolean] {
override def visit(axiom: OWLSubClassOfAxiom): Boolean = {
val sub = axiom.getSubClass().getClassExpressionType()
val sup = axiom.getSuperClass().getClassExpressionType()
t match {
case RSAAxiomType.T3top => // ∃R.⊤ ⊑ B
axiom.isT3 && axiom
.getSubClass()
.asInstanceOf[OWLObjectSomeValuesFrom]
.getFiller
.isOWLThing
case RSAAxiomType.T3 => // ∃R.A ⊑ B
sub == ClassExpressionType.OBJECT_SOME_VALUES_FROM && sup == ClassExpressionType.OWL_CLASS
case RSAAxiomType.T4 => // A ⊑ ≤1R.B
sub == ClassExpressionType.OWL_CLASS && sup == ClassExpressionType.OBJECT_MAX_CARDINALITY
case RSAAxiomType.T5 => // A ⊑ ∃R.B
sub == ClassExpressionType.OWL_CLASS && sup == ClassExpressionType.OBJECT_SOME_VALUES_FROM
}
}
override def visit(axiom: OWLEquivalentClassesAxiom): Boolean = {
// TODO
false
}
def doDefault(axiom: OWLAxiom): Boolean = false
}
private def isOfType(t: RSAAxiomType): Boolean = {
val visitor = new RSAAxiomTypeDetector(t)
axiom.accept(visitor)
}
/* Exposed methods */
def isT3top: Boolean = isOfType(RSAAxiomType.T3top)
def isT3: Boolean = isOfType(RSAAxiomType.T3)
def isT4: Boolean = isOfType(RSAAxiomType.T4)
def isT5: Boolean = isOfType(RSAAxiomType.T5)
/* Extracting ObjectPropertyExpressions from axioms
*
* This extracts all ObjectPropertyExpressions from a given
* axiom. While the implementation is generic we use it on axioms
* of specific types (see above).
*
* NOTE: it is not possible to use the `objectPropertyInSignature`
* method of `OWLAxiom` because it returns all "role names" involved
* in the signature of an axiom. In particular we won't get the inverse
* of a role if this appears in the axiom (but we will get the role
* itself instead).
*/
private class RSAAxiomRoleExtractor()
extends OWLAxiomVisitorEx[List[OWLObjectPropertyExpression]] {
private class RSAExprRoleExtractor()
extends OWLClassExpressionVisitorEx[
List[OWLObjectPropertyExpression]
] {
override def visit(
expr: OWLObjectSomeValuesFrom
): List[OWLObjectPropertyExpression] =
List(expr.getProperty)
override def visit(
expr: OWLObjectMaxCardinality
): List[OWLObjectPropertyExpression] =
List(expr.getProperty)
/* NOTE: this instance of `visit` for `OWLClass` shouldn't be necessary. However
* if missing, the code throws a `NullPointerException`. It seems like, for some
* reason, `OWLClass` is not really a subinterface of `OWLClassExpression`, as
* stated in the JavaDocs.
*/
override def visit(expr: OWLClass): List[OWLObjectPropertyExpression] =
List()
def doDefault(
expr: OWLClassExpression
): List[OWLObjectPropertyExpression] =
List()
}
override def visit(
axiom: OWLSubClassOfAxiom
): List[OWLObjectPropertyExpression] = {
val visitor = new RSAExprRoleExtractor()
val sub = axiom.getSubClass.accept(visitor)
val sup = axiom.getSuperClass.accept(visitor)
sub ++ sup
}
override def visit(
axiom: OWLEquivalentClassesAxiom
): List[OWLObjectPropertyExpression] = {
// TODO
List()
}
def doDefault(axiom: OWLAxiom): List[OWLObjectPropertyExpression] = List()
}
/* Exposed methods */
def objectPropertyExpressionsInSignature
: List[OWLObjectPropertyExpression] = {
val visitor = new RSAAxiomRoleExtractor()
axiom.accept(visitor)
}
}
} // trait RSAAxiom
|