I try to understand the rector-normalization-technique for ontologies in detail. I use owlready to implement the examples.
The article recommends to have a asserted single inheritance structure and introduce multiple inheritance by inference. As example it uses classes as Protein
, Insulin
, and Protein_Hormone
, Hormone_Role
.
Asserted facts:
Insulin
is_subclass_of
Protein
Insulin
plays_role
Hormone_Role
Protein_Hormone
is equivalent to (Protein
and
plays_role
owl:someValuesFrom
Hormone_Role
) (defined class)
After the reasoner ran, Insulin
is correctly recognized as subclass of Protein_Hormone
(expected result).
However, it is still classified as direct subclass of protein. This relation I deem redundant because every instance of Protein_Hormone
must be a Protein
by definition. Also, if I apply Protegé, the inferred class structure does not contain this redundant relation, as shown here:
Is there a (canonical) way to get rid of this superfluous subclass relation?
Alternatively, why is my suspicion of superfluousness wrong?
Code for this problem (see also this notebook for outputs):
import owlready2 as owl2
# rme: rector-modularization-example
onto = owl2.get_ontology("https://w3id.org/yet/undefined/rme#")
with onto:
class Protein(owl2.Thing):
pass
class Insulin(Protein):
pass
class Hormone_Role(owl2.Thing):
pass
class plays_role(owl2.ObjectProperty):
pass
class Protein_Hormone(owl2.Thing):
equivalent_to = [Protein & plays_role.some(Hormone_Role)]
Insulin.is_a.append(plays_role.some(Hormone_Role))
# before reasoning
print(list(Protein.subclasses()))
owl2.sync_reasoner_hermit(infer_property_values=True, debug=1)
# after reasoning
print(list(Protein.subclasses()))