diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/rsacomb/CanonicalModel.scala | 292 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/Main.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RDFoxUtil.scala | 10 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RSA.scala | 11 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RSAOntology.scala | 951 | ||||
| -rw-r--r-- | src/test/scala/rsacomb/CanonicalModelSpec.scala | 22 | ||||
| -rw-r--r-- | src/test/scala/rsacomb/FilteringProgramSpecs.scala | 1 |
7 files changed, 624 insertions, 665 deletions
diff --git a/src/main/scala/rsacomb/CanonicalModel.scala b/src/main/scala/rsacomb/CanonicalModel.scala new file mode 100644 index 0000000..f7a45a7 --- /dev/null +++ b/src/main/scala/rsacomb/CanonicalModel.scala | |||
| @@ -0,0 +1,292 @@ | |||
| 1 | package rsacomb | ||
| 2 | |||
| 3 | import org.semanticweb.owlapi.model.{OWLObjectInverseOf, OWLObjectProperty} | ||
| 4 | import org.semanticweb.owlapi.model.{ | ||
| 5 | OWLClass, | ||
| 6 | // OWLObjectProperty, | ||
| 7 | OWLSubObjectPropertyOfAxiom, | ||
| 8 | // OWLObjectPropertyExpression, | ||
| 9 | OWLObjectSomeValuesFrom, | ||
| 10 | OWLSubClassOfAxiom | ||
| 11 | } | ||
| 12 | |||
| 13 | import tech.oxfordsemantic.jrdfox.logic.datalog.{ | ||
| 14 | Rule, | ||
| 15 | BodyFormula, | ||
| 16 | TupleTableAtom, | ||
| 17 | Negation | ||
| 18 | } | ||
| 19 | import tech.oxfordsemantic.jrdfox.logic.expression.{ | ||
| 20 | Term, | ||
| 21 | Variable, | ||
| 22 | // Resource, | ||
| 23 | IRI | ||
| 24 | } | ||
| 25 | |||
| 26 | import suffix.{Empty, Forward, Backward, Inverse} | ||
| 27 | |||
| 28 | class CanonicalModel(val ontology: RSAOntology) extends RSAAxiom { | ||
| 29 | |||
| 30 | // Makes working with IRIs less painful | ||
| 31 | import RDFoxUtil._ | ||
| 32 | |||
| 33 | val named: List[Rule] = | ||
| 34 | ontology.individuals.map(a => | ||
| 35 | Rule.create(TupleTableAtom.rdf(a, IRI.RDF_TYPE, RSA.Named)) | ||
| 36 | ) | ||
| 37 | |||
| 38 | val rolesAdditionalRules: List[Rule] = { | ||
| 39 | // Given a role (predicate) compute additional logic rules | ||
| 40 | def additional(pred: String): Seq[Rule] = { | ||
| 41 | val varX = Variable.create("X") | ||
| 42 | val varY = Variable.create("Y") | ||
| 43 | for ( | ||
| 44 | (hSuffix, bSuffix) <- List( | ||
| 45 | (Empty, Forward), | ||
| 46 | (Empty, Backward), | ||
| 47 | (Inverse, Forward + Inverse), | ||
| 48 | (Inverse, Backward + Inverse), | ||
| 49 | (Backward + Inverse, Forward), | ||
| 50 | (Forward + Inverse, Backward), | ||
| 51 | (Backward, Forward + Inverse), | ||
| 52 | (Forward, Backward + Inverse) | ||
| 53 | ) | ||
| 54 | ) | ||
| 55 | yield Rule.create( | ||
| 56 | TupleTableAtom.rdf(varX, pred :: hSuffix, varY), | ||
| 57 | TupleTableAtom.rdf(varX, pred :: bSuffix, varY) | ||
| 58 | ) | ||
| 59 | } | ||
| 60 | // Compute additional rules per role | ||
| 61 | ontology.roles | ||
| 62 | .collect { case prop: OWLObjectProperty => prop } | ||
| 63 | .map(_.getIRI.getIRIString) | ||
| 64 | .flatMap(additional) | ||
| 65 | } | ||
| 66 | |||
| 67 | private lazy val topAxioms: List[Rule] = { | ||
| 68 | val varX = Variable.create("X") | ||
| 69 | val varY = Variable.create("Y") | ||
| 70 | val concepts = ontology.concepts.map(c => { | ||
| 71 | Rule.create( | ||
| 72 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING), | ||
| 73 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, c.getIRI) | ||
| 74 | ) | ||
| 75 | }) | ||
| 76 | val roles = ontology.roles.map(r => { | ||
| 77 | val name = r match { | ||
| 78 | case x: OWLObjectProperty => x.getIRI.getIRIString | ||
| 79 | case x: OWLObjectInverseOf => | ||
| 80 | x.getInverse.getNamedProperty.getIRI.getIRIString :: Inverse | ||
| 81 | } | ||
| 82 | Rule.create( | ||
| 83 | List( | ||
| 84 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING), | ||
| 85 | TupleTableAtom.rdf(varY, IRI.RDF_TYPE, IRI.THING) | ||
| 86 | ), | ||
| 87 | List(TupleTableAtom.rdf(varX, name, varY)) | ||
| 88 | ) | ||
| 89 | }) | ||
| 90 | concepts ::: roles | ||
| 91 | } | ||
| 92 | |||
| 93 | private val equalityAxioms: List[Rule] = { | ||
| 94 | val varX = Variable.create("X") | ||
| 95 | val varY = Variable.create("Y") | ||
| 96 | val varZ = Variable.create("Z") | ||
| 97 | List( | ||
| 98 | Rule.create( | ||
| 99 | TupleTableAtom.rdf(varX, RSA.EquivTo, varX), | ||
| 100 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, IRI.THING) | ||
| 101 | ), | ||
| 102 | Rule.create( | ||
| 103 | TupleTableAtom.rdf(varY, RSA.EquivTo, varX), | ||
| 104 | TupleTableAtom.rdf(varX, RSA.EquivTo, varY) | ||
| 105 | ), | ||
| 106 | Rule.create( | ||
| 107 | TupleTableAtom.rdf(varX, RSA.EquivTo, varZ), | ||
| 108 | TupleTableAtom.rdf(varX, RSA.EquivTo, varY), | ||
| 109 | TupleTableAtom.rdf(varY, RSA.EquivTo, varZ) | ||
| 110 | ) | ||
| 111 | ) | ||
| 112 | } | ||
| 113 | |||
| 114 | val rules: List[Rule] = { | ||
| 115 | // Compute rules from ontology axioms | ||
| 116 | val rules = ontology.axioms.flatMap(_.accept(RuleGenerator)) | ||
| 117 | // Return full set of rules | ||
| 118 | rules ::: rolesAdditionalRules ::: topAxioms ::: equalityAxioms ::: named | ||
| 119 | } | ||
| 120 | |||
| 121 | object RuleGenerator | ||
| 122 | extends RDFoxAxiomConverter( | ||
| 123 | Variable.create("X"), | ||
| 124 | ontology.unsafeRoles, | ||
| 125 | SkolemStrategy.None, | ||
| 126 | Empty | ||
| 127 | ) { | ||
| 128 | |||
| 129 | private def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = { | ||
| 130 | val unfold = ontology.unfold(axiom).toList | ||
| 131 | // Fresh Variables | ||
| 132 | val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom)) | ||
| 133 | val varX = Variable.create("X") | ||
| 134 | // Predicates | ||
| 135 | val atomA: TupleTableAtom = { | ||
| 136 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 137 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, cls) | ||
| 138 | } | ||
| 139 | def predIN(t: Term): TupleTableAtom = { | ||
| 140 | TupleTableAtom.rdf( | ||
| 141 | t, | ||
| 142 | RSA.rsa("IN"), | ||
| 143 | RSA.rsa(unfold.hashCode.toString) | ||
| 144 | ) | ||
| 145 | } | ||
| 146 | def notIn(t: Term): Negation = Negation.create(predIN(t)) | ||
| 147 | val roleRf: TupleTableAtom = { | ||
| 148 | val visitor = | ||
| 149 | new RDFoxPropertyExprConverter(varX, v0, Forward) | ||
| 150 | axiom.getSuperClass | ||
| 151 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 152 | .getProperty | ||
| 153 | .accept(visitor) | ||
| 154 | .head | ||
| 155 | } | ||
| 156 | val atomB: TupleTableAtom = { | ||
| 157 | val cls = axiom.getSuperClass | ||
| 158 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 159 | .getFiller | ||
| 160 | .asInstanceOf[OWLClass] | ||
| 161 | .getIRI | ||
| 162 | TupleTableAtom.rdf(v0, IRI.RDF_TYPE, cls) | ||
| 163 | } | ||
| 164 | // TODO: To be consistent with the specifics of the visitor we are | ||
| 165 | // returning facts as `Rule`s with true body. While this is correct | ||
| 166 | // there is an easier way to import facts into RDFox. Are we able to | ||
| 167 | // do that? | ||
| 168 | val facts = unfold.map(x => Rule.create(predIN(x))) | ||
| 169 | val rules = List( | ||
| 170 | Rule.create(roleRf, atomA, notIn(varX)), | ||
| 171 | Rule.create(atomB, atomA, notIn(varX)) | ||
| 172 | ) | ||
| 173 | facts ++ rules | ||
| 174 | } | ||
| 175 | |||
| 176 | private def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = { | ||
| 177 | val roleR = | ||
| 178 | axiom.getSuperClass | ||
| 179 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 180 | .getProperty | ||
| 181 | if (ontology.confl(roleR) contains roleR) { | ||
| 182 | // Fresh Variables | ||
| 183 | val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom)) | ||
| 184 | val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 185 | val v2 = RSA.rsa("v2_" ++ RSA.hashed(axiom)) | ||
| 186 | // Predicates | ||
| 187 | def atomA(t: Term): TupleTableAtom = { | ||
| 188 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 189 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 190 | } | ||
| 191 | def roleRf(t1: Term, t2: Term): TupleTableAtom = { | ||
| 192 | val visitor = | ||
| 193 | new RDFoxPropertyExprConverter(t1, t2, Forward) | ||
| 194 | roleR.accept(visitor).head | ||
| 195 | } | ||
| 196 | def atomB(t: Term): TupleTableAtom = { | ||
| 197 | val cls = axiom.getSuperClass | ||
| 198 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 199 | .getFiller | ||
| 200 | .asInstanceOf[OWLClass] | ||
| 201 | .getIRI | ||
| 202 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 203 | } | ||
| 204 | //Rules | ||
| 205 | List( | ||
| 206 | Rule.create(roleRf(v0, v1), atomA(v0)), | ||
| 207 | Rule.create(atomB(v1), atomA(v0)), | ||
| 208 | Rule.create(roleRf(v1, v2), atomA(v1)), | ||
| 209 | Rule.create(atomB(v2), atomA(v1)) | ||
| 210 | ) | ||
| 211 | } else { | ||
| 212 | List() | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | private def rules3(axiom: OWLSubClassOfAxiom): List[Rule] = { | ||
| 217 | val cycle = ontology.cycle(axiom).toList | ||
| 218 | val roleR = | ||
| 219 | axiom.getSuperClass | ||
| 220 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 221 | .getProperty | ||
| 222 | // Fresh Variables | ||
| 223 | val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 224 | // Predicates | ||
| 225 | def atomA(t: Term): TupleTableAtom = { | ||
| 226 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 227 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 228 | } | ||
| 229 | def roleRf(t: Term): TupleTableAtom = { | ||
| 230 | val visitor = | ||
| 231 | new RDFoxPropertyExprConverter(t, v1, Forward) | ||
| 232 | roleR.accept(visitor).head | ||
| 233 | } | ||
| 234 | val atomB: TupleTableAtom = { | ||
| 235 | val cls = axiom.getSuperClass | ||
| 236 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 237 | .getFiller | ||
| 238 | .asInstanceOf[OWLClass] | ||
| 239 | .getIRI | ||
| 240 | TupleTableAtom.rdf(v1, IRI.RDF_TYPE, cls) | ||
| 241 | } | ||
| 242 | cycle.flatMap { x => | ||
| 243 | List( | ||
| 244 | Rule.create(roleRf(x), atomA(x)), | ||
| 245 | Rule.create(atomB, atomA(x)) | ||
| 246 | ) | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = { | ||
| 251 | if (axiom.isT5) { | ||
| 252 | // TODO: get role in T5 axiom | ||
| 253 | // Assuming one role here | ||
| 254 | val role = axiom.objectPropertyExpressionsInSignature(0) | ||
| 255 | if (ontology.unsafeRoles contains role) { | ||
| 256 | val visitor = | ||
| 257 | new RDFoxAxiomConverter( | ||
| 258 | Variable.create("X"), | ||
| 259 | ontology.unsafeRoles, | ||
| 260 | SkolemStrategy.Standard(axiom.toString), | ||
| 261 | Forward | ||
| 262 | ) | ||
| 263 | axiom.accept(visitor) | ||
| 264 | } else { | ||
| 265 | rules1(axiom) ::: rules2(axiom) ::: rules3(axiom) | ||
| 266 | } | ||
| 267 | } else { | ||
| 268 | // Fallback to standard OWL to LP translation | ||
| 269 | super.visit(axiom) | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = { | ||
| 274 | val varX = Variable.create("X") | ||
| 275 | val visitorF = new RDFoxAxiomConverter( | ||
| 276 | varX, | ||
| 277 | ontology.unsafeRoles, | ||
| 278 | SkolemStrategy.None, | ||
| 279 | Forward | ||
| 280 | ) | ||
| 281 | val visitorB = new RDFoxAxiomConverter( | ||
| 282 | varX, | ||
| 283 | ontology.unsafeRoles, | ||
| 284 | SkolemStrategy.None, | ||
| 285 | Backward | ||
| 286 | ) | ||
| 287 | axiom.accept(visitorB) ::: axiom.accept(visitorF) | ||
| 288 | } | ||
| 289 | |||
| 290 | } | ||
| 291 | |||
| 292 | } | ||
diff --git a/src/main/scala/rsacomb/Main.scala b/src/main/scala/rsacomb/Main.scala index 3963981..8270205 100644 --- a/src/main/scala/rsacomb/Main.scala +++ b/src/main/scala/rsacomb/Main.scala | |||
| @@ -52,7 +52,7 @@ object RSAComb extends App { | |||
| 52 | * case. | 52 | * case. |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | val ontology: RSAOntology = RSA.loadOntology(ontoPath) | 55 | val ontology = RSAOntology(ontoPath) |
| 56 | if (ontology.isRSA) { | 56 | if (ontology.isRSA) { |
| 57 | 57 | ||
| 58 | /* Load query */ | 58 | /* Load query */ |
diff --git a/src/main/scala/rsacomb/RDFoxUtil.scala b/src/main/scala/rsacomb/RDFoxUtil.scala index d391d41..653c51f 100644 --- a/src/main/scala/rsacomb/RDFoxUtil.scala +++ b/src/main/scala/rsacomb/RDFoxUtil.scala | |||
| @@ -15,6 +15,8 @@ import tech.oxfordsemantic.jrdfox.formats.SPARQLParser | |||
| 15 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI => RDFox_IRI} | 15 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI => RDFox_IRI} |
| 16 | import org.semanticweb.owlapi.model.{IRI => OWL_IRI} | 16 | import org.semanticweb.owlapi.model.{IRI => OWL_IRI} |
| 17 | 17 | ||
| 18 | import scala.collection.JavaConverters._ | ||
| 19 | |||
| 18 | object RDFoxUtil { | 20 | object RDFoxUtil { |
| 19 | 21 | ||
| 20 | implicit def rdfox2owlapi(iri: RDFox_IRI): OWL_IRI = { | 22 | implicit def rdfox2owlapi(iri: RDFox_IRI): OWL_IRI = { |
| @@ -29,6 +31,14 @@ object RDFoxUtil { | |||
| 29 | RDFox_IRI.create(iri) | 31 | RDFox_IRI.create(iri) |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 34 | implicit def javaToScalaList[A](list: java.util.List[A]): List[A] = { | ||
| 35 | list.asScala.toList | ||
| 36 | } | ||
| 37 | |||
| 38 | implicit def scalaToJavaList[A](list: List[A]): java.util.List[A] = { | ||
| 39 | list.asJava | ||
| 40 | } | ||
| 41 | |||
| 32 | def openConnection( | 42 | def openConnection( |
| 33 | dataStore: String | 43 | dataStore: String |
| 34 | ): (ServerConnection, DataStoreConnection) = { | 44 | ): (ServerConnection, DataStoreConnection) = { |
diff --git a/src/main/scala/rsacomb/RSA.scala b/src/main/scala/rsacomb/RSA.scala index dd09899..b0e140b 100644 --- a/src/main/scala/rsacomb/RSA.scala +++ b/src/main/scala/rsacomb/RSA.scala | |||
| @@ -1,13 +1,11 @@ | |||
| 1 | package rsacomb | 1 | package rsacomb |
| 2 | 2 | ||
| 3 | /* Java imports */ | 3 | /* Java imports */ |
| 4 | import java.io.File | ||
| 5 | import java.util.Map | 4 | import java.util.Map |
| 6 | 5 | ||
| 7 | import tech.oxfordsemantic.jrdfox.formats.SPARQLParser | 6 | import tech.oxfordsemantic.jrdfox.formats.SPARQLParser |
| 8 | import tech.oxfordsemantic.jrdfox.Prefixes | 7 | import tech.oxfordsemantic.jrdfox.Prefixes |
| 9 | import tech.oxfordsemantic.jrdfox.logic.expression.{Variable, IRI} | 8 | import tech.oxfordsemantic.jrdfox.logic.expression.{Variable, IRI} |
| 10 | import org.semanticweb.owlapi.apibinding.OWLManager | ||
| 11 | import org.semanticweb.owlapi.model.OWLOntology | 9 | import org.semanticweb.owlapi.model.OWLOntology |
| 12 | import org.semanticweb.owlapi.model.{ | 10 | import org.semanticweb.owlapi.model.{ |
| 13 | OWLAxiom, | 11 | OWLAxiom, |
| @@ -18,7 +16,7 @@ import org.semanticweb.owlapi.model.{ | |||
| 18 | // Debug only | 16 | // Debug only |
| 19 | import scala.collection.JavaConverters._ | 17 | import scala.collection.JavaConverters._ |
| 20 | 18 | ||
| 21 | object RSA extends RSAOntology with RSAAxiom { | 19 | object RSA extends RSAAxiom { |
| 22 | 20 | ||
| 23 | val Prefixes: Prefixes = new Prefixes() | 21 | val Prefixes: Prefixes = new Prefixes() |
| 24 | Prefixes.declarePrefix(":", "http://example.com/rsa_example.owl#") | 22 | Prefixes.declarePrefix(":", "http://example.com/rsa_example.owl#") |
| @@ -28,6 +26,7 @@ object RSA extends RSAOntology with RSAAxiom { | |||
| 28 | Prefixes.declarePrefix("owl:", "http://www.w3.org/2002/07/owl#") | 26 | Prefixes.declarePrefix("owl:", "http://www.w3.org/2002/07/owl#") |
| 29 | 27 | ||
| 30 | val EquivTo: IRI = this.rsa("EquivTo") | 28 | val EquivTo: IRI = this.rsa("EquivTo") |
| 29 | val Named: IRI = this.rsa("NAMED") | ||
| 31 | 30 | ||
| 32 | // Counter used to implement a simple fresh variable generator | 31 | // Counter used to implement a simple fresh variable generator |
| 33 | private var counter = -1; | 32 | private var counter = -1; |
| @@ -61,10 +60,4 @@ object RSA extends RSAOntology with RSAAxiom { | |||
| 61 | this.hashed(cls1, prop, cls2) | 60 | this.hashed(cls1, prop, cls2) |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | // TODO: move this somewhere else... maybe an OntoUtils class or something. | ||
| 65 | def loadOntology(onto: File): OWLOntology = { | ||
| 66 | val manager = OWLManager.createOWLOntologyManager() | ||
| 67 | manager.loadOntologyFromOntologyDocument(onto) | ||
| 68 | } | ||
| 69 | |||
| 70 | } // object RSA | 63 | } // object RSA |
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala index dd65116..52bff37 100644 --- a/src/main/scala/rsacomb/RSAOntology.scala +++ b/src/main/scala/rsacomb/RSAOntology.scala | |||
| @@ -3,6 +3,8 @@ package rsacomb | |||
| 3 | /* Java imports */ | 3 | /* Java imports */ |
| 4 | import java.util.HashMap | 4 | import java.util.HashMap |
| 5 | import java.util.stream.{Collectors, Stream} | 5 | import java.util.stream.{Collectors, Stream} |
| 6 | import java.io.File | ||
| 7 | import org.semanticweb.owlapi.apibinding.OWLManager | ||
| 6 | 8 | ||
| 7 | import org.semanticweb.owlapi.model.{OWLOntology, OWLAxiom} | 9 | import org.semanticweb.owlapi.model.{OWLOntology, OWLAxiom} |
| 8 | import org.semanticweb.owlapi.model.{ | 10 | import org.semanticweb.owlapi.model.{ |
| @@ -46,663 +48,326 @@ import org.semanticweb.owlapi.model.OWLObjectInverseOf | |||
| 46 | 48 | ||
| 47 | import suffix.{Empty, Forward, Backward, Inverse} | 49 | import suffix.{Empty, Forward, Backward, Inverse} |
| 48 | 50 | ||
| 49 | object RSAOntology {} | 51 | object RSAOntology { |
| 50 | /* Wrapper trait for the implicit class `RSAOntology`. | ||
| 51 | */ | ||
| 52 | trait RSAOntology { | ||
| 53 | 52 | ||
| 54 | /* Implements additional features to reason about RSA ontologies | 53 | def apply(ontology: OWLOntology): RSAOntology = new RSAOntology(ontology) |
| 55 | * on top of `OWLOntology` from the OWLAPI. | ||
| 56 | */ | ||
| 57 | implicit class RSAOntology(ontology: OWLOntology) extends RSAAxiom { | ||
| 58 | |||
| 59 | // Gather TBox/RBox/ABox from original ontology | ||
| 60 | lazy val tbox: List[OWLAxiom] = | ||
| 61 | ontology | ||
| 62 | .tboxAxioms(Imports.INCLUDED) | ||
| 63 | .collect(Collectors.toList()) | ||
| 64 | .asScala | ||
| 65 | .toList | ||
| 66 | |||
| 67 | lazy val rbox: List[OWLAxiom] = | ||
| 68 | ontology | ||
| 69 | .rboxAxioms(Imports.INCLUDED) | ||
| 70 | .collect(Collectors.toList()) | ||
| 71 | .asScala | ||
| 72 | .toList | ||
| 73 | |||
| 74 | lazy val abox: List[OWLAxiom] = | ||
| 75 | ontology | ||
| 76 | .aboxAxioms(Imports.INCLUDED) | ||
| 77 | .collect(Collectors.toList()) | ||
| 78 | .asScala | ||
| 79 | .toList | ||
| 80 | |||
| 81 | lazy val axioms: List[OWLAxiom] = abox ++ tbox ++ rbox | ||
| 82 | |||
| 83 | /* Retrieve individuals in the original ontology | ||
| 84 | */ | ||
| 85 | lazy val individuals: List[IRI] = | ||
| 86 | ontology | ||
| 87 | .getIndividualsInSignature() | ||
| 88 | .asScala | ||
| 89 | .map(_.getIRI) | ||
| 90 | .map(RDFoxUtil.owlapi2rdfox) | ||
| 91 | .toList | ||
| 92 | |||
| 93 | lazy val concepts: List[OWLClass] = | ||
| 94 | ontology.getClassesInSignature().asScala.toList | ||
| 95 | |||
| 96 | lazy val roles: List[OWLObjectPropertyExpression] = | ||
| 97 | axioms | ||
| 98 | .flatMap(_.objectPropertyExpressionsInSignature) | ||
| 99 | .distinct | ||
| 100 | |||
| 101 | // OWLAPI reasoner for same easier tasks | ||
| 102 | private val reasoner = | ||
| 103 | (new StructuralReasonerFactory()).createReasoner(ontology) | ||
| 104 | |||
| 105 | /* Steps for RSA check | ||
| 106 | * 1) convert ontology axioms into LP rules | ||
| 107 | * 2) call RDFox on the onto and compute materialization | ||
| 108 | * 3) build graph from E(x,y) facts | ||
| 109 | * 4) check if the graph is tree-like | ||
| 110 | * ideally this annotates the graph with info about the reasons | ||
| 111 | * why the ontology might not be RSA. This could help a second | ||
| 112 | * step of approximation of an Horn-ALCHOIQ to RSA | ||
| 113 | */ | ||
| 114 | lazy val isRSA: Boolean = { | ||
| 115 | |||
| 116 | val unsafe = this.unsafeRoles | ||
| 117 | |||
| 118 | /* DEBUG: print rules in DL syntax and unsafe roles */ | ||
| 119 | //val renderer = new DLSyntaxObjectRenderer() | ||
| 120 | //println("\nDL rules:") | ||
| 121 | //axioms.foreach(x => println(renderer.render(x))) | ||
| 122 | //println("\nUnsafe roles:") | ||
| 123 | //println(unsafe) | ||
| 124 | |||
| 125 | /* Ontology convertion into LP rules */ | ||
| 126 | val datalog = for { | ||
| 127 | axiom <- axioms | ||
| 128 | visitor = new RDFoxAxiomConverter( | ||
| 129 | RSA.getFreshVariable(), | ||
| 130 | unsafe, | ||
| 131 | SkolemStrategy.ConstantRSA(axiom.toString), | ||
| 132 | Empty | ||
| 133 | ) | ||
| 134 | rule <- axiom.accept(visitor) | ||
| 135 | } yield rule | ||
| 136 | |||
| 137 | /* DEBUG: print datalog rules */ | ||
| 138 | //println("\nDatalog roles:") | ||
| 139 | //datalog.foreach(println) | ||
| 140 | |||
| 141 | // Open connection with RDFox | ||
| 142 | val (server, data) = RDFoxUtil.openConnection("RSACheck") | ||
| 143 | // Add Data (hardcoded for now) | ||
| 144 | data.importData(UpdateType.ADDITION, RSA.Prefixes, ":a a :A .") | ||
| 145 | |||
| 146 | /* Add built-in rules | ||
| 147 | */ | ||
| 148 | data.importData( | ||
| 149 | UpdateType.ADDITION, | ||
| 150 | RSA.Prefixes, | ||
| 151 | "<http://127.0.0.1/E>[?X,?Y] :- <http://127.0.0.1/PE>[?X,?Y], <http://127.0.0.1/U>[?X], <http://127.0.0.1/U>[?Y] ." | ||
| 152 | ) | ||
| 153 | 54 | ||
| 154 | /* Add built-in rules | 55 | def apply(ontology: File): RSAOntology = |
| 155 | */ | 56 | new RSAOntology(loadOntology(ontology)) |
| 156 | // data.importData( | ||
| 157 | // UpdateType.ADDITION, | ||
| 158 | // RSA.Prefixes, | ||
| 159 | // "[?entity, a, ?superClass] :- [?entity, a, ?class], [?class, rdfs:subClassOf, ?superClass] ." | ||
| 160 | // ) | ||
| 161 | |||
| 162 | /* Add ontology rules | ||
| 163 | */ | ||
| 164 | data.addRules(datalog.asJava) | ||
| 165 | |||
| 166 | /* Build graph | ||
| 167 | */ | ||
| 168 | val graph = this.rsaGraph(data); | ||
| 169 | //println(graph) | ||
| 170 | |||
| 171 | // Close connection to RDFox | ||
| 172 | RDFoxUtil.closeConnection(server, data) | ||
| 173 | |||
| 174 | /* To check if the graph is tree-like we check for acyclicity in a | ||
| 175 | * undirected graph. | ||
| 176 | * | ||
| 177 | * TODO: Implement additional checks (taking into account equality) | ||
| 178 | */ | ||
| 179 | graph.isAcyclic | ||
| 180 | } | ||
| 181 | 57 | ||
| 182 | lazy val unsafeRoles: List[OWLObjectPropertyExpression] = { | 58 | private def loadOntology(onto: File): OWLOntology = { |
| 183 | 59 | val manager = OWLManager.createOWLOntologyManager() | |
| 184 | /* DEBUG: print rules in DL syntax */ | 60 | manager.loadOntologyFromOntologyDocument(onto) |
| 185 | //val renderer = new DLSyntaxObjectRenderer() | 61 | } |
| 186 | 62 | } | |
| 187 | /* Checking for (1) unsafety condition: | ||
| 188 | * | ||
| 189 | * For all roles r1 appearing in an axiom of type T5, r1 is unsafe | ||
| 190 | * if there exists a role r2 (different from top) appearing in an axiom | ||
| 191 | * of type T3 and r1 is a subproperty of the inverse of r2. | ||
| 192 | */ | ||
| 193 | val unsafe1 = for { | ||
| 194 | axiom <- tbox | ||
| 195 | if axiom.isT5 | ||
| 196 | role1 <- axiom.objectPropertyExpressionsInSignature | ||
| 197 | roleSuper = | ||
| 198 | role1 +: reasoner | ||
| 199 | .superObjectProperties(role1) | ||
| 200 | .collect(Collectors.toList()) | ||
| 201 | .asScala | ||
| 202 | roleSuperInv = roleSuper.map(_.getInverseProperty) | ||
| 203 | axiom <- tbox | ||
| 204 | if axiom.isT3 && !axiom.isT3top | ||
| 205 | role2 <- axiom.objectPropertyExpressionsInSignature | ||
| 206 | if roleSuperInv.contains(role2) | ||
| 207 | } yield role1 | ||
| 208 | |||
| 209 | /* Checking for (2) unsafety condition: | ||
| 210 | * | ||
| 211 | * For all roles p1 appearing in an axiom of type T5, p1 is unsafe if | ||
| 212 | * there exists a role p2 appearing in an axiom of type T4 and p1 is a | ||
| 213 | * subproperty of either p2 or the inverse of p2. | ||
| 214 | * | ||
| 215 | */ | ||
| 216 | val unsafe2 = for { | ||
| 217 | axiom <- tbox | ||
| 218 | if axiom.isT5 | ||
| 219 | role1 <- axiom.objectPropertyExpressionsInSignature | ||
| 220 | roleSuper = | ||
| 221 | role1 +: reasoner | ||
| 222 | .superObjectProperties(role1) | ||
| 223 | .collect(Collectors.toList()) | ||
| 224 | .asScala | ||
| 225 | roleSuperInv = roleSuper.map(_.getInverseProperty) | ||
| 226 | axiom <- tbox | ||
| 227 | if axiom.isT4 | ||
| 228 | role2 <- axiom.objectPropertyExpressionsInSignature | ||
| 229 | if roleSuper.contains(role2) || roleSuperInv.contains(role2) | ||
| 230 | } yield role1 | ||
| 231 | |||
| 232 | (unsafe1 ++ unsafe2).toList | ||
| 233 | } | ||
| 234 | 63 | ||
| 235 | private def rsaGraph( | 64 | class RSAOntology(val ontology: OWLOntology) extends RSAAxiom { |
| 236 | data: DataStoreConnection | 65 | |
| 237 | ): Graph[Resource, UnDiEdge] = { | 66 | // Gather TBox/RBox/ABox from original ontology |
| 238 | val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }" | 67 | val tbox: List[OWLAxiom] = |
| 239 | val cursor = | 68 | ontology |
| 240 | data.createCursor(RSA.Prefixes, query, new HashMap[String, String]()); | 69 | .tboxAxioms(Imports.INCLUDED) |
| 241 | var mul = cursor.open() | 70 | .collect(Collectors.toList()) |
| 242 | var edges: List[UnDiEdge[Resource]] = List() | 71 | .asScala |
| 243 | while (mul > 0) { | 72 | .toList |
| 244 | edges = UnDiEdge(cursor.getResource(0), cursor.getResource(1)) :: edges | 73 | |
| 245 | mul = cursor.advance() | 74 | val rbox: List[OWLAxiom] = |
| 246 | } | 75 | ontology |
| 247 | Graph(edges: _*) | 76 | .rboxAxioms(Imports.INCLUDED) |
| 248 | } | 77 | .collect(Collectors.toList()) |
| 78 | .asScala | ||
| 79 | .toList | ||
| 80 | |||
| 81 | val abox: List[OWLAxiom] = | ||
| 82 | ontology | ||
| 83 | .aboxAxioms(Imports.INCLUDED) | ||
| 84 | .collect(Collectors.toList()) | ||
| 85 | .asScala | ||
| 86 | .toList | ||
| 87 | |||
| 88 | val axioms: List[OWLAxiom] = abox ::: tbox ::: rbox | ||
| 89 | |||
| 90 | /* Retrieve individuals in the original ontology | ||
| 91 | */ | ||
| 92 | val individuals: List[IRI] = | ||
| 93 | ontology | ||
| 94 | .getIndividualsInSignature() | ||
| 95 | .asScala | ||
| 96 | .map(_.getIRI) | ||
| 97 | .map(RDFoxUtil.owlapi2rdfox) | ||
| 98 | .toList | ||
| 99 | |||
| 100 | val concepts: List[OWLClass] = | ||
| 101 | ontology.getClassesInSignature().asScala.toList | ||
| 102 | |||
| 103 | val roles: List[OWLObjectPropertyExpression] = | ||
| 104 | axioms | ||
| 105 | .flatMap(_.objectPropertyExpressionsInSignature) | ||
| 106 | .distinct | ||
| 107 | |||
| 108 | // OWLAPI reasoner for same easier tasks | ||
| 109 | private val reasoner = | ||
| 110 | (new StructuralReasonerFactory()).createReasoner(ontology) | ||
| 111 | |||
| 112 | /* Steps for RSA check | ||
| 113 | * 1) convert ontology axioms into LP rules | ||
| 114 | * 2) call RDFox on the onto and compute materialization | ||
| 115 | * 3) build graph from E(x,y) facts | ||
| 116 | * 4) check if the graph is tree-like | ||
| 117 | * ideally this annotates the graph with info about the reasons | ||
| 118 | * why the ontology might not be RSA. This could help a second | ||
| 119 | * step of approximation of an Horn-ALCHOIQ to RSA | ||
| 120 | */ | ||
| 121 | lazy val isRSA: Boolean = { | ||
| 122 | |||
| 123 | val unsafe = this.unsafeRoles | ||
| 124 | |||
| 125 | /* DEBUG: print rules in DL syntax and unsafe roles */ | ||
| 126 | //val renderer = new DLSyntaxObjectRenderer() | ||
| 127 | //println("\nDL rules:") | ||
| 128 | //axioms.foreach(x => println(renderer.render(x))) | ||
| 129 | //println("\nUnsafe roles:") | ||
| 130 | //println(unsafe) | ||
| 131 | |||
| 132 | /* Ontology convertion into LP rules */ | ||
| 133 | val datalog = for { | ||
| 134 | axiom <- axioms | ||
| 135 | visitor = new RDFoxAxiomConverter( | ||
| 136 | RSA.getFreshVariable(), | ||
| 137 | unsafe, | ||
| 138 | SkolemStrategy.ConstantRSA(axiom.toString), | ||
| 139 | Empty | ||
| 140 | ) | ||
| 141 | rule <- axiom.accept(visitor) | ||
| 142 | } yield rule | ||
| 249 | 143 | ||
| 250 | def filteringProgram( | 144 | /* DEBUG: print datalog rules */ |
| 251 | query: SelectQuery, | 145 | //println("\nDatalog roles:") |
| 252 | nis: List[Term] | 146 | //datalog.foreach(println) |
| 253 | ): FilteringProgram = | ||
| 254 | new FilteringProgram(query, nis) | ||
| 255 | |||
| 256 | // TODO: the following functions needs testing | ||
| 257 | def confl( | ||
| 258 | role: OWLObjectPropertyExpression | ||
| 259 | ): Set[OWLObjectPropertyExpression] = { | ||
| 260 | |||
| 261 | val invSuperRoles = reasoner | ||
| 262 | .superObjectProperties(role) | ||
| 263 | .collect(Collectors.toSet()) | ||
| 264 | .asScala | ||
| 265 | .addOne(role) | ||
| 266 | .map(_.getInverseProperty) | ||
| 267 | |||
| 268 | invSuperRoles | ||
| 269 | .flatMap(x => | ||
| 270 | reasoner | ||
| 271 | .subObjectProperties(x) | ||
| 272 | .collect(Collectors.toSet()) | ||
| 273 | .asScala | ||
| 274 | .addOne(x) | ||
| 275 | ) | ||
| 276 | .filterNot(_.isOWLBottomObjectProperty()) | ||
| 277 | .filterNot(_.getInverseProperty.isOWLTopObjectProperty()) | ||
| 278 | } | ||
| 279 | 147 | ||
| 280 | def self(axiom: OWLSubClassOfAxiom): Set[Term] = { | 148 | // Open connection with RDFox |
| 281 | // Assuming just one role in the signature of a T5 axiom | 149 | val (server, data) = RDFoxUtil.openConnection("RSACheck") |
| 282 | val role = axiom.objectPropertyExpressionsInSignature(0) | 150 | // Add Data (hardcoded for now) |
| 283 | if (this.confl(role).contains(role)) { | 151 | data.importData(UpdateType.ADDITION, RSA.Prefixes, ":a a :A .") |
| 284 | Set( | ||
| 285 | RSA.rsa("v0_" ++ RSA.hashed(axiom)), | ||
| 286 | RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 287 | ) | ||
| 288 | } else { | ||
| 289 | Set() | ||
| 290 | } | ||
| 291 | } | ||
| 292 | 152 | ||
| 293 | // def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { | 153 | /* Add built-in rules |
| 294 | // // Assuming just one role in the signature of a T5 axiom | 154 | */ |
| 295 | // val roleR = axiom.objectPropertyExpressionsInSignature(0) | 155 | data.importData( |
| 296 | // val conflR = this.confl(roleR) | 156 | UpdateType.ADDITION, |
| 297 | // // We just need the TBox to find | 157 | RSA.Prefixes, |
| 298 | // val tbox = ontology | 158 | "<http://127.0.0.1/E>[?X,?Y] :- <http://127.0.0.1/PE>[?X,?Y], <http://127.0.0.1/U>[?X], <http://127.0.0.1/U>[?Y] ." |
| 299 | // .tboxAxioms(Imports.INCLUDED) | 159 | ) |
| 300 | // .collect(Collectors.toSet()) | ||
| 301 | // .asScala | ||
| 302 | // for { | ||
| 303 | // axiom1 <- tbox | ||
| 304 | // // TODO: is this an optimization or an error? | ||
| 305 | // if axiom1.isT5 | ||
| 306 | // // We expect only one role coming out of a T5 axiom | ||
| 307 | // roleS <- axiom1.objectPropertyExpressionsInSignature | ||
| 308 | // // Triples ordering is among triples involving safe roles. | ||
| 309 | // if !unsafeRoles.contains(roleS) | ||
| 310 | // if conflR.contains(roleS) | ||
| 311 | // individual = | ||
| 312 | // if (axiom.hashCode < axiom1.hashCode) { | ||
| 313 | // RSA.rsa("v0_" ++ axiom1.hashCode.toString()) | ||
| 314 | // } else { | ||
| 315 | // RSA.rsa("v1_" ++ axiom1.hashCode.toString()) | ||
| 316 | // } | ||
| 317 | // } yield individual | ||
| 318 | // } | ||
| 319 | |||
| 320 | def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { | ||
| 321 | // TODO: we can actually use `toTriple` from `RSAAxiom` | ||
| 322 | val classes = | ||
| 323 | axiom.classesInSignature.collect(Collectors.toList()).asScala | ||
| 324 | val classA = classes(0) | ||
| 325 | val roleR = axiom | ||
| 326 | .objectPropertyExpressionsInSignature(0) | ||
| 327 | .asInstanceOf[OWLObjectProperty] | ||
| 328 | val classB = classes(1) | ||
| 329 | cycle_aux(classA, roleR, classB) | ||
| 330 | } | ||
| 331 | 160 | ||
| 332 | def cycle_aux( | 161 | /* Add built-in rules |
| 333 | classA: OWLClass, | 162 | */ |
| 334 | roleR: OWLObjectProperty, | 163 | // data.importData( |
| 335 | classB: OWLClass | 164 | // UpdateType.ADDITION, |
| 336 | ): Set[Term] = { | 165 | // RSA.Prefixes, |
| 337 | val conflR = this.confl(roleR) | 166 | // "[?entity, a, ?superClass] :- [?entity, a, ?class], [?class, rdfs:subClassOf, ?superClass] ." |
| 338 | val classes = ontology | 167 | // ) |
| 339 | .classesInSignature(Imports.INCLUDED) | ||
| 340 | .collect(Collectors.toSet()) | ||
| 341 | .asScala | ||
| 342 | for { | ||
| 343 | classD <- classes | ||
| 344 | roleS <- conflR | ||
| 345 | classC <- classes | ||
| 346 | // Keeping this check for now | ||
| 347 | if !unsafeRoles.contains(roleS) | ||
| 348 | tripleARB = RSA.hashed(classA, roleR, classB) | ||
| 349 | tripleDSC = RSA.hashed(classD, roleS, classC) | ||
| 350 | individual = | ||
| 351 | if (tripleARB > tripleDSC) { | ||
| 352 | RSA.rsa("v1_" ++ tripleDSC) | ||
| 353 | } else { | ||
| 354 | // Note that this is also the case for | ||
| 355 | // `tripleARB == tripleDSC` | ||
| 356 | RSA.rsa("v0_" ++ tripleDSC) | ||
| 357 | } | ||
| 358 | } yield individual | ||
| 359 | } | ||
| 360 | 168 | ||
| 361 | def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = | 169 | /* Add ontology rules |
| 362 | this.self(axiom) | this.cycle(axiom) | 170 | */ |
| 363 | 171 | data.addRules(datalog.asJava) | |
| 364 | object canonicalModel { | ||
| 365 | |||
| 366 | import RDFoxUtil._ | ||
| 367 | |||
| 368 | val named: List[Rule] = | ||
| 369 | individuals.map(a => | ||
| 370 | Rule.create( | ||
| 371 | TupleTableAtom.rdf(a, IRI.RDF_TYPE, RSA.rsa("NAMED")) | ||
| 372 | ) | ||
| 373 | ) | ||
| 374 | |||
| 375 | val rolesAdditionalRules: List[Rule] = { | ||
| 376 | // Given a role (predicate) compute additional logic rules | ||
| 377 | def additional(pred: String): Seq[Rule] = { | ||
| 378 | val varX = Variable.create("X") | ||
| 379 | val varY = Variable.create("Y") | ||
| 380 | List( | ||
| 381 | Rule.create( | ||
| 382 | TupleTableAtom.rdf(varX, IRI.create(pred), varY), | ||
| 383 | TupleTableAtom | ||
| 384 | .rdf( | ||
| 385 | varX, | ||
| 386 | IRI.create(pred :: Forward), | ||
| 387 | varY | ||
| 388 | ) | ||
| 389 | ), | ||
| 390 | Rule.create( | ||
| 391 | TupleTableAtom.rdf(varX, IRI.create(pred), varY), | ||
| 392 | TupleTableAtom | ||
| 393 | .rdf( | ||
| 394 | varX, | ||
| 395 | IRI.create(pred :: Backward), | ||
| 396 | varY | ||
| 397 | ) | ||
| 398 | ), | ||
| 399 | Rule.create( | ||
| 400 | TupleTableAtom.rdf(varX, IRI.create(pred ++ "_inv"), varY), | ||
| 401 | TupleTableAtom | ||
| 402 | .rdf( | ||
| 403 | varX, | ||
| 404 | IRI.create(pred :: Forward + Inverse), | ||
| 405 | varY | ||
| 406 | ) | ||
| 407 | ), | ||
| 408 | Rule.create( | ||
| 409 | TupleTableAtom.rdf(varX, IRI.create(pred ++ "_inv"), varY), | ||
| 410 | TupleTableAtom | ||
| 411 | .rdf( | ||
| 412 | varX, | ||
| 413 | IRI.create(pred :: Backward + Inverse), | ||
| 414 | varY | ||
| 415 | ) | ||
| 416 | ), | ||
| 417 | Rule.create( | ||
| 418 | TupleTableAtom.rdf( | ||
| 419 | varY, | ||
| 420 | IRI.create(pred :: Backward + Inverse), | ||
| 421 | varX | ||
| 422 | ), | ||
| 423 | TupleTableAtom | ||
| 424 | .rdf( | ||
| 425 | varX, | ||
| 426 | IRI.create(pred :: Forward), | ||
| 427 | varY | ||
| 428 | ) | ||
| 429 | ), | ||
| 430 | Rule.create( | ||
| 431 | TupleTableAtom.rdf( | ||
| 432 | varY, | ||
| 433 | IRI.create(pred :: Forward + Inverse), | ||
| 434 | varX | ||
| 435 | ), | ||
| 436 | TupleTableAtom.rdf( | ||
| 437 | varX, | ||
| 438 | IRI.create(pred :: Backward), | ||
| 439 | varY | ||
| 440 | ) | ||
| 441 | ), | ||
| 442 | Rule.create( | ||
| 443 | TupleTableAtom.rdf( | ||
| 444 | varY, | ||
| 445 | IRI.create(pred :: Backward), | ||
| 446 | varX | ||
| 447 | ), | ||
| 448 | TupleTableAtom | ||
| 449 | .rdf( | ||
| 450 | varX, | ||
| 451 | IRI.create(pred :: Forward + Inverse), | ||
| 452 | varY | ||
| 453 | ) | ||
| 454 | ), | ||
| 455 | Rule.create( | ||
| 456 | TupleTableAtom.rdf( | ||
| 457 | varY, | ||
| 458 | IRI.create(pred :: Forward), | ||
| 459 | varX | ||
| 460 | ), | ||
| 461 | TupleTableAtom.rdf( | ||
| 462 | varX, | ||
| 463 | IRI.create(pred :: Backward + Inverse), | ||
| 464 | varY | ||
| 465 | ) | ||
| 466 | ) | ||
| 467 | ) | ||
| 468 | } | ||
| 469 | // Compute additional rules per role | ||
| 470 | axioms | ||
| 471 | .flatMap( | ||
| 472 | _.objectPropertiesInSignature.collect(Collectors.toSet()).asScala | ||
| 473 | ) | ||
| 474 | .distinct | ||
| 475 | .map(_.getIRI.getIRIString) | ||
| 476 | .flatMap(additional) | ||
| 477 | } | ||
| 478 | |||
| 479 | private lazy val topAxioms: List[Rule] = | ||
| 480 | concepts.map(c => { | ||
| 481 | val x = Variable.create("X") | ||
| 482 | Rule.create( | ||
| 483 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, IRI.THING), | ||
| 484 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, c.getIRI) | ||
| 485 | ) | ||
| 486 | }) ++ | ||
| 487 | roles.map(r => { | ||
| 488 | val x = Variable.create("X") | ||
| 489 | val y = Variable.create("Y") | ||
| 490 | val iri: IRI = r match { | ||
| 491 | case x: OWLObjectProperty => x.getIRI | ||
| 492 | case x: OWLObjectInverseOf => | ||
| 493 | IRI.create(x.getNamedProperty.getIRI.getIRIString ++ "_inv") | ||
| 494 | case x => x.getNamedProperty.getIRI | ||
| 495 | } | ||
| 496 | Rule.create( | ||
| 497 | List( | ||
| 498 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, IRI.THING), | ||
| 499 | TupleTableAtom.rdf(y, IRI.RDF_TYPE, IRI.THING) | ||
| 500 | ).asJava, | ||
| 501 | List[BodyFormula](TupleTableAtom.rdf(x, iri, y)).asJava | ||
| 502 | ) | ||
| 503 | }) | ||
| 504 | |||
| 505 | private val equalityAxioms: List[Rule] = { | ||
| 506 | val x = Variable.create("X") | ||
| 507 | val y = Variable.create("Y") | ||
| 508 | val z = Variable.create("Z") | ||
| 509 | List( | ||
| 510 | Rule.create( | ||
| 511 | TupleTableAtom.rdf(x, RSA.EquivTo, x), | ||
| 512 | TupleTableAtom.rdf(x, IRI.RDF_TYPE, IRI.THING) | ||
| 513 | ), | ||
| 514 | Rule.create( | ||
| 515 | TupleTableAtom.rdf(y, RSA.EquivTo, x), | ||
| 516 | TupleTableAtom.rdf(x, RSA.EquivTo, y) | ||
| 517 | ), | ||
| 518 | Rule.create( | ||
| 519 | TupleTableAtom.rdf(x, RSA.EquivTo, z), | ||
| 520 | TupleTableAtom.rdf(x, RSA.EquivTo, y), | ||
| 521 | TupleTableAtom.rdf(y, RSA.EquivTo, z) | ||
| 522 | ) | ||
| 523 | ) | ||
| 524 | } | ||
| 525 | |||
| 526 | val rules: List[Rule] = { | ||
| 527 | // Compute rules from ontology axioms | ||
| 528 | val rules = axioms.flatMap(_.accept(this.ProgramGenerator)) | ||
| 529 | // Return full set of rules | ||
| 530 | rules ++ rolesAdditionalRules ++ topAxioms ++ equalityAxioms ++ named | ||
| 531 | } | ||
| 532 | |||
| 533 | object ProgramGenerator | ||
| 534 | extends RDFoxAxiomConverter( | ||
| 535 | Variable.create("X"), | ||
| 536 | unsafeRoles, | ||
| 537 | SkolemStrategy.None, | ||
| 538 | Empty | ||
| 539 | ) { | ||
| 540 | |||
| 541 | private def rules1(axiom: OWLSubClassOfAxiom): List[Rule] = { | ||
| 542 | val unfold = ontology.unfold(axiom).toList | ||
| 543 | // Fresh Variables | ||
| 544 | val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom)) | ||
| 545 | val varX = Variable.create("X") | ||
| 546 | // Predicates | ||
| 547 | val atomA: TupleTableAtom = { | ||
| 548 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 549 | TupleTableAtom.rdf(varX, IRI.RDF_TYPE, cls) | ||
| 550 | } | ||
| 551 | def in(t: Term): TupleTableAtom = { | ||
| 552 | TupleTableAtom.rdf( | ||
| 553 | t, | ||
| 554 | RSA.rsa("IN"), | ||
| 555 | RSA.rsa(unfold.hashCode.toString) | ||
| 556 | ) | ||
| 557 | } | ||
| 558 | def notIn(t: Term): Negation = Negation.create(in(t)) | ||
| 559 | val roleRf: TupleTableAtom = { | ||
| 560 | val visitor = | ||
| 561 | new RDFoxPropertyExprConverter(varX, v0, Forward) | ||
| 562 | axiom.getSuperClass | ||
| 563 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 564 | .getProperty | ||
| 565 | .accept(visitor) | ||
| 566 | .head | ||
| 567 | } | ||
| 568 | val atomB: TupleTableAtom = { | ||
| 569 | val cls = axiom.getSuperClass | ||
| 570 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 571 | .getFiller | ||
| 572 | .asInstanceOf[OWLClass] | ||
| 573 | .getIRI | ||
| 574 | TupleTableAtom.rdf(v0, IRI.RDF_TYPE, cls) | ||
| 575 | } | ||
| 576 | // TODO: To be consistent with the specifics of the visitor we are | ||
| 577 | // returning facts as `Rule`s with true body. While this is correct | ||
| 578 | // there is an easier way to import facts into RDFox. Are we able to | ||
| 579 | // do that? | ||
| 580 | val facts = unfold.map(x => Rule.create(in(x))) | ||
| 581 | val rules = List( | ||
| 582 | Rule.create(roleRf, atomA, notIn(varX)), | ||
| 583 | Rule.create(atomB, atomA, notIn(varX)) | ||
| 584 | ) | ||
| 585 | facts ++ rules | ||
| 586 | } | ||
| 587 | 172 | ||
| 588 | private def rules2(axiom: OWLSubClassOfAxiom): List[Rule] = { | 173 | /* Build graph |
| 589 | val roleR = | 174 | */ |
| 590 | axiom.getSuperClass | 175 | val graph = this.rsaGraph(data); |
| 591 | .asInstanceOf[OWLObjectSomeValuesFrom] | 176 | //println(graph) |
| 592 | .getProperty | ||
| 593 | if (ontology.confl(roleR) contains roleR) { | ||
| 594 | // Fresh Variables | ||
| 595 | val v0 = RSA.rsa("v0_" ++ RSA.hashed(axiom)) | ||
| 596 | val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 597 | val v2 = RSA.rsa("v2_" ++ RSA.hashed(axiom)) | ||
| 598 | // Predicates | ||
| 599 | def atomA(t: Term): TupleTableAtom = { | ||
| 600 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 601 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 602 | } | ||
| 603 | def roleRf(t1: Term, t2: Term): TupleTableAtom = { | ||
| 604 | val visitor = | ||
| 605 | new RDFoxPropertyExprConverter(t1, t2, Forward) | ||
| 606 | roleR.accept(visitor).head | ||
| 607 | } | ||
| 608 | def atomB(t: Term): TupleTableAtom = { | ||
| 609 | val cls = axiom.getSuperClass | ||
| 610 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 611 | .getFiller | ||
| 612 | .asInstanceOf[OWLClass] | ||
| 613 | .getIRI | ||
| 614 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 615 | } | ||
| 616 | //Rules | ||
| 617 | List( | ||
| 618 | Rule.create(roleRf(v0, v1), atomA(v0)), | ||
| 619 | Rule.create(atomB(v1), atomA(v0)), | ||
| 620 | Rule.create(roleRf(v1, v2), atomA(v1)), | ||
| 621 | Rule.create(atomB(v2), atomA(v1)) | ||
| 622 | ) | ||
| 623 | } else { | ||
| 624 | List() | ||
| 625 | } | ||
| 626 | } | ||
| 627 | 177 | ||
| 628 | private def rules3(axiom: OWLSubClassOfAxiom): List[Rule] = { | 178 | // Close connection to RDFox |
| 629 | val cycle = ontology.cycle(axiom).toList | 179 | RDFoxUtil.closeConnection(server, data) |
| 630 | val roleR = | ||
| 631 | axiom.getSuperClass | ||
| 632 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 633 | .getProperty | ||
| 634 | // Fresh Variables | ||
| 635 | val v1 = RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 636 | // Predicates | ||
| 637 | def atomA(t: Term): TupleTableAtom = { | ||
| 638 | val cls = axiom.getSubClass.asInstanceOf[OWLClass].getIRI | ||
| 639 | TupleTableAtom.rdf(t, IRI.RDF_TYPE, cls) | ||
| 640 | } | ||
| 641 | def roleRf(t: Term): TupleTableAtom = { | ||
| 642 | val visitor = | ||
| 643 | new RDFoxPropertyExprConverter(t, v1, Forward) | ||
| 644 | roleR.accept(visitor).head | ||
| 645 | } | ||
| 646 | val atomB: TupleTableAtom = { | ||
| 647 | val cls = axiom.getSuperClass | ||
| 648 | .asInstanceOf[OWLObjectSomeValuesFrom] | ||
| 649 | .getFiller | ||
| 650 | .asInstanceOf[OWLClass] | ||
| 651 | .getIRI | ||
| 652 | TupleTableAtom.rdf(v1, IRI.RDF_TYPE, cls) | ||
| 653 | } | ||
| 654 | cycle.flatMap { x => | ||
| 655 | List( | ||
| 656 | Rule.create(roleRf(x), atomA(x)), | ||
| 657 | Rule.create(atomB, atomA(x)) | ||
| 658 | ) | ||
| 659 | } | ||
| 660 | } | ||
| 661 | 180 | ||
| 662 | override def visit(axiom: OWLSubClassOfAxiom): List[Rule] = { | 181 | /* To check if the graph is tree-like we check for acyclicity in a |
| 663 | if (axiom.isT5) { | 182 | * undirected graph. |
| 664 | // TODO: get role in T5 axiom | 183 | * |
| 665 | // Assuming one role here | 184 | * TODO: Implement additional checks (taking into account equality) |
| 666 | val role = axiom.objectPropertyExpressionsInSignature(0) | 185 | */ |
| 667 | if (ontology.unsafeRoles.contains(role)) { | 186 | graph.isAcyclic |
| 668 | val visitor = | 187 | } |
| 669 | new RDFoxAxiomConverter( | ||
| 670 | Variable.create("X"), | ||
| 671 | ontology.unsafeRoles, | ||
| 672 | SkolemStrategy.Standard(axiom.toString), | ||
| 673 | Forward | ||
| 674 | ) | ||
| 675 | axiom.accept(visitor) | ||
| 676 | } else { | ||
| 677 | rules1(axiom) ++ rules2(axiom) ++ rules3(axiom) | ||
| 678 | } | ||
| 679 | } else { | ||
| 680 | // Fallback to standard OWL to LP translation | ||
| 681 | super.visit(axiom) | ||
| 682 | } | ||
| 683 | } | ||
| 684 | 188 | ||
| 685 | override def visit(axiom: OWLSubObjectPropertyOfAxiom): List[Rule] = { | 189 | lazy val unsafeRoles: List[OWLObjectPropertyExpression] = { |
| 686 | val varX = Variable.create("X") | ||
| 687 | val varY = Variable.create("Y") | ||
| 688 | val visitorF = new RDFoxAxiomConverter( | ||
| 689 | Variable.create("X"), | ||
| 690 | ontology.unsafeRoles, | ||
| 691 | SkolemStrategy.None, | ||
| 692 | Forward | ||
| 693 | ) | ||
| 694 | val visitorB = new RDFoxAxiomConverter( | ||
| 695 | Variable.create("X"), | ||
| 696 | ontology.unsafeRoles, | ||
| 697 | SkolemStrategy.None, | ||
| 698 | Backward | ||
| 699 | ) | ||
| 700 | axiom.accept(visitorB) ++ axiom.accept(visitorF) | ||
| 701 | } | ||
| 702 | 190 | ||
| 703 | } | 191 | /* DEBUG: print rules in DL syntax */ |
| 192 | //val renderer = new DLSyntaxObjectRenderer() | ||
| 704 | 193 | ||
| 194 | /* Checking for (1) unsafety condition: | ||
| 195 | * | ||
| 196 | * For all roles r1 appearing in an axiom of type T5, r1 is unsafe | ||
| 197 | * if there exists a role r2 (different from top) appearing in an axiom | ||
| 198 | * of type T3 and r1 is a subproperty of the inverse of r2. | ||
| 199 | */ | ||
| 200 | val unsafe1 = for { | ||
| 201 | axiom <- tbox | ||
| 202 | if axiom.isT5 | ||
| 203 | role1 <- axiom.objectPropertyExpressionsInSignature | ||
| 204 | roleSuper = | ||
| 205 | role1 +: reasoner | ||
| 206 | .superObjectProperties(role1) | ||
| 207 | .collect(Collectors.toList()) | ||
| 208 | .asScala | ||
| 209 | roleSuperInv = roleSuper.map(_.getInverseProperty) | ||
| 210 | axiom <- tbox | ||
| 211 | if axiom.isT3 && !axiom.isT3top | ||
| 212 | role2 <- axiom.objectPropertyExpressionsInSignature | ||
| 213 | if roleSuperInv.contains(role2) | ||
| 214 | } yield role1 | ||
| 215 | |||
| 216 | /* Checking for (2) unsafety condition: | ||
| 217 | * | ||
| 218 | * For all roles p1 appearing in an axiom of type T5, p1 is unsafe if | ||
| 219 | * there exists a role p2 appearing in an axiom of type T4 and p1 is a | ||
| 220 | * subproperty of either p2 or the inverse of p2. | ||
| 221 | * | ||
| 222 | */ | ||
| 223 | val unsafe2 = for { | ||
| 224 | axiom <- tbox | ||
| 225 | if axiom.isT5 | ||
| 226 | role1 <- axiom.objectPropertyExpressionsInSignature | ||
| 227 | roleSuper = | ||
| 228 | role1 +: reasoner | ||
| 229 | .superObjectProperties(role1) | ||
| 230 | .collect(Collectors.toList()) | ||
| 231 | .asScala | ||
| 232 | roleSuperInv = roleSuper.map(_.getInverseProperty) | ||
| 233 | axiom <- tbox | ||
| 234 | if axiom.isT4 | ||
| 235 | role2 <- axiom.objectPropertyExpressionsInSignature | ||
| 236 | if roleSuper.contains(role2) || roleSuperInv.contains(role2) | ||
| 237 | } yield role1 | ||
| 238 | |||
| 239 | (unsafe1 ++ unsafe2).toList | ||
| 240 | } | ||
| 241 | |||
| 242 | private def rsaGraph( | ||
| 243 | data: DataStoreConnection | ||
| 244 | ): Graph[Resource, UnDiEdge] = { | ||
| 245 | val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }" | ||
| 246 | val cursor = | ||
| 247 | data.createCursor(RSA.Prefixes, query, new HashMap[String, String]()); | ||
| 248 | var mul = cursor.open() | ||
| 249 | var edges: List[UnDiEdge[Resource]] = List() | ||
| 250 | while (mul > 0) { | ||
| 251 | edges = UnDiEdge(cursor.getResource(0), cursor.getResource(1)) :: edges | ||
| 252 | mul = cursor.advance() | ||
| 253 | } | ||
| 254 | Graph(edges: _*) | ||
| 255 | } | ||
| 256 | |||
| 257 | def filteringProgram( | ||
| 258 | query: SelectQuery, | ||
| 259 | nis: List[Term] | ||
| 260 | ): FilteringProgram = | ||
| 261 | new FilteringProgram(query, nis) | ||
| 262 | |||
| 263 | lazy val canonicalModel = new CanonicalModel(this) | ||
| 264 | |||
| 265 | // TODO: the following functions needs testing | ||
| 266 | def confl( | ||
| 267 | role: OWLObjectPropertyExpression | ||
| 268 | ): Set[OWLObjectPropertyExpression] = { | ||
| 269 | |||
| 270 | val invSuperRoles = reasoner | ||
| 271 | .superObjectProperties(role) | ||
| 272 | .collect(Collectors.toSet()) | ||
| 273 | .asScala | ||
| 274 | .addOne(role) | ||
| 275 | .map(_.getInverseProperty) | ||
| 276 | |||
| 277 | invSuperRoles | ||
| 278 | .flatMap(x => | ||
| 279 | reasoner | ||
| 280 | .subObjectProperties(x) | ||
| 281 | .collect(Collectors.toSet()) | ||
| 282 | .asScala | ||
| 283 | .addOne(x) | ||
| 284 | ) | ||
| 285 | .filterNot(_.isOWLBottomObjectProperty()) | ||
| 286 | .filterNot(_.getInverseProperty.isOWLTopObjectProperty()) | ||
| 287 | } | ||
| 288 | |||
| 289 | def self(axiom: OWLSubClassOfAxiom): Set[Term] = { | ||
| 290 | // Assuming just one role in the signature of a T5 axiom | ||
| 291 | val role = axiom.objectPropertyExpressionsInSignature(0) | ||
| 292 | if (this.confl(role).contains(role)) { | ||
| 293 | Set( | ||
| 294 | RSA.rsa("v0_" ++ RSA.hashed(axiom)), | ||
| 295 | RSA.rsa("v1_" ++ RSA.hashed(axiom)) | ||
| 296 | ) | ||
| 297 | } else { | ||
| 298 | Set() | ||
| 705 | } | 299 | } |
| 706 | } // implicit class RSAOntology | 300 | } |
| 301 | |||
| 302 | // def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { | ||
| 303 | // // Assuming just one role in the signature of a T5 axiom | ||
| 304 | // val roleR = axiom.objectPropertyExpressionsInSignature(0) | ||
| 305 | // val conflR = this.confl(roleR) | ||
| 306 | // // We just need the TBox to find | ||
| 307 | // val tbox = ontology | ||
| 308 | // .tboxAxioms(Imports.INCLUDED) | ||
| 309 | // .collect(Collectors.toSet()) | ||
| 310 | // .asScala | ||
| 311 | // for { | ||
| 312 | // axiom1 <- tbox | ||
| 313 | // // TODO: is this an optimization or an error? | ||
| 314 | // if axiom1.isT5 | ||
| 315 | // // We expect only one role coming out of a T5 axiom | ||
| 316 | // roleS <- axiom1.objectPropertyExpressionsInSignature | ||
| 317 | // // Triples ordering is among triples involving safe roles. | ||
| 318 | // if !unsafeRoles.contains(roleS) | ||
| 319 | // if conflR.contains(roleS) | ||
| 320 | // individual = | ||
| 321 | // if (axiom.hashCode < axiom1.hashCode) { | ||
| 322 | // RSA.rsa("v0_" ++ axiom1.hashCode.toString()) | ||
| 323 | // } else { | ||
| 324 | // RSA.rsa("v1_" ++ axiom1.hashCode.toString()) | ||
| 325 | // } | ||
| 326 | // } yield individual | ||
| 327 | // } | ||
| 328 | |||
| 329 | def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { | ||
| 330 | // TODO: we can actually use `toTriple` from `RSAAxiom` | ||
| 331 | val classes = | ||
| 332 | axiom.classesInSignature.collect(Collectors.toList()).asScala | ||
| 333 | val classA = classes(0) | ||
| 334 | val roleR = axiom | ||
| 335 | .objectPropertyExpressionsInSignature(0) | ||
| 336 | .asInstanceOf[OWLObjectProperty] | ||
| 337 | val classB = classes(1) | ||
| 338 | cycle_aux(classA, roleR, classB) | ||
| 339 | } | ||
| 340 | |||
| 341 | def cycle_aux( | ||
| 342 | classA: OWLClass, | ||
| 343 | roleR: OWLObjectProperty, | ||
| 344 | classB: OWLClass | ||
| 345 | ): Set[Term] = { | ||
| 346 | val conflR = this.confl(roleR) | ||
| 347 | val classes = ontology | ||
| 348 | .classesInSignature(Imports.INCLUDED) | ||
| 349 | .collect(Collectors.toSet()) | ||
| 350 | .asScala | ||
| 351 | for { | ||
| 352 | classD <- classes | ||
| 353 | roleS <- conflR | ||
| 354 | classC <- classes | ||
| 355 | // Keeping this check for now | ||
| 356 | if !unsafeRoles.contains(roleS) | ||
| 357 | tripleARB = RSA.hashed(classA, roleR, classB) | ||
| 358 | tripleDSC = RSA.hashed(classD, roleS, classC) | ||
| 359 | individual = | ||
| 360 | if (tripleARB > tripleDSC) { | ||
| 361 | RSA.rsa("v1_" ++ tripleDSC) | ||
| 362 | } else { | ||
| 363 | // Note that this is also the case for | ||
| 364 | // `tripleARB == tripleDSC` | ||
| 365 | RSA.rsa("v0_" ++ tripleDSC) | ||
| 366 | } | ||
| 367 | } yield individual | ||
| 368 | } | ||
| 369 | |||
| 370 | def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = | ||
| 371 | this.self(axiom) | this.cycle(axiom) | ||
| 707 | 372 | ||
| 708 | } // trait RSAOntology | 373 | } // implicit class RSAOntology |
diff --git a/src/test/scala/rsacomb/CanonicalModelSpec.scala b/src/test/scala/rsacomb/CanonicalModelSpec.scala index ef27a4f..cac40a3 100644 --- a/src/test/scala/rsacomb/CanonicalModelSpec.scala +++ b/src/test/scala/rsacomb/CanonicalModelSpec.scala | |||
| @@ -23,7 +23,7 @@ object Ontology1_CanonicalModelSpec { | |||
| 23 | val renderer = new DLSyntaxObjectRenderer() | 23 | val renderer = new DLSyntaxObjectRenderer() |
| 24 | 24 | ||
| 25 | val ontology_path: File = new File("examples/example1.ttl") | 25 | val ontology_path: File = new File("examples/example1.ttl") |
| 26 | val ontology: RSAOntology = RSA.loadOntology(ontology_path) | 26 | val ontology = RSAOntology(ontology_path) |
| 27 | val program = ontology.canonicalModel | 27 | val program = ontology.canonicalModel |
| 28 | 28 | ||
| 29 | val roleR = new OWLObjectPropertyImpl(RSA.base("R")) | 29 | val roleR = new OWLObjectPropertyImpl(RSA.base("R")) |
| @@ -87,7 +87,7 @@ class Ontology1_CanonicalModelSpec | |||
| 87 | 87 | ||
| 88 | renderer.render(AsubClassOfD) should "be converted into a single Rule" in { | 88 | renderer.render(AsubClassOfD) should "be converted into a single Rule" in { |
| 89 | val varX = Variable.create("X") | 89 | val varX = Variable.create("X") |
| 90 | val visitor = program.ProgramGenerator | 90 | val visitor = program.RuleGenerator |
| 91 | val rules = AsubClassOfD.accept(visitor) | 91 | val rules = AsubClassOfD.accept(visitor) |
| 92 | rules.loneElement shouldBe a[Rule] | 92 | rules.loneElement shouldBe a[Rule] |
| 93 | } | 93 | } |
| @@ -152,7 +152,7 @@ class Ontology1_CanonicalModelSpec | |||
| 152 | AsomeValuesFromSiC | 152 | AsomeValuesFromSiC |
| 153 | ) should "produce 1 rule" in { | 153 | ) should "produce 1 rule" in { |
| 154 | val varX = Variable.create("X") | 154 | val varX = Variable.create("X") |
| 155 | val visitor = program.ProgramGenerator | 155 | val visitor = program.RuleGenerator |
| 156 | val rules = AsomeValuesFromSiC.accept(visitor) | 156 | val rules = AsomeValuesFromSiC.accept(visitor) |
| 157 | rules should have length 1 | 157 | rules should have length 1 |
| 158 | } | 158 | } |
| @@ -175,7 +175,7 @@ class Ontology1_CanonicalModelSpec | |||
| 175 | // Rule 3 provides 48 rule (split in 2) | 175 | // Rule 3 provides 48 rule (split in 2) |
| 176 | // Then (1*2 + 48) + (0) + (48*2) = 146 | 176 | // Then (1*2 + 48) + (0) + (48*2) = 146 |
| 177 | val varX = Variable.create("X") | 177 | val varX = Variable.create("X") |
| 178 | val visitor = program.ProgramGenerator | 178 | val visitor = program.RuleGenerator |
| 179 | val rules = DsomeValuesFromRB.accept(visitor) | 179 | val rules = DsomeValuesFromRB.accept(visitor) |
| 180 | rules should have length 146 | 180 | rules should have length 146 |
| 181 | } | 181 | } |
| @@ -198,7 +198,7 @@ class Ontology1_CanonicalModelSpec | |||
| 198 | // Rule 3 provides 32 rule (split in 2) | 198 | // Rule 3 provides 32 rule (split in 2) |
| 199 | // Then (1*2 + 32) + (0) + (32*2) = 98 | 199 | // Then (1*2 + 32) + (0) + (32*2) = 98 |
| 200 | val varX = Variable.create("X") | 200 | val varX = Variable.create("X") |
| 201 | val visitor = program.ProgramGenerator | 201 | val visitor = program.RuleGenerator |
| 202 | val rules = DsomeValuesFromRB.accept(visitor) | 202 | val rules = DsomeValuesFromRB.accept(visitor) |
| 203 | rules should have length 146 | 203 | rules should have length 146 |
| 204 | } | 204 | } |
| @@ -207,7 +207,7 @@ class Ontology1_CanonicalModelSpec | |||
| 207 | SsubPropertyOfT | 207 | SsubPropertyOfT |
| 208 | ) should "produce 2 rules" in { | 208 | ) should "produce 2 rules" in { |
| 209 | val varX = Variable.create("X") | 209 | val varX = Variable.create("X") |
| 210 | val visitor = program.ProgramGenerator | 210 | val visitor = program.RuleGenerator |
| 211 | val rules = SsubPropertyOfT.accept(visitor) | 211 | val rules = SsubPropertyOfT.accept(visitor) |
| 212 | rules should have length 2 | 212 | rules should have length 2 |
| 213 | } | 213 | } |
| @@ -220,7 +220,7 @@ object Ontology2_CanonicalModelSpec { | |||
| 220 | val renderer = new DLSyntaxObjectRenderer() | 220 | val renderer = new DLSyntaxObjectRenderer() |
| 221 | 221 | ||
| 222 | val ontology_path: File = new File("examples/example2.owl") | 222 | val ontology_path: File = new File("examples/example2.owl") |
| 223 | val ontology: RSAOntology = RSA.loadOntology(ontology_path) | 223 | val ontology = RSAOntology(ontology_path) |
| 224 | val program = ontology.canonicalModel | 224 | val program = ontology.canonicalModel |
| 225 | 225 | ||
| 226 | val roleR = new OWLObjectPropertyImpl(RSA.base("R")) | 226 | val roleR = new OWLObjectPropertyImpl(RSA.base("R")) |
| @@ -326,7 +326,7 @@ class Ontology2_CanonicalModelSpec | |||
| 326 | renderer.render( | 326 | renderer.render( |
| 327 | AsomeValuesFromRB | 327 | AsomeValuesFromRB |
| 328 | ) should "produce 1 rule" in { | 328 | ) should "produce 1 rule" in { |
| 329 | val visitor = program.ProgramGenerator | 329 | val visitor = program.RuleGenerator |
| 330 | val rules = AsomeValuesFromRB.accept(visitor) | 330 | val rules = AsomeValuesFromRB.accept(visitor) |
| 331 | rules should have length 1 | 331 | rules should have length 1 |
| 332 | } | 332 | } |
| @@ -336,7 +336,7 @@ class Ontology2_CanonicalModelSpec | |||
| 336 | renderer.render( | 336 | renderer.render( |
| 337 | BsomeValuesFromSC | 337 | BsomeValuesFromSC |
| 338 | ) should "produce 1 rule" in { | 338 | ) should "produce 1 rule" in { |
| 339 | val visitor = program.ProgramGenerator | 339 | val visitor = program.RuleGenerator |
| 340 | val rules = BsomeValuesFromSC.accept(visitor) | 340 | val rules = BsomeValuesFromSC.accept(visitor) |
| 341 | rules should have length 1 | 341 | rules should have length 1 |
| 342 | } | 342 | } |
| @@ -346,7 +346,7 @@ class Ontology2_CanonicalModelSpec | |||
| 346 | renderer.render( | 346 | renderer.render( |
| 347 | CsomeValuesFromTD | 347 | CsomeValuesFromTD |
| 348 | ) should "produce 1 rule" in { | 348 | ) should "produce 1 rule" in { |
| 349 | val visitor = program.ProgramGenerator | 349 | val visitor = program.RuleGenerator |
| 350 | val rules = CsomeValuesFromTD.accept(visitor) | 350 | val rules = CsomeValuesFromTD.accept(visitor) |
| 351 | rules should have length 1 | 351 | rules should have length 1 |
| 352 | } | 352 | } |
| @@ -356,7 +356,7 @@ class Ontology2_CanonicalModelSpec | |||
| 356 | renderer.render( | 356 | renderer.render( |
| 357 | DsomeValuesFromPA | 357 | DsomeValuesFromPA |
| 358 | ) should "produce 1 rule" in { | 358 | ) should "produce 1 rule" in { |
| 359 | val visitor = program.ProgramGenerator | 359 | val visitor = program.RuleGenerator |
| 360 | val rules = DsomeValuesFromPA.accept(visitor) | 360 | val rules = DsomeValuesFromPA.accept(visitor) |
| 361 | rules should have length 1 | 361 | rules should have length 1 |
| 362 | } | 362 | } |
diff --git a/src/test/scala/rsacomb/FilteringProgramSpecs.scala b/src/test/scala/rsacomb/FilteringProgramSpecs.scala index 26b0857..79e675f 100644 --- a/src/test/scala/rsacomb/FilteringProgramSpecs.scala +++ b/src/test/scala/rsacomb/FilteringProgramSpecs.scala | |||
| @@ -283,7 +283,6 @@ object FilteringProgramSpec { | |||
| 283 | 283 | ||
| 284 | val queries = | 284 | val queries = |
| 285 | List(query0, query1, query2, query3, query4, query5, query6, query7) | 285 | List(query0, query1, query2, query3, query4, query5, query6, query7) |
| 286 | |||
| 287 | } | 286 | } |
| 288 | 287 | ||
| 289 | class FilteringProgramSpec | 288 | class FilteringProgramSpec |
