Skip to content

Commit 0dd7456

Browse files
committed
Fix traversal down property hierarchy. Keep track of already seen properties and classes.
1 parent 30d3c69 commit 0dd7456

1 file changed

Lines changed: 36 additions & 16 deletions

File tree

src/main/scala/org/renci/relationgraph/Main.scala

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ object Main extends ZCaseApp[Config] {
6767
classesTasks = classesStream.map(c => ZIO.effectTotal(processSuperclasses(c, whelk, config)))
6868
queue <- Queue.unbounded[Restriction]
6969
activeRestrictions <- Ref.make(0)
70-
_ <- traverse(properties, classes, whelk, config.mode, queue, activeRestrictions)
71-
restrictionsStream = Stream.fromQueue(queue).map(r => processRestrictionAndExtendQueue(r, classes, whelk, config.mode, queue, activeRestrictions))
70+
seenRef <- Ref.make(Map.empty[AtomicConcept, Set[AtomicConcept]])
71+
_ <- traverse(properties, classes, whelk, config.mode, queue, activeRestrictions, seenRef)
72+
restrictionsStream = Stream.fromQueue(queue).map(r => processRestrictionAndExtendQueue(r, classes, whelk, config.mode, queue, activeRestrictions, seenRef))
7273
allTasks = classesTasks ++ restrictionsStream
7374
processed = allTasks.mapMParUnordered(JRuntime.getRuntime.availableProcessors)(identity)
7475
_ <- processed.foreach {
@@ -101,22 +102,33 @@ object Main extends ZCaseApp[Config] {
101102

102103
def allClasses(ont: OWLOntology): ZStream[Any, Nothing, OWLClass] = Stream.fromIterable(ont.getClassesInSignature(Imports.INCLUDED).asScala.to(Set) - OWLThing - OWLNothing)
103104

104-
def traverse(properties: Hierarchy, classes: Hierarchy, reasoner: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int]): UIO[Unit] =
105-
ZIO.foreach_(properties.subclasses.getOrElse(Top, Set.empty)) { subprop =>
106-
traverseProperty(subprop, properties, classes, reasoner, mode, queue, activeRestrictions)
105+
def traverse(properties: Hierarchy, classes: Hierarchy, reasoner: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[Unit] = {
106+
ZIO.foreachPar_(properties.subclasses.getOrElse(Top, Set.empty) - Bottom) { subprop =>
107+
traverseProperty(subprop, properties, classes, reasoner, mode, queue, activeRestrictions, seenRef)
107108
}
109+
}
108110

109-
def traverseProperty(property: AtomicConcept, properties: Hierarchy, classes: Hierarchy, whelk: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int]): UIO[Unit] = {
110-
val restrictions = if (hasSubClasses(property, whelk)) {
111+
def traverseProperty(property: AtomicConcept, properties: Hierarchy, classes: Hierarchy, whelk: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[Unit] = {
112+
val propertyHasResults = hasSubClasses(property, whelk)
113+
val restrictions = if (propertyHasResults) {
111114
(classes.subclasses.getOrElse(Top, Set.empty) - Bottom).map(filler => Restriction(Role(property.id), filler))
112-
} else Set.empty
115+
} else Set.empty[Restriction]
113116
for {
117+
subProperties <- seenRef.modify { seen =>
118+
val subProperties = properties.subclasses.getOrElse(property, Set.empty) - Bottom
119+
val seenForThisProperty = seen.getOrElse(property, Set.empty) ++ restrictions.map(_.filler)
120+
val updatedSeen = seen.updated(property, seenForThisProperty)
121+
val unseenProperties = subProperties.filterNot(updatedSeen.keySet)
122+
(unseenProperties, updatedSeen ++ unseenProperties.map(p => p -> Set.empty[AtomicConcept]).toMap)
123+
}
124+
_ <- ZIO.foreachPar_(subProperties) { subProp =>
125+
traverseProperty(subProp, properties, classes, whelk, mode, queue, activeRestrictions, seenRef)
126+
}
114127
_ <- activeRestrictions.update(current => current + restrictions.size)
115128
_ <- queue.offerAll(restrictions).unit
116129
active <- activeRestrictions.get
117130
_ <- queue.shutdown.when(active < 1)
118131
} yield ()
119-
120132
}
121133

122134
def hasSubClasses(property: AtomicConcept, whelk: ReasonerState): Boolean = {
@@ -127,12 +139,18 @@ object Main extends ZCaseApp[Config] {
127139
(updatedWhelk.closureSubsBySuperclass.getOrElse(queryConcept, Set.empty) - Bottom).nonEmpty
128140
}
129141

130-
def processRestrictionAndExtendQueue(restriction: Restriction, classes: Hierarchy, whelk: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int]): UIO[TriplesGroup] = {
142+
def processRestrictionAndExtendQueue(restriction: Restriction, classes: Hierarchy, whelk: ReasonerState, mode: Config.OutputMode, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[TriplesGroup] = {
131143
for {
132144
triples <- ZIO.effectTotal(processRestriction(restriction, whelk, mode))
133-
directFillerSubclassesRestrictions = if (triples.redundant.nonEmpty)
134-
(classes.subclasses.getOrElse(restriction.filler, Set.empty) - Bottom).map(c => Restriction(restriction.property, c))
135-
else Set.empty
145+
directFillerSubclassesRestrictions <- if (triples.redundant.nonEmpty) seenRef.modify { seen =>
146+
val propertyConcept = AtomicConcept(restriction.property.id)
147+
val seenForThisProperty = seen.getOrElse(propertyConcept, Set.empty)
148+
val subClasses = classes.subclasses.getOrElse(restriction.filler, Set.empty) - Bottom
149+
val unseenSubClasses = subClasses -- seenForThisProperty
150+
val updatedSeen = seen.updated(propertyConcept, seenForThisProperty ++ subClasses)
151+
val newRestrictions = unseenSubClasses.map(c => Restriction(restriction.property, c))
152+
(newRestrictions, updatedSeen)
153+
} else ZIO.succeed(Set.empty[Restriction])
136154
_ <- activeRestrictions.update(current => current - 1 + directFillerSubclassesRestrictions.size)
137155
_ <- queue.offerAll(directFillerSubclassesRestrictions)
138156
active <- activeRestrictions.get
@@ -179,12 +197,14 @@ object Main extends ZCaseApp[Config] {
179197

180198
def propertyHierarchy(ont: OWLOntology): Hierarchy = {
181199
val subPropAxioms = ont.getAxioms(AxiomType.SUB_OBJECT_PROPERTY).asScala.to(Set).collect {
182-
case ax if ax.getSubProperty.isNamed && ax.getSuperProperty.isNamed => ConceptInclusion(
200+
case ax if ax.getSubProperty.isNamed && ax.getSuperProperty.isNamed && !ax.getSuperProperty.isOWLTopObjectProperty => ConceptInclusion(
183201
AtomicConcept(ax.getSubProperty.asOWLObjectProperty.getIRI.toString),
184202
AtomicConcept(ax.getSuperProperty.asOWLObjectProperty.getIRI.toString))
185203
}
186-
val allProps = ont.getObjectPropertiesInSignature((Imports.INCLUDED)).asScala.to(Set).map(prop =>
187-
ConceptInclusion(AtomicConcept(prop.getIRI.toString), AtomicConcept(prop.getIRI.toString)))
204+
val allProps = ont.getObjectPropertiesInSignature((Imports.INCLUDED)).asScala.to(Set)
205+
.filterNot(_.isOWLTopObjectProperty)
206+
.map(prop =>
207+
ConceptInclusion(AtomicConcept(prop.getIRI.toString), AtomicConcept(prop.getIRI.toString)))
188208
val allAxioms = (subPropAxioms ++ allProps).toSet[Axiom]
189209
val whelk = Reasoner.assert(allAxioms)
190210
classHierarchy(whelk)

0 commit comments

Comments
 (0)