aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2021-04-05 13:14:00 +0100
committerFederico Igne <federico.igne@cs.ox.ac.uk>2021-04-05 13:14:00 +0100
commitb622e151905d9a3b8fff14748cc840696dc85f16 (patch)
treebed37dc1243d7f6926560ff7fed0a10d943a875a
parent4879515113b2bc107ee0e35ad164de42f6c0d059 (diff)
downloadRSAComb-b622e151905d9a3b8fff14748cc840696dc85f16.tar.gz
RSAComb-b622e151905d9a3b8fff14748cc840696dc85f16.zip
Add shifting for disjunction in the rhs of an axiom
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/converter/Normalizer.scala58
-rw-r--r--src/test/scala/uk/ac/ox/cs/rsacomb/converter/NormalizerSpec.scala21
2 files changed, 77 insertions, 2 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/Normalizer.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/Normalizer.scala
index a771e3d..fe81312 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/converter/Normalizer.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/converter/Normalizer.scala
@@ -31,6 +31,10 @@ class Normalizer() {
31 factory.getOWLClass(s"X$counter") 31 factory.getOWLClass(s"X$counter")
32 } 32 }
33 33
34 /** Statistics */
35 private var discarted = 0
36 private var shifted = 0
37
34 /** Normalizes a 38 /** Normalizes a
35 * [[org.semanticweb.owlapi.model.OWLLogicalAxiom OWLLogicalAxiom]] 39 * [[org.semanticweb.owlapi.model.OWLLogicalAxiom OWLLogicalAxiom]]
36 * 40 *
@@ -122,8 +126,12 @@ class Normalizer() {
122 ) 126 )
123 } 127 }
124 } 128 }
125 /** Disjunction on the rhs is not supported */ 129 /** Disjunction on the rhs is not supported directly
126 case (_, sup: OWLObjectUnionOf) => notInHornALCHOIQ(a) 130 *
131 * Instead we `shift` the rule to eliminate the disjunction.
132 */
133 case (_, sup: OWLObjectUnionOf) =>
134 shift(sub, sup) flatMap normalize
127 /** Complex class expression on existential restriction on the lhs 135 /** Complex class expression on existential restriction on the lhs
128 * 136 *
129 * exists R . C c D -> { C c X, exists R . X c D } 137 * exists R . C c D -> { C c X, exists R . X c D }
@@ -515,6 +523,50 @@ class Normalizer() {
515 case a => Seq(a) 523 case a => Seq(a)
516 } 524 }
517 525
526 /** Shift an axiom with disjunction on the rhs */
527 private def shift(
528 sub: OWLClassExpression,
529 sup: OWLObjectUnionOf
530 ): Seq[OWLLogicalAxiom] = {
531 val body = sub.asConjunctSet.map((atom) => (atom, freshOWLClass()))
532 val head = sup.asDisjunctSet.map((atom) => (atom, freshOWLClass()))
533
534 /* Update statistics */
535 shifted += 1
536
537 val r1 =
538 factory.getOWLSubClassOfAxiom(
539 factory.getOWLObjectIntersectionOf(
540 (body.map(_._1) ++ head.map(_._2)): _*
541 ),
542 factory.getOWLNothing
543 )
544
545 val r2s =
546 for {
547 (a, na) <- head
548 hs = head.map(_._2).filterNot(_ equals na)
549 } yield factory.getOWLSubClassOfAxiom(
550 factory.getOWLObjectIntersectionOf(
551 (body.map(_._1) ++ hs): _*
552 ),
553 a
554 )
555
556 val r3s =
557 for {
558 (a, na) <- body
559 bs = body.map(_._1).filterNot(_ equals a)
560 } yield factory.getOWLSubClassOfAxiom(
561 factory.getOWLObjectIntersectionOf(
562 (bs ++ head.map(_._2)): _*
563 ),
564 na
565 )
566
567 Seq(r1) ++ r2s ++ r3s
568 }
569
518 /** Approximation function for axioms out of Horn-ALCHOIQ 570 /** Approximation function for axioms out of Horn-ALCHOIQ
519 * 571 *
520 * By default discards the axiom, which guarantees a lower bound 572 * By default discards the axiom, which guarantees a lower bound
@@ -523,6 +575,8 @@ class Normalizer() {
523 protected def notInHornALCHOIQ( 575 protected def notInHornALCHOIQ(
524 axiom: OWLLogicalAxiom 576 axiom: OWLLogicalAxiom
525 ): Seq[OWLLogicalAxiom] = { 577 ): Seq[OWLLogicalAxiom] = {
578 /* Update statistics */
579 discarted += 1
526 Logger print s"'$axiom' has been ignored because it is not in Horn-ALCHOIQ" 580 Logger print s"'$axiom' has been ignored because it is not in Horn-ALCHOIQ"
527 Seq() 581 Seq()
528 } 582 }
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/converter/NormalizerSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/converter/NormalizerSpec.scala
index 3a686c0..7f0f720 100644
--- a/src/test/scala/uk/ac/ox/cs/rsacomb/converter/NormalizerSpec.scala
+++ b/src/test/scala/uk/ac/ox/cs/rsacomb/converter/NormalizerSpec.scala
@@ -73,6 +73,27 @@ class NormalizerSpec extends AnyFlatSpec with Matchers with LoneElement {
73 ).flatMap(normalizer.normalize) 73 ).flatMap(normalizer.normalize)
74 } 74 }
75 75
76 "Disjunction on the rhs" should "be shifted" in {
77 def cls(n: Int) = factory.getOWLClass(s"_:class$n")
78 val axiom1 =
79 factory.getOWLSubClassOfAxiom(
80 factory.getOWLObjectIntersectionOf(cls(1), cls(2), cls(3)),
81 factory.getOWLObjectUnionOf(cls(4), cls(5))
82 )
83 val axiom2 =
84 factory.getOWLSubClassOfAxiom(
85 cls(1),
86 factory.getOWLObjectUnionOf(cls(2), cls(3), cls(4))
87 )
88 val axiom3 =
89 factory.getOWLSubClassOfAxiom(
90 factory.getOWLObjectIntersectionOf(cls(1), cls(2), cls(3)),
91 factory.getOWLObjectUnionOf(cls(4))
92 )
93 normalizer.normalize(axiom1) should have length 5
94 normalizer.normalize(axiom2) should have length 5
95 normalizer.normalize(axiom3) should have length 4
96 }
76 //"A class name" should "be converted into a single atom" in { 97 //"A class name" should "be converted into a single atom" in {
77 // val cls = factory.getOWLClass(iriString0) 98 // val cls = factory.getOWLClass(iriString0)
78 // val atom = TupleTableAtom.rdf(term0, IRI.RDF_TYPE, IRI.create(iriString0)) 99 // val atom = TupleTableAtom.rdf(term0, IRI.RDF_TYPE, IRI.create(iriString0))