diff options
| author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-17 14:19:08 +0000 |
|---|---|---|
| committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-11-17 14:19:08 +0000 |
| commit | e1a04294ed8737444e40323474f4084cb64c1d55 (patch) | |
| tree | f3464a10152e7df6b7831f11e3d355b34dec1a2c /src/main/scala/rsacomb/CanonicalModel.scala | |
| parent | e6c211b6a9c497b625710f7b97f793d1a796b461 (diff) | |
| download | RSAComb-e1a04294ed8737444e40323474f4084cb64c1d55.tar.gz RSAComb-e1a04294ed8737444e40323474f4084cb64c1d55.zip | |
Remove implicit RSAOntology conversion
This was causing problems without giving any significant advantage. Now
it will be easier to refactor classes like RSA, RSAOntology,
CanonicalModel.
Diffstat (limited to 'src/main/scala/rsacomb/CanonicalModel.scala')
| -rw-r--r-- | src/main/scala/rsacomb/CanonicalModel.scala | 292 |
1 files changed, 292 insertions, 0 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 | } | ||
