Oh OWL, how you vex me.
I’m starting an implementation of a reasoner in Python (BECAUSE!!!). Which led me to the need for some internal representation of the ontologies I want to reason over. Fine. OWLReady won’t do, by design. Sigh.
So, I first think to whip out a quickly representation with tuples, maybe Named Tuples, maybe TYPED NAMED TUPLES!!! (but that’s misery for another blog post) and I start…
…but, I think, why not do a proper Python API straight off the structural spec? That’s what it was meant for. The OWL API basically follows it. It gives me “free” documentation and proves the concept. I put a lot of work into that spec, though Boris designed the functional syntax and thus the API (and Boris and I have been fighting over APIs since the first time we met!)
I’ve sketched out a partial set of syntactic forms following the OWL API in Python which gives me, essentially, new, evaluable, literal forms. Let’s compare to other syntaxes!
For comparison, I’ll use a four axiom, EL ontology taken from the ELK paper (example 1 on page 6). It’s small. It’s not complex. So yay!
This is what you see in most papers. No one parses it.
A ⊑ ∃R.(C ⊓ D)
B ≡ A ⊓ ∃S.D
∃S.D ⊑ C
R ⊑ S
Awesome. Clear. Easy to read. Somewhat annoying to type.
Jewel is a syntax I came up with designed to be close to German syntax (with a Model Logic twist) and very typeable. I have a parser but haven’t used it in aeons.
A => <R>(C & D).
B = A & <S>D.
<S>D => C.
R ==> S.
IT’S PRETTY DAMN FINE!
Easyish to parse. Almost as short as German. Easy to read. Excellent.
Adhoc Wordy DLish StrucSpec Like
Using named tuples, I threw together a little wordy syntax that mapped directly into the corresponding Python structures:
Subconcept(Concept('A'), Exists(Role('R'), And(Concept('C'), Concept('D')))),
Subconcept(Concept('B'), And(Concept('A'), Exists(Role('S'), Concept('D')))),
Subconcept(And(Concept('A'), Exists(Role('S'), Concept('D'))), Concept('B')),
Subconcept(Exists(Role('S'), Concept('D')), Concept('C')),
Could be worse! I latched on to the DL terms “concept” and “role” because that was what I was reading, but what I’d gain with “class” I lose with “property” so it’s fine. Maybe I could use one letter names for the atomics:
Subconcept(C('A'), Exists(R('R'), And(C('C'), C('D')))),
Subconcept(C('B'), And(C('A'), Exists(R('S'), C('D')))),
Subconcept(And(C('A'), Exists(R('S'), C('D'))), C('B')),
Subconcept(Exists(R('S'), C('D')), C('C')),
And really, it could be “Sub” if I’m going to type all the vocabulary.
Not terrible. Okish to type. Automatic parsing. Deviates from everything.
OWL Structural Spec
I’m just going to do the first axiom because I lost the will to live:
OY! I could get rid of the
owl with a tweak to imports (i.e., to the bad practice of
from owl import *), but that’s only going to help a little. How I hate all those redundant “objectProperty”s.
I hated literally every moment of typing out this one axiom, even with autocomplete. Reading it makes me want to throw up. I can’t imagine that programming with it would be nice.
Let’s see what happens if I add the prefix to the ad hoc one:
owl.Subconcept(owl.C('A'), owl.Exists(owl.R('R'), owl.And(owl.C('C'), owl.C('D')))),
Ooo, that sucks. Maybe killing the prefix will save the day?
So, I don’t think I’m going to continue with the strict conformance to the naming scheme of the Structural Spec.