blob: 474d31617a7b2b583cb329d3a47f2591b13d7785 (
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
|
package rsacomb
/* Java imports */
import java.util.stream.{Collectors,Stream}
import org.semanticweb.owlapi.model.OWLOntology
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression
import org.semanticweb.owlapi.model.parameters.Imports
import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory
import tech.oxfordsemantic.jrdfox.logic.Variable
/* Scala imports */
import scala.collection.JavaConverters._
/* Debug only */
import org.semanticweb.owlapi.dlsyntax.renderer.DLSyntaxObjectRenderer
/* Wrapper trait for the implicit class `RSAOntology`.
*/
trait RSAOntology {
/* Implements additional features to reason about RSA ontologies
* on top of `OWLOntology` from the OWLAPI.
*/
implicit class RSAOntology(ontology: OWLOntology) extends RSAAxiom {
def isRSA: Boolean = {
/* TODO: Steps for RSA check
* 1) convert ontology axioms into LP rules
* 2) call RDFox on the onto and compute materialization
* 3) build graph from E(x,y) facts
* 4) check if the graph is tree-like
* ideally this annotates the graph with info about the reasons
* why the ontology might not be RSA. This could help a second
* step of approximation of an Horn-ALCHOIQ to RSA
*/
val tbox =
Stream.concat(ontology.tboxAxioms(Imports.INCLUDED), ontology.rboxAxioms(Imports.INCLUDED))
.collect(Collectors.toList()).asScala
val unsafe = ontology.getUnsafeRoles
/* DEBUG: print rules in DL syntax */
val renderer = new DLSyntaxObjectRenderer()
println("\nDL rules:")
tbox.foreach(x => println(renderer.render(x)))
/* Ontology convertion into LP rules */
println("\nLP rules:")
for {
axiom <- tbox
visitor = new RDFoxAxiomConverter(Variable.create("x"), SkolemStrategy.ConstantRSA(axiom.toString), unsafe)
rule <- axiom.accept(visitor)
} yield println(rule)
/* DEBUG */
true
}
def getUnsafeRoles: List[OWLObjectPropertyExpression] = {
// The reasoner is used to check unsafety condition for the ontology roles
val factory = new StructuralReasonerFactory()
val reasoner = factory.createReasoner(ontology)
val tbox = ontology.tboxAxioms(Imports.INCLUDED).collect(Collectors.toSet()).asScala
/* DEBUG: print rules in DL syntax */
//val renderer = new DLSyntaxObjectRenderer()
/* Checking for (1) unsafety condition:
*
* For all roles p1 appearing in an axiom of type T5, p1 is unsafe
* if there exists a role p2 (different from top) appearing in an axiom
* of type T3 and p1 is a subproperty of the inverse of p2.
*
* TODO: We are not checking whether the class expression on the right in T3
* is top. For now we can assume it is always the case.
*/
val unsafe = for {
ax1 <- tbox
if ax1.isT5
p1 <- ax1.objectPropertyExpressionsInSignature
sup = p1.getInverseProperty +: reasoner.superObjectProperties(p1).map(_.getInverseProperty).collect(Collectors.toList()).asScala
ax2 <- tbox
if ax2.isT3
p2 <- ax2.objectPropertyExpressionsInSignature
if sup.contains(p2)
} yield p1
/* Checking for (2) unsafety condition:
*
* TODO
*/
/* TODO: We should be able to avoid this last conversion to List.
* Maybe we should just move everything to Sets instead of Lists, since
* they have a more straightforward conversion from Java collections.
*/
unsafe.toList
}
} // implicit class RSAOntology
} // trait RSAOntology
|