Example 1: Endurant types

People & Organizations -- Kind, SubKind, Phase, Role, Category, RoleMixin, PhaseMixin

gufo:Kind gufo:SubKind gufo:Phase gufo:Role gufo:Category gufo:RoleMixin gufo:PhaseMixin

What you'll learn

This example is about usage scenarios 3 and 4 from the gUFO usage guide: instantiating and specializing gUFO's taxonomy of types. You will see how to say, of an OWL class you define, what kind of type it is -- whether it is rigid or anti-rigid, whether it supplies identity to its instances (a sortal) or merely groups several sortals together (a non-sortal) -- and why that distinction matters enough that gUFO ships a whole taxonomy, and gufoshapes ships rules to check it.

The domain

The ontology models people and organizations at a small scale: :Person and :Organization, a few of the ways an instance of either can be temporarily or contingently classified (:Child/:Adult, :Student, :Employee), and one specialization that is permanent rather than contingent (:University, a kind of organization). It also has two classes that intentionally do not specialize just :Person or just :Organization, because the distinctions they capture -- being a customer, being currently active -- cut across both.

Why gUFO has a taxonomy of types, not just individuals

Declaring :Person rdfs:subClassOf gufo:FunctionalComplex tells OWL that persons are functional complexes, but it says nothing about what kind of class :Person itself is. Two classes can look identical in OWL -- both are just owl:Class with some rdfs:subClassOf axioms -- while meaning very different things conceptually. Compare:

:Person rdfs:subClassOf gufo:FunctionalComplex .   # every person is necessarily a person
:Student rdfs:subClassOf :Person .                 # a person may stop being a student

Nothing in that OWL fragment distinguishes a class whose instances hold it necessarily from one whose instances hold it contingently. gUFO's taxonomy of types exists to make that distinction explicit, by having the modeler additionally state, using OWL 2 punning, that the class is itself an instance of one of gUFO's type metaclasses:

:Person rdf:type owl:Class ;
        rdfs:subClassOf gufo:FunctionalComplex ;
        rdf:type gufo:Kind .

:Student rdf:type owl:Class ;
         rdfs:subClassOf :Person ;
         rdf:type gufo:Role .

Punning is what makes :Person both a class (of persons) and an individual (an instance of gufo:Kind) at once. This is legal OWL 2 DL not because of anything specific to gUFO, but because OWL 2's semantics always interpret a name's "class facet" and its "individual facet" separately, so the two uses never contradict each other -- any OWL 2 DL ontology gets that for free. What gUFO contributes is not this legality but the vocabulary: a whole second taxonomy of metaclasses (gufo:Kind, gufo:Role, gufo:Phase, ...) for the individual facet of a punned class like :Person to instantiate meaningfully.

The taxonomy, in two dimensions

Every gUFO endurant type sits somewhere on two independent axes:

Sortal (supplies identity)Non-sortal (does not)
Rigid (necessary for all instances)gufo:Kind, gufo:SubKindgufo:Category
Anti-rigid (contingent for all instances)gufo:Phase, gufo:Rolegufo:PhaseMixin, gufo:RoleMixin
Semi-rigid (necessary for some, contingent for others)(gUFO defines no such sortal)gufo:Mixin

Sortal vs. non-sortal is about identity: a sortal type (like :Person) provides the principle by which we count and re-identify its instances over time -- "this is the same person as before". A non-sortal (like :Agent below) groups instances that already get their identity from some sortal further down the hierarchy; :Agent itself answers no "is this the same agent?" question that isn't really "is this the same person/organization?".

Rigid, anti-rigid and semi-rigid are about modality: a rigid type applies to its instances in every possible world in which they exist at all (a person cannot stop being a person without ceasing to exist). An anti-rigid type applies contingently (a person can stop being a student, or a child, while remaining the very same person). A semi-rigid type is neither uniformly: it applies necessarily to some of its instances and contingently to others. gUFO's own example is "FemaleAnimal" (gufo:Mixin): necessary for a lion or a shark, but contingent for a clownfish or a mushroom coral, which can change sex. Note that gufo:Mixin is non-sortal only, not anti-rigid -- gUFO defines no semi-rigid sortal, since a sortal's identity principle is expected to apply uniformly to its instances. This example has no natural semi-rigid grouping in its domain, so gufo:Mixin is not instantiated below; see the table above for where it would fit if it were.

Step by step

A non-sortal at the top: gufo:Category

:Agent captures what persons and organizations have in common, without providing identity for either. It is rigid (nothing stops being an agent while it exists) but non-sortal, so it is declared a gufo:Category:

:Agent a owl:Class , gufo:Category ;
    rdfs:subClassOf gufo:FunctionalComplex .

Two rigid sortals: gufo:Kind

:Person and :Organization each supply their own principle of identity, and each applies necessarily to its instances, so both are kinds. In UFO, an individual can only ever instantiate one kind -- a kind is precisely what supplies its unique principle of identity -- so any two distinct kinds are, in principle, always disjoint. OWL has no way of enforcing this by itself, though: nothing about being declared a gufo:Kind makes two classes disjoint automatically. Declaring owl:disjointWith explicitly is what actually makes that hold in this ontology, and it is good practice to do so for any two kinds, regardless of what supertype (if any) they share:

:Person a owl:Class , gufo:Kind ;
    rdfs:subClassOf :Agent .

:Organization a owl:Class , gufo:Kind ;
    rdfs:subClassOf :Agent ;
    owl:disjointWith :Person .

A rigid specialization: gufo:SubKind

:University is still rigid -- an organization does not stop being a university while it exists -- but it does not introduce a new principle of identity: a university is individuated exactly as any organization is. That combination (rigid, sortal, but not identity-providing) is gufo:SubKind:

:University a owl:Class , gufo:SubKind ;
    rdfs:subClassOf :Organization .

Anti-rigid sortals: gufo:Phase and gufo:Role

:Child/:Adult and :Student/:Employee are all anti-rigid specializations of :Person: a given person moves in and out of them without changing who they are. gUFO further distinguishes why the type is contingent:

:Child a owl:Class , gufo:Phase ;
    rdfs:subClassOf :Person .

:Adult a owl:Class , gufo:Phase ;
    rdfs:subClassOf :Person ;
    owl:disjointWith :Child .

:Student a owl:Class , gufo:Role ;
    rdfs:subClassOf :Person .

:Employee a owl:Class , gufo:Role ;
    rdfs:subClassOf :Person .

Anti-rigid non-sortals: gufo:RoleMixin and gufo:PhaseMixin

"Being a customer" and "being currently active" are contingent, just like a role or a phase -- but they are not specific to persons or to organizations: both can be customers, and both can be active or inactive. A class like this must specialize the non-sortal :Agent, not either kind, and its metatype records that it is anti-rigid and relationally- or intrinsically-grounded, just like Role and Phase, but without supplying identity:

:Customer a owl:Class , gufo:RoleMixin ;
    rdfs:subClassOf :Agent .

:ActiveAgent a owl:Class , gufo:PhaseMixin ;
    rdfs:subClassOf :Agent .

:InactiveAgent a owl:Class , gufo:PhaseMixin ;
    rdfs:subClassOf :Agent ;
    owl:disjointWith :ActiveAgent .

This is exactly the situation gUFO's non-sortals are for: had :Customer been forced to specialize :Person alone, :GlobexCorp (an organization) could never be modeled as a customer without either duplicating the role under :Organization or, worse, misclassifying :GlobexCorp as a person.

Instantiating it

With the type-level declarations in place, ordinary individuals just instantiate these classes as usual (usage scenario 1 from the guide):

:Alice a :Person , :Student , :Adult , :Customer , :ActiveAgent .

:GlobexCorp a :Organization , :Customer , :ActiveAgent .

:OldTownPrinters a :Organization , :InactiveAgent .

Notice :GlobexCorp and :Alice share the :Customer and :ActiveAgent classifications despite being different kinds of thing -- precisely what the non-sortals were introduced to allow.

The full ontology

See ontology.ttl for the complete file, including all individuals (:Bob, :Carol, :AcmeUniversity).

Common pitfall: a rigid type "under" a role

Suppose a modeler wants a class for managers and, reaching for the class that "sounds most important", declares:

:Manager a owl:Class , gufo:Kind ;
    rdfs:subClassOf :Employee .   # :Employee is a gufo:Role

This is syntactically fine OWL, and -- because gufo:Kind and gufo:Role are just punned individuals, not classes that OWL's open-world semantics can reason about as mutually exclusive in this configuration -- a DL reasoner raises no error. But it is nonsense in UFO: a gufo:Kind must be rigid and must supply identity on its own, yet here it specializes :Employee, which is both anti-rigid and already sortal. Managers would, absurdly, never stop being managers even after leaving the company, while simultaneously getting their identity from a role that is itself contingent.

What was probably meant is :Manager a gufo:Role (a kind of employee, contingent on managing something) or gufo:SubKind (if "manager" is meant to be permanent once attained). The full mistake is kept in invalid-example.ttl, and the gUFO SHACL shapes reject it on two counts at once:

How this is checked

examples/tests/test_examples.py runs two checks against ontology.ttl, and two against invalid-example.ttl:

From examples/tests/, after installing requirements.txt into a virtualenv:

.venv/bin/pytest -v -k endurant-types