Skip to content

Commit

Permalink
Merge pull request #148 from balhoff/issue-144
Browse files Browse the repository at this point in the history
Implement arbitrary length property chains
  • Loading branch information
balhoff authored Jun 17, 2021
2 parents 11246e6 + 40a4f32 commit 8d19946
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 48 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
Loading

0 comments on commit 8d19946

Please sign in to comment.