Category Archives: OWL

Unfolding T-boxes in GO using POPL

“Unfolding a T-box” may sound like some quaint tea ceremony ritual, but in fact in the context of description logics it refers to the iterative replacement of classes by equivalent anonymous class expressions.

Many reasoners take advantage of T-box unfolding behind the scenes. But there may be reasons to unfold your T-box in a more public fashion.

For example, there are frequently criticisms of highly specific wordy GO terms such as:
GO:2001043 positive regulation of cytokinetic cell separation involved in cell cycle cytokinesis

Whilst not as unwieldy as some of the infamous ICD9 examples, some feel that this is taking pre-composition too far. In fact these detailed pre-composed terms are very useful for systems that aren’t capable of consuming anonymous class expressions. However, for some purposes it may be useful to replace this with a nested class expression.

This can be done in 3 lines with a POPL script:


class(X) ===> null where X==_.
annotationAssertion(_,X,_) ===> null where X==_.

X ===>Y where X==Y.

The first two lines remove class declarations and annotation assertions (e.g. label assignments) for any defined classes. The final line does all the work: it replaces every occurrence of a defined class with the equivalent class expression.

This means if we have the following gene association (e.g. from a GAF file):


Class: :Gene1234
Types: 'positive regulation of cytokinetic cell separation involved in cell cycle cytokinesis'

it will be translated to:

Class: :Gene1234
Types:
  capable_of some 
    ('biological regulation'
     and (positively_regulates some 
        ('cytokinetic cell separation'
         and (part_of some 
            (cytokinesis
             and (part_of some 'cell cycle'))))))

We can also choose to selectively unfold – e.g. unfold all regulation terms:


X ===>Y where (X==Y, Y='biological regulation and _).

Resulting in:

Class: :Gene1234
Types:
  capable_of some
    ('biological regulation'
      and (positively_regulates some 'cytokinetic cell separation involved in cell cycle cytokinesis'))

The same thing could be done in java, but would require significantly more code and messing around with visitor classes. The results would be less declarative, and harder to customize.

What if we want to perform the reverse operation? This is similar to finding the most specific subsuming class, which is a standard reasoner operation. However, in this case we want to find a more specific class expression, which is slightly more difficult. This might be the topic of a future post.

Prolog OWL Shell at OWLED 2011

My slides and paper for POSH are now online:

Manuscript: owled2011_submission_15.pdf

Slides: POSH (slideshare)

Posh — the Prolog OWL Shell

Posh (Prolog OWL Shell) is a command line utility
that wraps the Thea OWL library to allow for advanced querying and
processing of ontologies, combining the power of prolog and OWL
reasoning.

Installation

Install SWI

Download and install SWI-Prolog (http://swi-prolog.org). This is a
simple point and click procedure for most platforms. If you want to use
reasoners such as Pellet, make sure you have JPL installed (see
troubleshoooting section).

Posh Git

Get the latest version of Thea from github. Git clone is
recommended, but you can also use the githb download link.

Assuming you placed the project in your toplevel directory, set your path:


export PATH="$PATH:$HOME/thea"

You’re now set to use Posh

Getting Started

First we start thea using the –shell option. We also start it in JPL
mode, as we will be making use of the OWLAPI to interface with
reasoners. We’ll also load the OWL translation of the fly anatomy
ontology, from the OBO library.


thea-jpl --jvm-opt -Xmx2048M  http://purl.obolibrary.org/obo/fbbt.owl --shell 

This starts us up in an ehanced prolog shell with the fly anatomy
loaded. You can make arbitrary prolog queries, as in any prolog shell,
for example:


?- member(X,[a,b,c]).
X = a ;
X = b ;
X = c.

If you don’t know prolog, you should still be able to get by. The
crucial syntax to remember is that variables commence with an
uppercase letter (or ‘_’) and each line should be terminated by a
‘.’. Also, if you get stuck, type ‘help.’ for a list of commands.

Let’s start by checking our list of ontologies:


?- ls.
*http://purl.obolibrary.org/obo/fbbt.owl
true.

The first thing we’ll do is set some display options. fbbt uses labels
for all classes, so we will make sure these are displayed.


 ?- set display + labels.
true.

We will also choose to display all class expressions as ‘plsyn’. This
looks like a mixture of DL syntax and manchester syntax. Why another
syntax? Because plsyn is pure prolog, which means it can be used
directly in prolog queries and operations. It’s not the most
user-friendly syntax, but it’s worthwhile getting to know if you
intend to be doing any advanced operations from within this shell.


 ?- set display + plsyn.
true.

These settings are automatically saved in your ~/.thearc file.

Type “settings.” to see the full list. To clear the display settings:


 ?- unset display.
true.

You should stick with labels and plsyn for this tutorial. Other useful
values are “tabular” and “combined”.

Initial exploration

We can use the l/1 command to find all axioms associated with a class (in this case ‘wing’):


?- l wing.
% Axiom Type: annotationAssertion
annotationAssertion('http://purl.obolibrary.org/obo/IAO_0000115',wing,'A flight organ of the adult external thorax that is derived from a dorsal mesothoracic disc.').
annotationAssertion('http://purl.obolibrary.org/obo/IAO_id',wing,'FBbt:00004729').
annotationAssertion('http://purl.obolibrary.org/obo/IAO_subset',wing,'FB_gloss').
annotationAssertion('http://purl.obolibrary.org/obo/IAO_subset',wing,cur).
annotationAssertion('http://purl.obolibrary.org/obo/IAO_xref',annotation(wing,'http://purl.obolibrary.org/obo/IAO_0000115','A flight organ of the adult external thorax that is derived from a dorsal mesothoracic disc.'),'FBC:gg').
annotationAssertion(label,wing,wing).
% Axiom Type: class
class wing.
% Axiom Type: subClassOf
'chordotonal organ of wing'<part_of some wing.
'wing hair'<part_of some wing.
wing<appendage.
wing<develops_from some 'wing disc'.
wing<part_of some 'adult mesothoracic segment'.
wing<part_of some 'adult external thorax'.
tegula<part_of some wing.
'wing hinge'<part_of some wing.
'wing septum'<part_of some wing.
'wing margin'<part_of some wing.
'wing blade'<part_of some wing.
'dorsal wing blade'<part_of some wing.
'ventral wing blade'<part_of some wing.
true.

If the term of interest starts with an uppercase character, or includes a space, you need to quote the label:


?- l 'wing disc'.
...

Quotes must be escaped:


?- l 'Wheeler\'s organ'.
...

You can list add the axioms in the current ontology by typing
“lsa.”. This might produce quite a long list. You can query more
precisely using prolog, but if you’re not ready for that, you can rely
on your unix wizardry skills:


?- lsa -- 'grep wing'.
...

The “–” predicate will pipe the results of the posh command to any
unix command or script.

Trees and graphs

We can draw ascii trees showing the denormalized subclass hierarchy tree using t/1:


?- t wing.
anatomical entity
.material anatomical entity
..anatomical structure
...organism subdivision
....appendage
.....wing
true.

Note that this is just the asserted developmental axioms – so
far these are just queries on the ontology structure – we will get to
entailed facts later on.

Use the v/1 command to visualize an object (graphviz required):


?- v 'wing disc'.

By default, this will show the closure over subclass axioms, as well
as positive restrictions. The default behavior can be controlled, and
the graphviz display is highly configurable, but this is out of scope
for this tutorial.

Prolog query shorthand

You can use this shell to query any of the prolog facts in the owl
model database. For example, to find all development axioms:


?- labelAnnotation_value(DF,develops_from),
   subClassOf(X,someValuesFrom(DF,Y)).
DF = 'http://purl.obolibrary.org/obo/TODO_develops_from',
X = 'http://purl.obolibrary.org/obo/FBbt_00000000',
Y = 'http://purl.obolibrary.org/obo/FBbt_00000110' ;
DF = 'http://purl.obolibrary.org/obo/TODO_develops_from',
X = 'http://purl.obolibrary.org/obo/FBbt_00000090',
Y = 'http://purl.obolibrary.org/obo/FBbt_00016018' ;
DF = 'http://purl.obolibrary.org/obo/TODO_develops_from',
X = 'http://purl.obolibrary.org/obo/FBbt_00000091',
Y = 'http://purl.obolibrary.org/obo/FBbt_00004891' ;
DF = 'http://purl.obolibrary.org/obo/TODO_develops_from',
X = 'http://purl.obolibrary.org/obo/FBbt_00000095',
Y = 'http://purl.obolibrary.org/obo/FBbt_00017000' .

This isn’t very meaningful – you can use labelAnnotation/2 to map results back to labels:


?- labelAnnotation_value(DF,develops_from),
  subClassOf(X,someValuesFrom(DF,Y)),
  labelAnnotation_value(Y,YN).

But this is a bit tedious. Posh has the convenience command q/1
which launches a query takes care of all label/IRI mapping for you


?- q X < develops_from some Y.
'germ layer derivative'<develops_from some 'germ layer'.
'dorsal ridge'<develops_from some 'dorsal ridge primordium'.
'pole bud'<develops_from some 'pole plasm'.
amnioserosa<develops_from some 'amnioserosa primordium'.
ectoderm<develops_from some 'ectoderm anlage'.
'dorsal ectoderm'<develops_from some 'dorsal ectoderm anlage'.
'anterior ectoderm'<develops_from some 'anterior ectoderm anlage'.
'posterior ectoderm'<develops_from some 'posterior ectoderm anlage'.
endoderm<develops_from some 'endoderm anlage'.
mesoderm<develops_from some 'mesoderm anlage'.
...

Note we’re also using the infix operator ‘<' as a shorthand for the
prolog subClassOf/2 predicate, and the infix operator 'some' as
shorthand for someValuesFrom terms. The result is a bastard hybrid of
prolog, DL syntax by way of Manchester. Unfortunately the default
output is quite stingy with whitespace, and is overly compact.

The following shows all subclass axioms:


?- q _<_.

The list of axioms is quite large. We can filter this set using any
unix command, such as perl or grep using ‘–‘.


?- q X < develops_from some Y -- 'grep muscle'.
'embryonic/larval somatic muscle'<develops_from some 'somatic muscle primordium'.
'longitudinal muscle'<develops_from some 'longitudinal visceral muscle primordium'.
'prothoracic pharyngeal muscle'<develops_from some 'dorsal pharyngeal muscle primordium'.
'abdominal ventral acute muscle 1'<develops_from some 'abdominal ventral acute muscle 1 founder cell'.
'abdominal ventral acute muscle 2'<develops_from some 'abdominal ventral acute muscle 2 founder cell'.
'abdominal ventral acute muscle 3'<develops_from some 'abdominal ventral acute muscle 3 founder cell'.
'abdominal dorsal oblique muscle 3'<develops_from some 'abdominal dorsal oblique muscle 3 founder cell'.
'abdominal lateral oblique muscle 1'<develops_from some 'abdominal lateral oblique muscle 1 founder cell'.
'abdominal dorsal transverse muscle 1'<develops_from some 'abdominal dorsal transverse muscle 1 founder cell'.
'abdominal ventral transverse muscle 1'<develops_from some 'abdominal ventral transverse muscle 1 founder cell'.
'adult myoblast'<develops_from some 'adult muscle precursor primordium'.
'circular visceral muscle fiber'<develops_from some 'circular visceral muscle primordium'.
'dorsal pharyngeal muscle primordium'<develops_from some 'dorsal pharyngeal muscle anlage'.
'dorsal pharyngeal muscle primordium'<develops_from some 'head mesoderm'.
'adult muscle precursor primordium'<develops_from some 'trunk mesoderm'.
'somatic muscle primordium'<develops_from some 'somatic mesoderm'.
'visceral muscle primordium'<develops_from some 'visceral mesoderm'.
'larval muscle system'<develops_from some 'embryonic muscle system'.
'embryonic gonadal sheath muscle'<develops_from some 'gonadal sheath proper primordium'.
'larval gonadal sheath muscle'<develops_from some 'embryonic gonadal sheath muscle'.
'hindgut visceral muscle fiber'<develops_from some 'hindgut visceral muscle primordium'.
'foregut visceral muscle fiber'<develops_from some 'foregut visceral muscle primordium'.
'embryonic/larval midgut longitudinal visceral muscle'<develops_from some 'midgut longitudinal visceral muscle primordium'.
'circular visceral muscle primordium'<develops_from some 'visceral mesoderm'.
'esophageal visceral muscle primordium'<develops_from some 'head mesoderm'.
'esophageal visceral muscle'<develops_from some 'esophageal visceral muscle primordium'.
true.

In Posh, ‘==’ translates to equivalent_to/2, and ‘and’ translates
to intersectionOf, so we can ask for all definitions that
directly use the neuron class:


?- q X == neuron and A.
'abdominal neuron'==neuron and part_of some abdomen.
'A8 neuron'==neuron and part_of some 'abdominal segment 8'.
'prothoracic anterior fascicle neuron'==neuron and fasciculates_with some 'prothoracic intersegmental nerve'.
'prothoracic posterior fascicle neuron'==neuron and fasciculates_with some 'prothoracic segmental nerve'.
'mesothoracic anterior fascicle neuron'==neuron and fasciculates_with some 'mesothoracic intersegmental nerve'.
'mesothoracic posterior fascicle neuron'==neuron and fasciculates_with some 'mesothoracic segmental nerve'.
'metathoracic anterior fascicle neuron'==neuron and fasciculates_with some 'metathoracic intersegmental nerve'.
'metathoracic posterior fascicle neuron'==neuron and fasciculates_with some 'metathoracic segmental nerve'.
'abdominal anterior fascicle neuron'==neuron and fasciculates_with some 'abdominal intersegmental nerve'.
'abdominal posterior fascicle neuron'==neuron and fasciculates_with some 'abdominal segmental nerve'.
'peptidergic neuron'==neuron and releases_neurotransmitter some peptide.
'sensory neuron'==neuron and has_function_in some 'detection of stimulus involved in sensory perception'.
...

Editing the ontology

The commands add/1 and rm/1 will assert and retract to the current
ontology. When you’re done use can use save_axioms/2 to persist your
results to a file.


?- add brain < has_part some neuron.
% Asserting brain<has_part some neuron.
 into http://purl.obolibrary.org/obo/fbbt.owl
true.

You can always undo:


?- undo.
% Undo: Asserting brain<has_part some neuron.
 into http://purl.obolibrary.org/obo/fbbt.owl
true.

If you have asserted multiple facts, you will keep getting prompted
until you hit return or have undone all facts you added. If you change
your mind again, just type “redo.”.

Using a reasoner

Thea comes pre-packaged with both java reasoners and a prolog
rule-based reasoner. We’ll assume Pellet, a java reasoner.

Start the reasoner like this:


?- init pellet.
% library(thea2/owl2_java_owlapi) compiled into owl2_reasoner 0.01 sec, 13,608 bytes
% initializing: reasoner 0.76
% completed: reasoner 21.82 time: 21.06
true.

Behind the scenes, Posh has established contact with the java
OWLAPI. If you’re having java issues, or want to use a boutique
reasoner the OWLAPI can’t talk to, you can always talk to a reasoner
via OWLLink – but that’s the subject of another tutorial.

The qi/1 predicate is similar to q/1, but the query is passed to the
reasoner. Here’s how we find all neurons:


?- qi X < neuron.
'5-2Ica1'<neuron.
'lamina receptor cell R1'<neuron.
'abdominal 1 desC neuron'<neuron.
'5-2I'<neuron.
'abdominal 2 desC neuron'<neuron.
'lamina receptor cell R3'<neuron.
'5-1I'<neuron.
...

The results are all entailed subclass axioms. If you just want the
classes you can use the SELECT .. WHERE .. idiom:


?- qi X where X < neuron.
'5-2Ica1'.
'lamina receptor cell R1'.
'abdominal 1 desC neuron'.
'5-2I'.
'abdominal 2 desC neuron'.
'lamina receptor cell R3'.
'5-1I'.
'lamina receptor cell R2'.
'4-4I'.
'5-2Icp'.
...

Again the list is quite large. The unix ‘head’ and ‘tail’ commands are
quite convenient here:


?- qi X < neuron -- head.

You can use any DL expression, for example someValuesFrom restrictions:


?- qi X < overlaps some neuron.
'photoreceptor cell R2 pigment granule'<overlaps some neuron.
'photoreceptor cell R5 pigment granule'<overlaps some neuron.
neurite<overlaps some neuron.
'photoreceptor cell R6 pigment granule'<overlaps some neuron.
synapse<overlaps some neuron.
'photoreceptor cell R3 pigment granule'<overlaps some neuron.
'photoreceptor cell R7 pigment granule'<overlaps some neuron.
'end plate'<overlaps some neuron.

Or intersections:


?- qi X < neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron MN5'<neuron and overlaps some 'muscle cell'.
'b2 motor neuron'<neuron and overlaps some 'muscle cell'.
'cibarial pump muscle neuron'<neuron and overlaps some 'muscle cell'.
'III1 motor neuron'<neuron and overlaps some 'muscle cell'.
'Nothing'<neuron and overlaps some 'muscle cell'.
'I1 motor neuron'<neuron and overlaps some 'muscle cell'.
'direct flight muscle motor neuron'<neuron and overlaps some 'muscle cell'.
'III3 motor neuron'<neuron and overlaps some 'muscle cell'.
'b1 motor neuron'<neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron MN3'<neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron MN4'<neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron MN1'<neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron MN2'<neuron and overlaps some 'muscle cell'.
'tergal depressor of trochanter muscle motor neuron'<neuron and overlaps some 'muscle cell'.
'indirect flight muscle motor neuron'<neuron and overlaps some 'muscle cell'.
'dorsal tp motor neuron'<neuron and overlaps some 'muscle cell'.
'ventral tp motor neuron'<neuron and overlaps some 'muscle cell'.
true.
?- qi X < neuron and overlaps some 'muscle cell' -- wc.
      17     160    1202
true.

Note that nothing is asserted to overlap in fbbt. Where is the
reasoner getting these inferences from? Let’s have a look at the property:


 ?- l overlaps.
* Axiom Type: annotationAssertion
annotationAssertion('http://purl.obolibrary.org/obo/IAO_id',overlaps,overlaps).
annotationAssertion(label,overlaps,overlaps).
* Axiom Type: objectProperty
objectProperty(overlaps).
* Axiom Type: subPropertyOf
part_of@<overlaps.
partially_overlaps@<overlaps.
true.

part_of holds whenever overlaps holds (the “@<" is plsyn for
subPropertyOf/2), so in fact our query above gives the same results as
querying for parts of a muscle cell.

In fact, overlaps should hold whenever we have a chain of has_part and
part_of. Let's add this axiom. The plsyn for subproperties and property
chains is a bit abstruse and non-obvious:


?- add overlaps @< has_part*part_of.

You can always type the full prolog functional syntax if you prefer:


?- add subPropertyOf(overlaps,propertyChain([has_part,part_of])).

(the add/1 command takes care of translating your labels to IRIs).

With the current version of fbbt we have to also add this:


?- add has_part inverseOf part_of.

Unfortunately, this has the negative consequence of slowing Pellet
down a lot. Let’s backtrack.


?- undo.
% Undo: Asserting has_part inverseOf part_of.
 into http://purl.obolibrary.org/obo/fbbt.owl
true ;
% Undo: Asserting propertyChain([has_part,part_of])@<overlaps.
 into http://purl.obolibrary.org/obo/fbbt.owl
true.

Advanced Ontology Processing

Let’s say we want to start asserting spatial non-overlaps in our
ontology – for example, a leg and a wing have no parts in common:


?- add wing < not has_part some (part_of some leg).

but it would be very tedious to do this for all possible
partitions. What if instead we start from the basis that the current
ontology is correct, and assert non-overlap for all sibling parts that
cannot be proved to overlap?

First let’s do some exploration – let’s try and query for
part_of-siblings directly asserted to be parts of the leg:


?- q row(P1,P2) where P1 < part_of some leg, P2 < part_of some leg.
row(coxa,coxa).
row(coxa,tibia).
row(coxa,trochanter).
row(coxa,femur).
...

Note this includes reflexive pairs. We can exclude reflexive pairs by
doing an equality test. We might try and do this in this way:


?- q row(P1,P2) where P1 < part_of some leg, P2 < part_of some leg, P1\=P2.
true.

But this returns no results. Why? We can check using the tr/2
predicate to translate our shorthand above to the actual prolog goal:


?- tr((P1 < part_of some leg, P2 < part_of some leg, P1\=P2),X).
X = (subClassOf(P1, someValuesFrom('http://purl.obolibrary.org/obo/TODO_part_of', 
                                    'http://purl.obolibrary.org/obo/FBbt_00004640')), 
     subClassOf(P2, someValuesFrom('http://purl.obolibrary.org/obo/TODO_part_of', 
                                    'http://purl.obolibrary.org/obo/FBbt_00004640')), 
     differentIndividuals([[P1, P2]])).

Here “\=” is being translated to differentIndividuals/2. Now that we
are doing more advanced hybrid queries we have to exercise a little
more control by being explicit about which parts are shorthand. We can
use pq/1 to execute a query without implicit translation and
explicitly translate using g/1:


?- pq row(P1,P2) where g((P1 < part_of some leg, P2 < part_of some leg)), P1\=P2.
row(coxa,tibia).
row(coxa,trochanter).
row(coxa,femur).
row(coxa,joint).
row(coxa,'tarsal segment').
row(coxa,pretarsus).
row(tibia,coxa).
row(tibia,trochanter).
row(tibia,femur).
row(tibia,joint).
row(tibia,'tarsal segment').
row(tibia,pretarsus).
row(trochanter,coxa).
...

In the above, only the sections inside the “g()” term are translated
from the shorthand syntax.

We’re still fetching symmetric pairs. We can avoid this using the
prolog @< comparison operator (which again has a different meaning in
our shorthand):


?- pq row(P1,P2) where g((P1 < part_of some leg, P2 < part_of some leg)), P1@<P2.
...

We can go ahead and assert non-overlap for all direct parts of the leg:


?- add P1 < not has_part some part_of some P2
    where g(P1 < part_of some leg), g(P2 < part_of some leg), P1\==P2.
% Asserting coxa<not has_part some part_of some tibia.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting coxa<not has_part some part_of some trochanter.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting coxa<not has_part some part_of some femur.
 into http://purl.obolibrary.org/obo/fbbt.owl
...

But we probably shouldn’t do this – our assumption is too
strong. There’s no reason to believe that all parts of the leg should
be spatially disconnected.

To see a counter-example, try:


?- pq row(X,P1,P2) where 
    W='embryonic head',g(P1 < part_of some W), g(P2 < part_of some W), P1@<P2, 
    gi(X < part_of some P1 and part_of some P2).
row('deutero/tritocerebral embryonic fiber tract founder cluster','embryonic antennal segment','embryonic intercalary segment').
row('A subperineurial glial cell (subesophageal)','embryonic mandibular segment','embryonic maxillary segment').
row('A subperineurial glial cell (subesophageal)','embryonic mandibular segment','embryonic labial segment').
row('A subperineurial glial cell (subesophageal)','embryonic maxillary segment','embryonic labial segment').
true.

Here we are querying the asserted database (via g/1) for part-siblings
and the inferred database (via gi/1) to see if there are parts shared
by those part-siblings. We can see there are some parts shared by some
pairs – if we were to assert that these were spatially disconnected
then we would get unsatisfiable classes next time we classified.

We can then write a command that asserts spatial disconnection only in
those cases where it can’t be proved there is an existing overlap:


?- add P1 < not has_part some part_of some P2 where W='embryonic head',g(P1 < part_of some W), g(P2 < part_of some W), P1\=P2, \+ gi(X < part_of some P1 and part_of some P2).
% Asserting 'embryonic ocular segment'<not has_part some part_of some 'embryonic procephalic segment'.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting 'embryonic ocular segment'<not has_part some part_of some 'embryonic labral segment'.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting 'embryonic ocular segment'<not has_part some part_of some 'embryonic antennal segment'.
 into http://purl.obolibrary.org/obo/fbbt.owl
...

This is probably still too eager, as we making a closed world
assumption here (the “\+” is a prolog not, which means “cannot be
proved”). There may well be shared parts not yet in our
ontology. Nevertheless, it can be useful to make our initial
constraints too strong and progressively weaken them.

We can write a prolog clause that will execute this update for any
value of W. Use ctrl-z to suspend the shell:


cat > assert_non_overlap.pl
assert_non_overlap(W) :-
  add 
   P1 < not has_part some part_of some P2 
  where 
   g(P1 < part_of some W), g(P2 < part_of some W), 
   P1\=P2, 
   \+ gi(X < part_of some P1 and part_of some P2).

In future sessions just type “consult(assert_non_overlap).” to load
this program.

Template-based search and replace

We can perform even more powerful translations on the ontology using
POPL. To illustrate, let’s add some ‘overlaps’ axioms:


 ?- add 'nervous system' < overlaps some head.
% Asserting 'nervous system'<overlaps some head.
 into http://purl.obolibrary.org/obo/fbbt.owl
true.

We can then translate these axioms using the following POPL expression:


 ?- overlaps some Y ===> has_part some part_of some Y.

We can check the results:


 ?- l 'nervous system' -- 'grep head'.
'nervous system'<has_part some part_of some head.
true.

You can use a where clause for selective replacement:


?- overlaps some Y ===> has_part some part_of some Y 
    where gi(Y < 'organism subdivision').

Ontology editing using templates

Create a file called “nc.pl” with the following contents:


edit_template(nc(X),
              [iri(obo('FBbt',8)),
               class X,
               N-annotationAssertion(label,X,literal(N)),
               multi(Y-subClassOf(X,Y)),
               multi(W-subClassOf(X,part_of some W)),
               multi(Pre-subClassOf(X,develops_from some Pre))
              ]).

You can load this from within a shell session by calling
“consult(nc)”. Execute it using “+” like this:


?- +nc.

A new IRI is generated, and you will be prompted for template values, the first one is the class label:


class'http://purl.obolibrary.org/obo/FBbt_10005990'.

% Template: annotationAssertion(label,http://purl.obolibrary.org/obo/FBbt_10005990,literal(_G83))
% Enter value: _G83 >> 

Type a value and hit enter. Fill in values for other fields. If it’s a
multi-valued field, keep adding new entries and then hit “enter” when
done:


% Enter value: _G83 >> neuron ABC
% Val=neuron ABC
annotationAssertion(label,'http://purl.obolibrary.org/obo/FBbt_10005990','neuron ABC').

% Template: subClassOf(http://purl.obolibrary.org/obo/FBbt_10005990,_G97)
% Enter value: _G97 >> neuron
% Val=neuron
'http://purl.obolibrary.org/obo/FBbt_10005990'> 

% Template: subClassOf(http://purl.obolibrary.org/obo/FBbt_10005990,part_of some _G108)
% Enter value: _G108 >> mushroom body
% Val=mushroom body
'http://purl.obolibrary.org/obo/FBbt_10005990'> 

% Template: subClassOf(http://purl.obolibrary.org/obo/FBbt_10005990,develops_from some _G122)
% Enter value: _G122 >> 

The database hasn’t changed yet. The axioms to be added are
summarized, then you’re prompted:


% ------------------
% AXIOMS TO ADD:
% ------------------
% class'http://purl.obolibrary.org/obo/FBbt_10005990'.
class'http://purl.obolibrary.org/obo/FBbt_10005990'.
% annotationAssertion(label,'http://purl.obolibrary.org/obo/FBbt_10005990','neuron ABC').
annotationAssertion('http://www.w3.org/2000/01/rdf-schema#label','http://purl.obolibrary.org/obo/FBbt_10005990',literal('neuron ABC')).
% 'http://purl.obolibrary.org/obo/FBbt_10005990'<neuron.
subClassOf('http://purl.obolibrary.org/obo/FBbt_10005990','http://purl.obolibrary.org/obo/FBbt_00005106').
% 'http://purl.obolibrary.org/obo/FBbt_10005990'<part_of some 'mushroom body'.
subClassOf('http://purl.obolibrary.org/obo/FBbt_10005990',someValuesFrom('http://purl.obolibrary.org/obo/TODO_part_of','http://purl.obolibrary.org/obo/FBbt_00005801')).
% OK? [enter for yes, any other char for no]

% Set ontology to http://purl.obolibrary.org/obo/fbbt.owl
% Asserting class'http://purl.obolibrary.org/obo/FBbt_10005990'.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting annotationAssertion(label,'neuron ABC','neuron ABC').
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting 'neuron ABC'<neuron.
 into http://purl.obolibrary.org/obo/fbbt.owl
% Asserting 'neuron ABC'<part_of some 'mushroom body'.
 into http://purl.obolibrary.org/obo/fbbt.owl
% AXIOMS ADDED. Type "undo." to retract.
true.

Web interface

It’s also possible to start up bomshell with an embedded ClioPatria
web server. This allows simultaneous querying and ontology
manipulation through both the command line and a web browser pointing
to localhost. Configuring the webserver is outside the scope of this
tutorial.

Finding out more

The shell interface is a quick and dirty wrapper around other Thea
modules. You can figure out exactly what a shall command does by using
the prolog “listing” command. E.g. “listing(q).”.

Consult the Thea OWL Lib
website
for more information.

Troubleshooting

JPL installation

The current SWI dmg file for Snow Leopard doesn’t appear to install
JPL correctly. This may be temporary. You may have to obtain the SWI source and do this:


cd packages/jpl
./configure
sudo make install

Support for OWLAPIv3 in Thea2

Thea2 now wraps OWLAPI v3. Support is provided for pellet and hermit out of the box.

There is now also additional command line support.

  • download and install SWI-Prolog
  • download Thea2 (for now you have to git clone and get the owlapi3 branch)
  • Add Thea2 to your path:

(assuming you install in ~/thea2)

export PATH="$PATH:$HOME/thea2"

You can then use the thea-jpl script, which takes care of JPL setup, adding the owlapiv3 jars to your classpath etc:

e.g.

thea-jpl testfiles/pizza.owl --reasoner pellet --reasoner-ask-all

shows all inferred axioms

For more examples, see Cookbook.txt

Thea paper accepted for OWLED2009

Provisional version of the paper up on:

(new) Thea website

(pending reivisions)

Towards portability with Thea2

The Thea OWL package is currently SWI-specific. It would be nice to use this with other prologs, particularly to take advantage of tabling in combination with DLP programs generated from OWL.

I’m impressed by the prolog-commons effort, particularly the convergence we are seeing between Yap and Prolog. Currently the core parts of Thea work with Yap, although there are some annoyances (Yap is unfamiliar with the useful debug/3). Unfortunately the excellent semweb package is still SWI-specific, so you will need to convert your ontology to axioms in prolog syntax first. OWL-XML should in principle be possible, as Yap-6 includes the SWI sgml package, although this appears not be working yet.

For other prologs the lack of a standard module system is the main hindrance. I have added a simple translator to the Thea2 makefile that will strip module declarations generating mostly ISO conformant prolog that can be used with GNU Prolog and XSB. Again, this is just for the core parts. XSB does include the sgml package so parsing OWL-XML is possible with some difficutly, although there are some annoyances such as incompatibilities in the load_structure/3 predicate.

I’m encouraged to hear that these 4 open source prologs are converging on a standard module system, so we should have better compatbility in the future. Converging on a FLI may be too much to ask, so it would be useful to have prolog implementations of xml and rdf parsing to use as fallbacks if the C libs are not present or usable.

Translating between logic programs and OWL/SWRL

Using the Thea2 library, it’ possible to translate certain OWL-DL ontologies into logic programs, and then query over them using LP systems such as Yap or XSB. Only the DLP subset is translated, and care must be taken to avoid common pitfalls.

It’s now also possible to do the reverse translation for a similar subset of LP programs. For example, if we have a file uncle.pl, with contents:
uncle_of(U,C) :- brother_of(U,P),parent_of(P,C).

We can do a simple syntactic translation to SWRL from the command line as follows:
swipl -g "[owl2_io],convert_axioms('uncle.pl',pl_swrl, 'uncle.swrl',owl, [])"

This yields the rather voluminous SWRL ontology:


<swrl:Imp>
<swrl:body>
<swrl:AtomList>
<rdf:first>
<swrl:IndividualPropertyAtom>
<swrl:argument1 rdf:resource="#v1"/>
<swrl:argument2 rdf:resource="#v3"/>
<swrl:propertyPredicate rdf:resource="http://example.org#brother_of"/>
</swrl:IndividualPropertyAtom>
</rdf:first>
<rdf:rest>
<swrl:AtomList>
<rdf:first>
<swrl:IndividualPropertyAtom>
<swrl:argument1 rdf:resource="#v3"/>
<swrl:argument2 rdf:resource="#v2"/>
<swrl:propertyPredicate rdf:resource="http://example.org#parent_of"/>
</swrl:IndividualPropertyAtom>
</rdf:first>
<rdf:rest rdf:resource="&rdf;nil"/>
</swrl:AtomList>
</rdf:rest>
</swrl:AtomList>
</swrl:body>
<swrl:head>
<swrl:AtomList>
<rdf:first>
<swrl:IndividualPropertyAtom>
<swrl:argument1 rdf:resource="#v1"/>
<swrl:argument2 rdf:resource="#v2"/>
<swrl:propertyPredicate rdf:resource="http://example.org#uncle_of"/>
</swrl:IndividualPropertyAtom>
</rdf:first>
<rdf:rest rdf:resource="&rdf;nil"/>
</swrl:AtomList>
</swrl:head>
</swrl:Imp>

Personally I prefer authoring rules in prolog syntax in emacs and then converting via Thea, but YMMV.

We can also translate the SWRL into a property chain axiom subPropertyOf(propertyChain([uncle_of,brother_of]),uncle_of), eliminating the rule altogether:


swipl -g "[owl2_io],convert_axioms('uncle.pl',pl_swrl_owl, 'uncle.owl',owl, [])"

If you look at the results in Protege4 you will see:


brother_of o parent_of ➞ uncle_of

Other patterns also recognized include domain/ranges, transitivity, invereProperties, etc

These kind of syntactic translations are useful for interoperability. The benefits of writing ontology fragments as rules becomes more apparent if we consider the following program processual_part_of.pl:


% if part_of holds for a process, the specific
% relation is processual_part_of
processual_part_of(P,W) :- part_of(P,W),process(W). %
% if part_of holds for an object, the specific
% relation is spatial_part_of
static_part_of(P,W) :- part_of(P,W),object(W). %
part_of(p1,p2).
part_of(ob1,ob2).
process(p1).
process(p2).
object(ob1).
object(ob2).

The two rules in this program can distinguish two relations based on the domain of the relation. For example, we can ask


?- processual_part_of(X,Y).

And get back the answers p1-p2, but not ob1-ob2.

This is a fairly trivial program. Yet it’s not immediately obvious how to code this in OWL. There is a way but it is rather ingenious/baroque, involving the creation of two fake properties and some self-restrictions and property chains.

Fortunately, Thea2 will help us with this too.


swipl -g "[owl2_io],convert_axioms('testfiles/processual_part_of.pl',pl_swrl_owl,'ppo.owl',owl,[])"

Here I show the results in Thea/owlpl syntax:


subClassOf('_d:process', hasSelf('_d:process_p')).
subClassOf('_d:object', hasSelf('_d:object_p')).
subPropertyOf(propertyChain(['_d:part_of', '_d:process_p']), '_d:processual_part_of').
subPropertyOf(propertyChain(['_d:part_of', '_d:object_p']), '_d:static_part_of').
propertyAssertion('_d:part_of', p1, p2).
propertyAssertion('_d:part_of', ob1, ob2).
classAssertion('_d:process', p1).
classAssertion('_d:process', p2).
classAssertion('_d:object', ob1).
classAssertion('_d:object', ob2).

here all the nasty ‘fake property’ stuff is taken care of for us behind the scenes.

We can demonstrate it works with the following sparql query via Pellet2:


SELECT * WHERE {?x <http://x.org#processual_part_of&gt; ?y}

which yields:


Query Results (1 answers):
x | y
=======
p1 | p2

Of course, there are many prolog programs that cannot be translated to OWL, and many OWL ontologies for which logic programs cannot be created. Each paradigm has its own strengths and weaknesses. Greater interoperability between the two can only help.

A prolog library for OWL2 and SWRL

Ontologies are vital for the life sciences. The Web Ontology Language (OWL) offers decidability of reasoning, and now with OWL2 and SWRL reasonably high levels of expressivity.

Vangelis Vassilidis and I are writing Thea2, based on his original Thea library. The redesign introduces prolog predicates for every OWL2 axiom, and prolog terms for owl class and property expressions. We use the SWI-Prolog semweb library for reading/writing to RDF. There is also an (optional) JPL bridge wrapping the Manchester OWLAPI.

There are a number of different reasoning strategies, including:

  • simple but limited backward chaining reasoning
  • using Grosof’s translation to DLP in conjunction with systems such as Yap, XSB or DLV
  • using standard OWL reasoners via JPL (DIG interface from Thea1 still needs ported)

Source: github
Documentation: pldoc