diff options
| author | Federico Igne <git@federicoigne.com> | 2021-07-27 12:52:48 +0100 |
|---|---|---|
| committer | Federico Igne <git@federicoigne.com> | 2021-07-27 12:52:48 +0100 |
| commit | 30b199205f3a16cc92577393ddf9b5d7b36d9dc3 (patch) | |
| tree | 3cb94f148a2bfb206c9481e723141a28cfcc310a | |
| parent | d017662e2d65ec72e7decde3b76591c198da9819 (diff) | |
| download | RSAComb-30b199205f3a16cc92577393ddf9b5d7b36d9dc3.tar.gz RSAComb-30b199205f3a16cc92577393ddf9b5d7b36d9dc3.zip | |
Add skeleton for upperbound computation
| -rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala new file mode 100644 index 0000000..ba26113 --- /dev/null +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/Upperbound.scala | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | package uk.ac.ox.cs.rsacomb.approximation | ||
| 2 | |||
| 3 | // import java.io.File | ||
| 4 | |||
| 5 | import org.semanticweb.owlapi.apibinding.OWLManager | ||
| 6 | import org.semanticweb.owlapi.model.{IRI => _, _} | ||
| 7 | |||
| 8 | // import tech.oxfordsemantic.jrdfox.logic.expression.{Resource, IRI} | ||
| 9 | |||
| 10 | // import scala.collection.mutable.{Set, Map} | ||
| 11 | // import scalax.collection.Graph | ||
| 12 | // import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._ | ||
| 13 | // import scalax.collection.GraphTraversal._ | ||
| 14 | |||
| 15 | import uk.ac.ox.cs.rsacomb.RSAOntology | ||
| 16 | // import uk.ac.ox.cs.rsacomb.RSAUtil | ||
| 17 | import uk.ac.ox.cs.rsacomb.ontology.Ontology | ||
| 18 | |||
| 19 | object UpperBound { | ||
| 20 | |||
| 21 | private val manager = OWLManager.createOWLOntologyManager() | ||
| 22 | private val factory = manager.getOWLDataFactory() | ||
| 23 | |||
| 24 | } | ||
| 25 | |||
| 26 | /** Approximation algorithm that mantains completeness for CQ answering. | ||
| 27 | * | ||
| 28 | * The input OWL 2 ontology is assumed to be normalized and the output | ||
| 29 | * ontology is guaranteed to be in RSA. | ||
| 30 | * | ||
| 31 | * The algorithm is performed in three steps: | ||
| 32 | * 1. the ontology is reduced to ALCHOIQ by discarding any axiom | ||
| 33 | * that is not in the language; | ||
| 34 | * 2. the ontology is further reduced to Horn-ALCHOIQ by shifting | ||
| 35 | * axioms with disjunction on the rhs; | ||
| 36 | * 3. the ontology is approximated to RSA by manipulating its | ||
| 37 | * dependency graph. | ||
| 38 | * | ||
| 39 | * @see [[uk.ac.ox.cs.rsacomb.converter.Normalizer]] | ||
| 40 | */ | ||
| 41 | class UpperBound extends Approximation[RSAOntology] { | ||
| 42 | |||
| 43 | /** Simplify conversion between Java and Scala collections */ | ||
| 44 | import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ | ||
| 45 | |||
| 46 | /** Simplify conversion between OWLAPI and RDFox concepts */ | ||
| 47 | // import uk.ac.ox.cs.rsacomb.implicits.RDFox._ | ||
| 48 | |||
| 49 | /** Main entry point for the approximation algorithm */ | ||
| 50 | def approximate(ontology: Ontology): RSAOntology = | ||
| 51 | toRSA( | ||
| 52 | new Ontology( | ||
| 53 | ontology.axioms filter inALCHOIQ flatMap toConjuncts, | ||
| 54 | ontology.datafiles | ||
| 55 | ) | ||
| 56 | ) | ||
| 57 | |||
| 58 | /** Discards all axioms outside ALCHOIQ */ | ||
| 59 | private def inALCHOIQ(axiom: OWLLogicalAxiom): Boolean = | ||
| 60 | axiom match { | ||
| 61 | case a: OWLSubClassOfAxiom => { | ||
| 62 | val sub = a.getSubClass.getNNF | ||
| 63 | val sup = a.getSuperClass.getNNF | ||
| 64 | (sub, sup) match { | ||
| 65 | case (sub: OWLObjectAllValuesFrom, _) => false | ||
| 66 | case (sub: OWLDataAllValuesFrom, _) => false | ||
| 67 | case (_, sup: OWLDataAllValuesFrom) => false | ||
| 68 | case (sub: OWLObjectMinCardinality, _) if sub.getCardinality >= 2 => | ||
| 69 | false | ||
| 70 | case (sub: OWLDataMinCardinality, _) if sub.getCardinality >= 2 => | ||
| 71 | false | ||
| 72 | case (_, sup: OWLObjectMinCardinality) if sup.getCardinality >= 2 => | ||
| 73 | false | ||
| 74 | case (_, sup: OWLDataMinCardinality) if sup.getCardinality >= 2 => | ||
| 75 | false | ||
| 76 | case (sub: OWLObjectMaxCardinality, _) => false | ||
| 77 | case (sub: OWLDataMaxCardinality, _) => false | ||
| 78 | case (_, sup: OWLObjectMaxCardinality) if sup.getCardinality >= 2 => | ||
| 79 | false | ||
| 80 | case (_, sup: OWLDataMaxCardinality) if sup.getCardinality >= 1 => | ||
| 81 | false | ||
| 82 | case (_, sup: OWLObjectOneOf) if sup.getIndividuals.length > 2 => | ||
| 83 | false | ||
| 84 | case (sub: OWLObjectHasSelf, _) => false | ||
| 85 | case (_, sup: OWLObjectHasSelf) => false | ||
| 86 | case _ => true | ||
| 87 | } | ||
| 88 | } | ||
| 89 | case a: OWLTransitiveObjectPropertyAxiom => false | ||
| 90 | case a: OWLReflexiveObjectPropertyAxiom => false | ||
| 91 | case a: OWLSubPropertyChainOfAxiom => false | ||
| 92 | case a: OWLAsymmetricObjectPropertyAxiom => false | ||
| 93 | case a => true | ||
| 94 | } | ||
| 95 | |||
| 96 | /** Turn disjuncts into conjuncts | ||
| 97 | * | ||
| 98 | * This is a very naive way of getting rid of disjunction preserving | ||
| 99 | * completeness of CQ answering. | ||
| 100 | * | ||
| 101 | * @todo implement a choice function that decides which disjunct to | ||
| 102 | * keep instead of keeping all of them. Note that PAGOdA is currently | ||
| 103 | * doing something similar. | ||
| 104 | */ | ||
| 105 | private def toConjuncts(axiom: OWLLogicalAxiom): List[OWLLogicalAxiom] = | ||
| 106 | axiom match { | ||
| 107 | case a: OWLSubClassOfAxiom => { | ||
| 108 | val sub = a.getSubClass.getNNF | ||
| 109 | val sup = a.getSuperClass.getNNF | ||
| 110 | sup match { | ||
| 111 | case sup: OWLObjectUnionOf => | ||
| 112 | sup.asDisjunctSet.map( | ||
| 113 | UpperBound.factory.getOWLSubClassOfAxiom(sub, _) | ||
| 114 | ) | ||
| 115 | case _ => List(axiom) | ||
| 116 | } | ||
| 117 | } | ||
| 118 | case _ => List(axiom) | ||
| 119 | } | ||
| 120 | |||
| 121 | // /** Approximate a Horn-ALCHOIQ ontology to RSA | ||
| 122 | // * | ||
| 123 | // * This is done by gathering those axioms that prevent the ontology | ||
| 124 | // * dependency graph from being tree-shaped, and removing them. | ||
| 125 | // * | ||
| 126 | // * @param ontology the set of axioms to approximate. | ||
| 127 | // * @return the approximated RSA ontology | ||
| 128 | // */ | ||
| 129 | // private def toRSA(ontology: Ontology): RSAOntology = { | ||
| 130 | // /* Compute the dependency graph for the ontology */ | ||
| 131 | // val (graph, nodemap) = ontology.dependencyGraph | ||
| 132 | |||
| 133 | // /* Define node colors for the graph visit */ | ||
| 134 | // sealed trait NodeColor | ||
| 135 | // case object Unvisited extends NodeColor | ||
| 136 | // case object Visited extends NodeColor | ||
| 137 | // case object ToDelete extends NodeColor | ||
| 138 | |||
| 139 | // /* Keep track of node colors during graph visit */ | ||
| 140 | // var color = Map.from[Resource, NodeColor]( | ||
| 141 | // graph.nodes.toOuter.map(k => (k, Unvisited)) | ||
| 142 | // ) | ||
| 143 | |||
| 144 | // for { | ||
| 145 | // component <- graph.componentTraverser().map(_ to Graph) | ||
| 146 | // edge <- component | ||
| 147 | // .outerEdgeTraverser(component.nodes.head) | ||
| 148 | // .withKind(BreadthFirst) | ||
| 149 | // } yield { | ||
| 150 | // val source = edge._1 | ||
| 151 | // val target = edge._2 | ||
| 152 | // color(source) match { | ||
| 153 | // case Unvisited | Visited => { | ||
| 154 | // color(target) match { | ||
| 155 | // case Unvisited => | ||
| 156 | // color(source) = Visited; | ||
| 157 | // color(target) = Visited | ||
| 158 | // case Visited => | ||
| 159 | // color(source) = ToDelete | ||
| 160 | // case ToDelete => | ||
| 161 | // color(source) = Visited | ||
| 162 | // } | ||
| 163 | // } | ||
| 164 | // case ToDelete => | ||
| 165 | // } | ||
| 166 | // } | ||
| 167 | |||
| 168 | // val toDelete = color.collect { case (resource: IRI, ToDelete) => | ||
| 169 | // nodemap(resource.getIRI) | ||
| 170 | // }.toList | ||
| 171 | |||
| 172 | // /* Remove axioms from approximated ontology */ | ||
| 173 | // RSAOntology(ontology.axioms diff toDelete, ontology.datafiles) | ||
| 174 | // } | ||
| 175 | |||
| 176 | // val edges1 = Seq('A ~> 'B, 'B ~> 'C, 'C ~> 'D, 'D ~> 'H, 'H ~> | ||
| 177 | // 'G, 'G ~> 'F, 'E ~> 'A, 'E ~> 'F, 'B ~> 'E, 'F ~> 'G, 'B ~> 'F, | ||
| 178 | // 'C ~> 'G, 'D ~> 'C, 'H ~> 'D) | ||
| 179 | // val edges2 = Seq('I ~> 'M, 'I ~> 'L, 'L ~> 'N, 'M ~> 'N) | ||
| 180 | // val edges3 = Seq('P ~> 'O) | ||
| 181 | // val graph = Graph.from(edges = edges1 ++ edges2 ++ edges3) | ||
| 182 | // | ||
| 183 | } | ||
