December 22, 2020

Describing foaf:membershipClass in OWL

I've recently discovered RDF, one of the web's rising frameworks for identifying and describing data, made for the web of linked data. It can describe people, institutions, accounts, places, events, languages, documents, and much more thanks to the vast range of standardized vocabularies for different concepts, entities, and relations. The core unit of information in RDF is the semantic triple: subject, predicate, and object. The individual concepts (resources) are identified with URIs, brining universal identification, verification, and navigation to pieces of data.

There are numerous vocabularies (ontologies) for RDF, and one of them is FOAF (Friend of a Friend), used for describing people and their online presence, as well as general groups of people. One of the properties a group in FOAF (class foaf:Group) can have is foaf:membershipClass. This states that people in a specific group can be thought of as members of a particular class, that the two sets of people are equal.

There is also OWL, an ontology of ontologies, a vocabulary for describing vocabularies. The purpose of this metaontology is assisting reasoners in deriving additional facts from data, forming a complex knowledge base. Even though there are simpler schemata that are sometimes enough (RDFS), OWL defines things like identity, equivalency of classes and properties, and constructions of anonymous classes and properties in terms of relations to other classes and properties.

There are parts of FOAF that are hard to describe using OWL, and foaf:membershipClass is one of those, since it links an individual (group) to a class. I will now try to describe it with OWL (using the Turtle language).

The complicated way

foaf:membershipClass a owl:FunctionalProperty , owl:InverseFunctionalProperty .

This states that the property can only map at most one class to a group, and at most one group can be mapped to a single class. If there are more resources mapped either way (something RDF itself will happily allow), this states that those are actually one and the same individual. This fact may not be entirely true, but without it things could go wrong.

Now the fun part. OWL allows declaring an anonymous class of type owl:Restriction that is realized as a class of things that have a certain property. We want to dynamically create such a restricion as in this template:

ex:Group foaf:membershipClass ex:Class .

ex:Class owl:equivalentClass [
  a owl:Restriction ;
  owl:onProperty [ owl:inverseOf foaf:member ] ;
  owl:hasValue ex:Group
] .

This states that our own class, ex:Class, has the same members as the class of all things that are a foaf:member of our group. Notice that foaf:member links a group to a person; there is nothing like foaf:memberOf so we have to obtain the inverse property via OWL.

OWL does not actually allow us to create a new individual for each group, so we have to cheat a bit: we will turn every group into a restriction:

foaf:Group rdfs:subClassOf owl:Restriction .

Yet we might not want nor need to do such a thing for every group, we only want to cover the groups that have a membership class specified:

[ a owl:Restriction ; owl:onProperty foaf:membershipClass ; owl:someValuesFrom rdfs:Class ] rdfs:subClassOf owl:Restriction .

This is essentially an implication stating that if an individual has a property of foaf:membershipClass linking to a class (which it should always do), it has a class owl:Restriction.

Yet we are still missing two properties from the restriction. This time, we will work just with foaf:member, and for that, we will modify the previous piece of code:

_:g a owl:Restriction ;
  owl:onProperty foaf:membershipClass ;
  owl:someValuesFrom rdfs:Class .

_:g rdfs:subClassOf owl:Restriction , [
  a owl:Restriction
  owl:onProperty owl:onProperty .
  owl:hasValue foaf:member .
] .

Our anonymous class of groups with foaf:membershipClass is now (locally) identified as _:g, and we have specified that while any such individial is an owl:Restriction, it also has a property owl:onProperty with foaf:member as its value.

Now the last property of the restriction is something describing its object, whose type we will conveniently obtain from foaf:membershipClass:

foaf:membershipClass rdfs:subPropertyOf owl:allValuesFrom .

The value of foaf:membershipClass will now specify the final part of the restriction, that all values of foaf:member must be in the specified class.

For every desired group, we now have a restriction saying that all members must be in a class. There is now a slight issue that we need to link the group back to itself, saying that that one group is actually the instance of its own restricted anonymous class. For this, we will first need to find a reflexive property somewhere – that's easy, we already have owl:sameAs and we assume that every individual is linked this way at least to itself. We could break the universe by saying:

owl:sameAs rdfs:subPropertyOf rdf:type .

But we don't want to turn every individual into a class, so we have to try something else. Let's go the other way:

_:p a owl:ObjectProperty , owl:FunctionalProperty , owl:InverseFunctionalProperty ;
  rdfs:subPropertyOf owl:sameAs , rdf:type .

This states that _:p is our new anonymous property, and its presence on a pair implies that the two objects are equal and that it is a type of itself. Conversely, if two entities are not the same, they also cannot have this property, which will be important for the next step:

_:g rdfs:subClassOf [
  a owl:Restriction ;
  owl:onProperty _:p ;
  owl:someValuesFrom _:g
] .

_:g rdfs:subClassOf [
  a owl:Restriction ;
  owl:onProperty _:p ;
  owl:allValuesFrom _:g
] .

Every of our modified groups must have our property _:p with an object of the same type, and indeed all of its objects must have that type (in practice there can be at most one due to the definition of _:p, so the second implication is not needed much).

Now we are done. Every group with a foaf:membershipClass must have type of something that is identical to it, so in reality there is (tautologically) only one individual that could be an object of such a statement. Assuming there are no other interpretations in which the group is a class, this restricts the group class to something that only has members of the specified type. It is basically like saying:

ex:Group a foaf:Group , [
  a owl:Restriction ;
  owl:onProperty foaf:member ;
  owl:allValuesFrom ex:Class
] .

The issue of this approach in practice is that it requires at least OWL Full, since it not only treats individuals as classes, but also makes them reason about the reasoning itself. While this was fun to attempt to produce, there aren't many (if any) engines that could process it. It also seems that in order to express the restriction class, we always have to "pollute" something else, in this case the actual group. Perhaps it does not need to be this complicated if we can live with the same consequences.

The simple but dangerous way

foaf:membershipClass rdfs:subPropertyOf owl:equivalentClass .
[ owl:inverseOf foaf:member ] owl:equivalentProperty rdf:type .

I would not recommend to any general ontology, but when used just with reasoning, this should do the trick. First it makes every group a class, one equivalent to that specified with foaf:membershipClass, and then states that being a member of a group is the same as having the type of that group itself. The additional implication is that having any type will also make the individual a member of a group, so there are some other restrictions that must be applied before this would be suitable for general use.

No comments:

Post a Comment