Skip to content

Commit 70d0488

Browse files
committed
Descend properties as needed.
1 parent 0dd7456 commit 70d0488

1 file changed

Lines changed: 33 additions & 40 deletions

File tree

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

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
package org.renci.relationgraph
22

3-
import java.io.{File, FileOutputStream, OutputStream}
4-
import java.lang.{Runtime => JRuntime}
5-
import java.nio.charset.StandardCharsets
6-
import java.security.MessageDigest
7-
import java.util.Base64
83
import caseapp._
94
import org.apache.jena.graph.{Node, NodeFactory, Triple}
105
import org.apache.jena.riot.RDFFormat
@@ -21,6 +16,11 @@ import zio._
2116
import zio.blocking._
2217
import zio.stream._
2318

19+
import java.io.{File, FileOutputStream, OutputStream}
20+
import java.lang.{Runtime => JRuntime}
21+
import java.nio.charset.StandardCharsets
22+
import java.security.MessageDigest
23+
import java.util.Base64
2424
import scala.io.Source
2525
import scala.jdk.CollectionConverters._
2626

@@ -33,7 +33,6 @@ object Main extends ZCaseApp[Config] {
3333
private val OWLOnProperty = OWL2.onProperty.asNode
3434
private val OWLSomeValuesFrom = OWL2.someValuesFrom.asNode
3535
private val OWLOntology = OWL2.Ontology.asNode
36-
private val df = OWLManager.getOWLDataFactory
3736

3837
override def run(config: Config, arg: RemainingArgs): ZIO[ZEnv, Nothing, ExitCode] = {
3938
val ontologyFile = new File(config.ontologyFile)
@@ -48,8 +47,8 @@ object Main extends ZCaseApp[Config] {
4847
val program = streamsManaged.use {
4948
case (nonredundantRDFWriter, redundantRDFWriter) =>
5049
for {
51-
fileProperties <- config.propertiesFile.map(readPropertiesFile).getOrElse(ZIO.succeed(Set.empty[OWLObjectProperty]))
52-
specifiedProperties = fileProperties ++ config.property.map(prop => df.getOWLObjectProperty(IRI.create(prop))).to(Set)
50+
fileProperties <- config.propertiesFile.map(readPropertiesFile).getOrElse(ZIO.succeed(Set.empty[AtomicConcept]))
51+
specifiedProperties = fileProperties ++ config.property.map(prop => AtomicConcept(prop)).to(Set)
5352
manager <- ZIO.effect(OWLManager.createOWLOntologyManager())
5453
ontology <- ZIO.effect(manager.loadOntologyFromOntologyDocument(ontologyFile))
5554
whelkOntology = Bridge.ontologyToAxioms(ontology)
@@ -68,8 +67,8 @@ object Main extends ZCaseApp[Config] {
6867
queue <- Queue.unbounded[Restriction]
6968
activeRestrictions <- Ref.make(0)
7069
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))
70+
_ <- traverse(specifiedProperties, properties, classes, queue, activeRestrictions, seenRef)
71+
restrictionsStream = Stream.fromQueue(queue).map(r => processRestrictionAndExtendQueue(r, properties, classes, whelk, config.mode, specifiedProperties.isEmpty, queue, activeRestrictions, seenRef))
7372
allTasks = classesTasks ++ restrictionsStream
7473
processed = allTasks.mapMParUnordered(JRuntime.getRuntime.availableProcessors)(identity)
7574
_ <- processed.foreach {
@@ -86,9 +85,9 @@ object Main extends ZCaseApp[Config] {
8685
program.exitCode
8786
}
8887

89-
def readPropertiesFile(file: String): ZIO[Blocking, Throwable, Set[OWLObjectProperty]] =
88+
def readPropertiesFile(file: String): ZIO[Blocking, Throwable, Set[AtomicConcept]] =
9089
effectBlocking(Source.fromFile(file, "utf-8")).bracketAuto { source =>
91-
effectBlocking(source.getLines().map(_.trim).filter(_.nonEmpty).map(line => df.getOWLObjectProperty(IRI.create(line))).to(Set))
90+
effectBlocking(source.getLines().map(_.trim).filter(_.nonEmpty).map(line => AtomicConcept(line)).to(Set))
9291
}
9392

9493
def createStreamRDF(output: OutputStream): Managed[Throwable, StreamRDF] =
@@ -102,27 +101,20 @@ object Main extends ZCaseApp[Config] {
102101

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

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)
104+
def traverse(specifiedProperties: Set[AtomicConcept], properties: Hierarchy, classes: Hierarchy, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[Unit] = {
105+
val descendProperties = specifiedProperties.isEmpty
106+
val queryProperties = if (descendProperties) properties.subclasses.getOrElse(Top, Set.empty) - Bottom else specifiedProperties
107+
ZIO.foreachPar_(queryProperties) { subprop =>
108+
traverseProperty(subprop, classes, queue, activeRestrictions, seenRef)
108109
}
109110
}
110111

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) {
114-
(classes.subclasses.getOrElse(Top, Set.empty) - Bottom).map(filler => Restriction(Role(property.id), filler))
115-
} else Set.empty[Restriction]
112+
def traverseProperty(property: AtomicConcept, classes: Hierarchy, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[Unit] = {
113+
val restrictions = (classes.subclasses.getOrElse(Top, Set.empty) - Bottom).map(filler => Restriction(Role(property.id), filler))
116114
for {
117-
subProperties <- seenRef.modify { seen =>
118-
val subProperties = properties.subclasses.getOrElse(property, Set.empty) - Bottom
115+
_ <- seenRef.update { seen =>
119116
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)
117+
seen.updated(property, seenForThisProperty)
126118
}
127119
_ <- activeRestrictions.update(current => current + restrictions.size)
128120
_ <- queue.offerAll(restrictions).unit
@@ -131,15 +123,7 @@ object Main extends ZCaseApp[Config] {
131123
} yield ()
132124
}
133125

134-
def hasSubClasses(property: AtomicConcept, whelk: ReasonerState): Boolean = {
135-
val queryConcept = AtomicConcept(s"${property.id}${Top.id}")
136-
val restriction = ExistentialRestriction(Role(property.id), Top)
137-
val axioms = Set(ConceptInclusion(queryConcept, restriction), ConceptInclusion(restriction, queryConcept))
138-
val updatedWhelk = Reasoner.assert(axioms, whelk)
139-
(updatedWhelk.closureSubsBySuperclass.getOrElse(queryConcept, Set.empty) - Bottom).nonEmpty
140-
}
141-
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] = {
126+
def processRestrictionAndExtendQueue(restriction: Restriction, properties: Hierarchy, classes: Hierarchy, whelk: ReasonerState, mode: Config.OutputMode, descendProperties: Boolean, queue: Queue[Restriction], activeRestrictions: Ref[Int], seenRef: Ref[Map[AtomicConcept, Set[AtomicConcept]]]): UIO[TriplesGroup] =
143127
for {
144128
triples <- ZIO.effectTotal(processRestriction(restriction, whelk, mode))
145129
directFillerSubclassesRestrictions <- if (triples.redundant.nonEmpty) seenRef.modify { seen =>
@@ -149,14 +133,23 @@ object Main extends ZCaseApp[Config] {
149133
val unseenSubClasses = subClasses -- seenForThisProperty
150134
val updatedSeen = seen.updated(propertyConcept, seenForThisProperty ++ subClasses)
151135
val newRestrictions = unseenSubClasses.map(c => Restriction(restriction.property, c))
152-
(newRestrictions, updatedSeen)
136+
if (descendProperties) {
137+
val subProperties = properties.subclasses.getOrElse(propertyConcept, Set.empty) - Bottom
138+
subProperties.foldLeft((newRestrictions, updatedSeen)) { case ((accRestrictions, accSeen), subProperty) =>
139+
val seenClassesForSubProperty = accSeen.getOrElse(subProperty, Set.empty)
140+
val updatedRestrictions = if (!seenClassesForSubProperty(restriction.filler))
141+
accRestrictions + Restriction(Role(subProperty.id), restriction.filler)
142+
else accRestrictions
143+
val updatedAccSeen = accSeen.updated(subProperty, seenClassesForSubProperty + restriction.filler)
144+
(updatedRestrictions, updatedAccSeen)
145+
}
146+
} else (newRestrictions, updatedSeen)
153147
} else ZIO.succeed(Set.empty[Restriction])
154148
_ <- activeRestrictions.update(current => current - 1 + directFillerSubclassesRestrictions.size)
155149
_ <- queue.offerAll(directFillerSubclassesRestrictions)
156150
active <- activeRestrictions.get
157151
_ <- queue.shutdown.when(active < 1)
158152
} yield triples
159-
}
160153

161154
def processRestriction(restriction: Restriction, whelk: ReasonerState, mode: Config.OutputMode): TriplesGroup = {
162155
val queryConcept = AtomicConcept(s"${restriction.property.id}${restriction.filler.id}")
@@ -201,7 +194,7 @@ object Main extends ZCaseApp[Config] {
201194
AtomicConcept(ax.getSubProperty.asOWLObjectProperty.getIRI.toString),
202195
AtomicConcept(ax.getSuperProperty.asOWLObjectProperty.getIRI.toString))
203196
}
204-
val allProps = ont.getObjectPropertiesInSignature((Imports.INCLUDED)).asScala.to(Set)
197+
val allProps = ont.getObjectPropertiesInSignature(Imports.INCLUDED).asScala.to(Set)
205198
.filterNot(_.isOWLTopObjectProperty)
206199
.map(prop =>
207200
ConceptInclusion(AtomicConcept(prop.getIRI.toString), AtomicConcept(prop.getIRI.toString)))

0 commit comments

Comments
 (0)