Skip to content

Commit

Permalink
Implement arbitrary length property chains.
Browse files Browse the repository at this point in the history
  • Loading branch information
balhoff committed Jun 17, 2021
1 parent 2488f7a commit 40a4f32
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package org.geneontology.whelk

sealed trait QueueExpression

sealed trait Entity
sealed trait Entity {

def id: String

}

trait HasSignature {

Expand All @@ -20,6 +24,8 @@ object Role {

def apply(id: String): Role = new Role(id.intern())

val CompositionRolePrefix: String = "http://whelk.geneontology.org/composition_role/"

}

final case class DataRole(id: String) extends Entity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ final case class ReasonerState(

def roleAssertions: Set[RoleAssertion] = (for {
(Nominal(target), links) <- linksByTarget
(role, subjects) <- links
(role, subjects) <- links.view.filterKeys(!_.id.startsWith(Role.CompositionRolePrefix))
Nominal(subject) <- subjects
} yield RoleAssertion(role, subject, target)).toSet

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.geneontology.archimedes.owl.OWLVocabulary._
import org.geneontology.archimedes.owl.{Atom => SWRLAtom, Axiom => OWLAxiom, DataHasValue => OWLDataHasValue, NamedIndividual => OWLNamedIndividual, Variable => OWLVariable, _}
import org.geneontology.archimedes.util.Lists.PluralList
import org.geneontology.whelk.BuiltIn._
import org.geneontology.whelk.Role.CompositionRolePrefix
import org.geneontology.whelk._

import scala.annotation.tailrec
Expand All @@ -13,41 +14,41 @@ object Bridge {
def ontologyToAxioms(ont: Ontology): Set[Axiom] = ont.axioms.flatMap(convertAxiom)

def convertAxiom(owlAxiom: OWLAxiom): Set[Axiom] = owlAxiom match {
case SubClassOf(subclass, superclass, _) => (convertExpression(subclass), convertExpression(superclass)) match {
case SubClassOf(subclass, superclass, _) => (convertExpression(subclass), convertExpression(superclass)) match {
case (Some(subConcept), Some(superConcept)) => Set(ConceptInclusion(subConcept, superConcept))
case _ => Set.empty
}
case EquivalentClasses(operands, _) =>
case EquivalentClasses(operands, _) =>
val converted = operands.items.map(convertExpression).toList.collect { case Some(concept) => concept }
converted.combinations(2).flatMap {
case first :: second :: Nil => Set(ConceptInclusion(first, second), ConceptInclusion(second, first))
case _ => Set.empty //impossible
}.toSet
case DisjointClasses(operands, _) if operands.items.size == 2 => //FIXME handle >2
case DisjointClasses(operands, _) if operands.items.size == 2 => //FIXME handle >2
val converted = operands.items.map(convertExpression).toList.collect { case Some(concept) => concept }
converted.combinations(2).flatMap {
case first :: second :: Nil => Set(ConceptInclusion(Conjunction(first, second), Bottom))
case _ => Set.empty //impossible
}.toSet
case ClassAssertion(cls, OWLNamedIndividual(iri), _) => convertExpression(cls).map(concept =>
case ClassAssertion(cls, OWLNamedIndividual(iri), _) => convertExpression(cls).map(concept =>
ConceptInclusion(Nominal(Individual(iri.id)), concept)).toSet
case ObjectPropertyAssertion(ObjectProperty(prop), OWLNamedIndividual(subj), OWLNamedIndividual(obj), _) =>
case ObjectPropertyAssertion(ObjectProperty(prop), OWLNamedIndividual(subj), OWLNamedIndividual(obj), _) =>
Set(ConceptInclusion(Nominal(Individual(subj.id)), ExistentialRestriction(Role(prop.id), Nominal(Individual(obj.id)))))
case ObjectPropertyAssertion(ObjectInverseOf(ObjectProperty(prop)), OWLNamedIndividual(obj), OWLNamedIndividual(subj), _) =>
case ObjectPropertyAssertion(ObjectInverseOf(ObjectProperty(prop)), OWLNamedIndividual(obj), OWLNamedIndividual(subj), _) =>
Set(ConceptInclusion(Nominal(Individual(subj.id)), ExistentialRestriction(Role(prop.id), Nominal(Individual(obj.id)))))
case EquivalentObjectProperties(propertyExpressions, _) =>
case EquivalentObjectProperties(propertyExpressions, _) =>
val properties = propertyExpressions.items.collect { case p @ ObjectProperty(_) => p }.toList
properties.combinations(2).flatMap {
case ObjectProperty(first) :: ObjectProperty(second) :: Nil => Set(RoleInclusion(Role(first.id), Role(second.id)))
case _ => Set.empty //impossible
}.toSet
case SubObjectPropertyOf(ObjectProperty(subproperty), ObjectProperty(superproperty), _) =>
case SubObjectPropertyOf(ObjectProperty(subproperty), ObjectProperty(superproperty), _) =>
val sub = Role(subproperty.id)
val sup = Role(superproperty.id)
Set(
RoleInclusion(sub, sup),
Rule(List(RoleAtom(sub, Variable("x1"), Variable("x2"))), List(RoleAtom(sup, Variable("x1"), Variable("x2")))))
case SubObjectPropertyOf(ObjectPropertyChain(PluralList(ObjectProperty(first), ObjectProperty(second), Nil)), ObjectProperty(superproperty), _) => //FIXME handle >2
case SubObjectPropertyOf(ObjectPropertyChain(PluralList(ObjectProperty(first), ObjectProperty(second), Nil)), ObjectProperty(superproperty), _) =>
val supRole = Role(superproperty.id)

def makeSubject(level: Int): Variable = if (level == 0) Variable("x") else Variable(s"x$level")
Expand All @@ -62,30 +63,34 @@ object Bridge {
Set(
RoleComposition(Role(first.id), Role(second.id), supRole),
Rule(body = atoms, head = List(RoleAtom(supRole, start, end))))
case TransitiveObjectProperty(ObjectProperty(property), _) =>
case SubObjectPropertyOf(ObjectPropertyChain(PluralList(first @ ObjectProperty(_), second @ ObjectProperty(_), (third @ ObjectProperty(_)) :: rest)), superproperty @ ObjectProperty(_), _) =>
val compositionProperty = ObjectProperty(IRI(s"$CompositionRolePrefix${first.iri.id}${second.iri.id}"))
convertAxiom(SubObjectPropertyOf(ObjectPropertyChain(PluralList(first, second, Nil)), compositionProperty)) ++
convertAxiom(SubObjectPropertyOf(ObjectPropertyChain(PluralList(compositionProperty, third, rest)), superproperty))
case TransitiveObjectProperty(ObjectProperty(property), _) =>
val role = Role(property.id)
Set(
RoleComposition(role, role, role),
Rule(body = List(RoleAtom(role, Variable("x1"), Variable("x2")), RoleAtom(role, Variable("x2"), Variable("x3"))), head = List(RoleAtom(role, Variable("x1"), Variable("x3")))))
case ReflexiveObjectProperty(ObjectProperty(property), _) => Set(
case ReflexiveObjectProperty(ObjectProperty(property), _) => Set(
ConceptInclusion(Top, SelfRestriction(Role(property.id)))
)
case ObjectPropertyDomain(ObjectProperty(property), ce, _) => convertExpression(ce).map(concept =>
case ObjectPropertyDomain(ObjectProperty(property), ce, _) => convertExpression(ce).map(concept =>
ConceptInclusion(ExistentialRestriction(Role(property.id), Top), concept)).toSet
case ObjectPropertyRange(ObjectProperty(property), ce, _) => convertExpression(ce).map(concept =>
case ObjectPropertyRange(ObjectProperty(property), ce, _) => convertExpression(ce).map(concept =>
//TODO only supporting in rules for now
Rule(body = List(RoleAtom(Role(property.id), Variable("x1"), Variable("x2"))), head = List(ConceptAtom(concept, Variable("x2"))))).toSet
case InverseObjectProperties(ObjectProperty(p), ObjectProperty(q), _) =>
case InverseObjectProperties(ObjectProperty(p), ObjectProperty(q), _) =>
val (roleP, roleQ) = (Role(p.id), Role(q.id))
val (x1, x2) = (Variable("x1"), Variable("x2"))
Set(
Rule(body = List(RoleAtom(roleP, x1, x2)), head = List(RoleAtom(roleQ, x2, x1))),
Rule(body = List(RoleAtom(roleQ, x1, x2)), head = List(RoleAtom(roleP, x2, x1))))
case DLSafeRule(body, head, _) => (for {
case DLSafeRule(body, head, _) => (for {
bodyAtoms <- convertAtomSet(body)
headAtoms <- convertAtomSet(head)
} yield Rule(bodyAtoms, headAtoms)).toSet
case _ =>
case _ =>
//println(s"Not supported: $other")
Set.empty
}
Expand Down
37 changes: 21 additions & 16 deletions modules/owlapi/src/main/scala/org/geneontology/whelk/Bridge.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.geneontology.whelk

import org.geneontology.whelk.BuiltIn._
import org.geneontology.whelk.Role.CompositionRolePrefix
import org.geneontology.whelk.owlapi.SWRLUtil
import org.geneontology.whelk.{Individual => WIndividual, Variable => WVariable}
import org.phenoscape.scowl._
Expand All @@ -21,41 +22,41 @@ object Bridge {
def ontologyToAxioms(ont: OWLOntology): Set[Axiom] = ont.getAxioms(Imports.INCLUDED).asScala.flatMap(convertAxiom).toSet

def convertAxiom(owlAxiom: OWLAxiom): Set[Axiom] = owlAxiom match {
case SubClassOf(_, subclass, superclass) => (convertExpression(subclass), convertExpression(superclass)) match {
case SubClassOf(_, subclass, superclass) => (convertExpression(subclass), convertExpression(superclass)) match {
case (Some(subConcept), Some(superConcept)) => Set(ConceptInclusion(subConcept, superConcept))
case _ => Set.empty
}
case EquivalentClasses(_, operands) =>
case EquivalentClasses(_, operands) =>
val converted = operands.map(convertExpression).toList.collect { case Some(concept) => concept }
converted.combinations(2).flatMap {
case first :: second :: Nil => Set(ConceptInclusion(first, second), ConceptInclusion(second, first))
case _ => ??? //impossible
}.toSet
case DisjointClasses(_, operands) if operands.size == 2 => //FIXME handle >2
case DisjointClasses(_, operands) if operands.size == 2 => //FIXME handle >2
val converted = operands.map(convertExpression).toList.collect { case Some(concept) => concept }
converted.combinations(2).flatMap {
case first :: second :: Nil => Set(ConceptInclusion(Conjunction(first, second), Bottom))
case _ => ??? //impossible
}.toSet
case ClassAssertion(_, cls, NamedIndividual(iri)) => convertExpression(cls).map(concept =>
case ClassAssertion(_, cls, NamedIndividual(iri)) => convertExpression(cls).map(concept =>
ConceptInclusion(Nominal(WIndividual(iri.toString)), concept)).toSet
case ObjectPropertyAssertion(_, ObjectProperty(prop), NamedIndividual(subj), NamedIndividual(obj)) =>
case ObjectPropertyAssertion(_, ObjectProperty(prop), NamedIndividual(subj), NamedIndividual(obj)) =>
Set(ConceptInclusion(Nominal(WIndividual(subj.toString)), ExistentialRestriction(Role(prop.toString), Nominal(WIndividual(obj.toString)))))
case ObjectPropertyAssertion(_, ObjectInverseOf(ObjectProperty(prop)), NamedIndividual(obj), NamedIndividual(subj)) =>
case ObjectPropertyAssertion(_, ObjectInverseOf(ObjectProperty(prop)), NamedIndividual(obj), NamedIndividual(subj)) =>
Set(ConceptInclusion(Nominal(WIndividual(subj.toString)), ExistentialRestriction(Role(prop.toString), Nominal(WIndividual(obj.toString)))))
case EquivalentObjectProperties(_, propertyExpressions) =>
case EquivalentObjectProperties(_, propertyExpressions) =>
val properties = propertyExpressions.collect { case p @ ObjectProperty(_) => p }.toList
properties.combinations(2).flatMap {
case ObjectProperty(first) :: ObjectProperty(second) :: Nil => Set(RoleInclusion(Role(first.toString), Role(second.toString)))
case _ => ??? //impossible
}.toSet
case SubObjectPropertyOf(_, ObjectProperty(subproperty), ObjectProperty(superproperty)) =>
case SubObjectPropertyOf(_, ObjectProperty(subproperty), ObjectProperty(superproperty)) =>
val sub = Role(subproperty.toString)
val sup = Role(superproperty.toString)
Set(
RoleInclusion(sub, sup),
Rule(List(RoleAtom(sub, WVariable("x1"), WVariable("x2"))), List(RoleAtom(sup, WVariable("x1"), WVariable("x2")))))
case SubObjectPropertyChainOf(_, ObjectProperty(first) :: ObjectProperty(second) :: Nil, ObjectProperty(superproperty)) => //FIXME handle >2
case SubObjectPropertyChainOf(_, ObjectProperty(first) :: ObjectProperty(second) :: Nil, ObjectProperty(superproperty)) =>
val supRole = Role(superproperty.toString)

def makeSubject(level: Int): WVariable = if (level == 0) WVariable("x") else WVariable(s"x$level")
Expand All @@ -70,30 +71,34 @@ object Bridge {
Set(
RoleComposition(Role(first.toString), Role(second.toString), supRole),
Rule(body = atoms, head = List(RoleAtom(supRole, start, end))))
case TransitiveObjectProperty(_, ObjectProperty(property)) =>
case SubObjectPropertyChainOf(_, (first @ ObjectProperty(_)) :: (second @ ObjectProperty(_)) :: more, (superproperty @ ObjectProperty(_))) =>
val compositionProperty: OWLObjectProperty = ObjectProperty(s"$CompositionRolePrefix${first.getIRI}${second.getIRI}")
convertAxiom(SubObjectPropertyChainOf(List(first, second), compositionProperty)) ++
convertAxiom(SubObjectPropertyChainOf(compositionProperty :: more, superproperty))
case TransitiveObjectProperty(_, ObjectProperty(property)) =>
val role = Role(property.toString)
Set(
RoleComposition(role, role, role),
Rule(body = List(RoleAtom(role, WVariable("x1"), WVariable("x2")), RoleAtom(role, WVariable("x2"), WVariable("x3"))), head = List(RoleAtom(role, WVariable("x1"), WVariable("x3")))))
case ReflexiveObjectProperty(_, ObjectProperty(property)) => Set(
case ReflexiveObjectProperty(_, ObjectProperty(property)) => Set(
ConceptInclusion(Top, SelfRestriction(Role(property.toString)))
)
case ObjectPropertyDomain(_, ObjectProperty(property), ce) => convertExpression(ce).map(concept =>
case ObjectPropertyDomain(_, ObjectProperty(property), ce) => convertExpression(ce).map(concept =>
ConceptInclusion(ExistentialRestriction(Role(property.toString), Top), concept)).toSet
case ObjectPropertyRange(_, ObjectProperty(property), ce) => convertExpression(ce).map(concept =>
case ObjectPropertyRange(_, ObjectProperty(property), ce) => convertExpression(ce).map(concept =>
//TODO only supporting in rules for now
Rule(body = List(RoleAtom(Role(property.toString), WVariable("x1"), WVariable("x2"))), head = List(ConceptAtom(concept, WVariable("x2"))))).toSet
case InverseObjectProperties(_, ObjectProperty(p), ObjectProperty(q)) =>
case InverseObjectProperties(_, ObjectProperty(p), ObjectProperty(q)) =>
val (roleP, roleQ) = (Role(p.toString), Role(q.toString))
val (x1, x2) = (WVariable("x1"), WVariable("x2"))
Set(
Rule(body = List(RoleAtom(roleP, x1, x2)), head = List(RoleAtom(roleQ, x2, x1))),
Rule(body = List(RoleAtom(roleQ, x1, x2)), head = List(RoleAtom(roleP, x2, x1))))
case DLSafeRule(_, body, head) => (for {
case DLSafeRule(_, body, head) => (for {
bodyAtoms <- convertAtomSet(body)
headAtoms <- convertAtomSet(head)
} yield Rule(bodyAtoms, headAtoms)).toSet
case _ =>
case _ =>
//println(s"Not supported: $other")
Set.empty
}
Expand Down
Loading

0 comments on commit 40a4f32

Please sign in to comment.