Skip to content

Commit

Permalink
Adding option for non-redundant entialed relationships. (#740)
Browse files Browse the repository at this point in the history
* Adding option for non-redundant entialed relationships.

Fixes #739

* tests

* removing ---s with messed with CLI formattinh

* Extended relationships notebook for entailed-direct

* skip correct test
  • Loading branch information
cmungall authored Apr 25, 2024
1 parent a52eed5 commit 64c6114
Show file tree
Hide file tree
Showing 9 changed files with 2,611 additions and 670 deletions.
792 changes: 481 additions & 311 deletions notebooks/Commands/Relationships.ipynb

Large diffs are not rendered by default.

2,164 changes: 1,919 additions & 245 deletions notebooks/Commands/ValidateDefinitions.ipynb

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
244 changes: 130 additions & 114 deletions src/oaklib/cli.py

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions src/oaklib/interfaces/obograph_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,38 @@ def descendant_graph(
self.transitive_query_cache[key] = g
return g

def non_redundant_entailed_relationships(
self,
predicates: List[PRED_CURIE] = None,
**kwargs,
) -> Iterator[RELATIONSHIP]:
"""
Yields all relationships that are directly entailed.
See https://github.com/INCATools/ontology-access-kit/issues/739
:param kwargs: same as relationships
:return:
"""
if "include_entailed" in kwargs:
kwargs.pop("include_entailed")
relationships = list(
self.relationships(predicates=predicates, include_entailed=True, **kwargs)
)
rel_by_sp = defaultdict(list)
for s, p, o in relationships:
if s == o:
continue
rel_by_sp[(s, p)].append(o)
for (s, p), objs in rel_by_sp.items():
redundant_set = set()
for o in objs:
ancs = list(self.ancestors(o, predicates=predicates, reflexive=False))
redundant_set.update(ancs)
for o in objs:
if o not in redundant_set:
yield s, p, o

def ancestors(
self,
start_curies: Union[CURIE, List[CURIE]],
Expand Down
2 changes: 2 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def output_path(fn: str) -> str:
NUCLEUS = "GO:0005634"
ORGANELLE_MEMBRANE = "GO:0031090"
NUCLEAR_ENVELOPE = "GO:0005635"
ORGANELLE_ENVELOPE = "GO:0031967"
ENVELOPE = "GO:0031975"
THYLAKOID = "GO:0009579"
ATOM = "CHEBI:33250"
INTERNEURON = "CL:0000099"
Expand Down
39 changes: 39 additions & 0 deletions tests/test_implementations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
CYTOPLASM,
CYTOPLASMIC_REGION,
ENDOMEMBRANE_SYSTEM,
ENVELOPE,
EUKARYOTA,
FAKE_ID,
FUNGI,
Expand All @@ -120,6 +121,8 @@
NUCLEUS,
OPISTHOKONTA,
ORGANELLE,
ORGANELLE_ENVELOPE,
ORGANELLE_MEMBRANE,
PHENOTYPIC_ABNORMALITY,
PHOTORECEPTOR_OUTER_SEGMENT,
PHOTOSYNTHETIC_MEMBRANE,
Expand Down Expand Up @@ -615,6 +618,42 @@ def test_relationships(self, oi: BasicOntologyInterface, ignore_annotation_edges
irels = list(oi.incoming_relationships(o, predicates=[p]))
test.assertIn((p, s), irels)

def test_entailed_relationships(self, oi: OboGraphInterface):
"""
Tests entailed relationship methods for compliance.
:param oi:
:return:
"""
test = self.test
cases = [
(
NUCLEAR_MEMBRANE,
[IS_A, PART_OF],
{IS_A: {ORGANELLE_MEMBRANE}, PART_OF: {NUCLEAR_ENVELOPE}},
),
(
NUCLEAR_MEMBRANE,
[IS_A, OVERLAPS],
{IS_A: {ORGANELLE_MEMBRANE}, OVERLAPS: {NUCLEAR_ENVELOPE}},
),
(NUCLEAR_MEMBRANE, [IS_A], {IS_A: {ORGANELLE_MEMBRANE}}),
(
NUCLEAR_MEMBRANE,
[PART_OF],
{PART_OF: {NUCLEAR_ENVELOPE, ORGANELLE_ENVELOPE, ENVELOPE}},
),
]
for curie, preds, expected in cases:
logging.info(f"TESTS FOR {curie}")
rels = list(oi.non_redundant_entailed_relationships(subjects=[curie], predicates=preds))
objs_by_pred = {p: set() for p in preds}
for s, p, o in rels:
objs_by_pred[p].add(o)
assert s == curie
for p in preds:
test.assertCountEqual(expected[p], objs_by_pred[p])

def test_rbox_relationships(self, oi: BasicOntologyInterface):
"""
Tests relationships between relationship types
Expand Down
4 changes: 4 additions & 0 deletions tests/test_implementations/test_simple_obo.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ def test_relationships_extra(self):
def test_relationships(self):
self.compliance_tester.test_relationships(self.oi)

@unittest.skip("Contents of go-nucleus file need to be aligned")
def test_entailed_relationships(self):
self.compliance_tester.test_entailed_relationships(self.oi)

def test_rbox_relationships(self):
self.compliance_tester.test_rbox_relationships(self.oi)

Expand Down
4 changes: 4 additions & 0 deletions tests/test_implementations/test_sqldb.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ def test_relationships(self):
oi = SqlImplementation(OntologyResource(slug=f"sqlite:///{str(DB)}"))
self.compliance_tester.test_relationships(oi, ignore_annotation_edges=False)

def test_entailed_relationships(self):
oi = SqlImplementation(OntologyResource(slug=f"sqlite:///{str(DB)}"))
self.compliance_tester.test_entailed_relationships(oi)

def test_relationships_chunking(self):
"""
Tests behavior for chunking relationship queries
Expand Down

0 comments on commit 64c6114

Please sign in to comment.