Define computables


This page describes the 'catkinized' version of KnowRob that uses the catkin buildsystem and the pure Java-based rosjava. The documentation for the older version, which was based on the rosbuild buildsystem and rosjava_jni, can be found here.


Computables serve for computing relations that would otherwise be manually asserted or inferred using logical inference. The computation can e.g. query external sources of information, or combine pieces of information in the knowledge base in order to create new statements. This concept is also known as “procedural attachments”, i.e. as methods for procedurally computing a relation that are attached to the semantic relation they calculate. Currently, there are two kinds of computables in KnowRob:

General concept

For computable properties to work, the following things need to be defined:

For including results by computable relations into the result set, use the rdf_triple(P, S, O) predicate instead of rdf_has(S, P, O). It is defined as

 rdf_triple(Property, Frame, Value) :-
   findall(SubProp, rdfs:rdfs_subproperty_of(SubProp, Property), SubProperties),
   member(SubProperty, SubProperties),
   (rdf_has(Frame, SubProperty, Value) [...]
   ; catch( rdfs_computable_triple(SubProperty, Frame, Value), error(instantiation_error, _), fail)
   ; user:rdf_triple_hook(SubProperty, Frame, Value)
   ).

The rdf_triple predicate combines the results of different inference methods: It first searches for sub-properties of the current property, and for each of them, first calls rdf_has for reading information asserted in the knowledge base directly, then calls all computable triples defined for any subproperty, and finally creates a hook to which other modules can attach. The code for managing the computables is contained in the module rdfs_computable.pl in knowrob_common.

Prolog computables

Prolog computables computes an OWL relation by evaluating a binary Prolog predicate.

Prolog properties

For Prolog properties, we will have a look at the knowrob:after relation between two temporal events. As a rather general property, it is defined in knowrob.owl and can be computed using a Prolog computable. First, the property is defined:

  <owl:ObjectProperty rdf:about="#after">
      <rdfs:range rdf:resource="#TimePoint"/>
      <rdfs:domain rdf:resource="#TimePoint"/>
      <rdfs:subPropertyOf rdf:resource="#temporallyRelated"/>
  </owl:ObjectProperty>

Then, the property is linked to the Prolog predicate comp_after for computing it:

  <computable:PrologProperty rdf:about="#computeAfter">
      <computable:target rdf:resource="#after"/>
      <computable:command rdf:datatype="&xsd;string">comp_after</computable:command>
      [...]
  </computable:PrologProperty>

Note that the target is described as a binary Prolog predicate (comp_after) that is supposed to handle the different cases of subject and/or object being bound. comp_after needs to be specified somewhere where it is available once knowrob.owl is loaded, which, in our case, is the module comp_temporal.

  % after(TimePoint, TimePoint)
  comp_after(Pre, After) :-
    rdf_has(Pre,   rdf:type, knowrob:'TemporalThing'),
    rdf_has(After, rdf:type, knowrob:'TemporalThing'),
    term_to_atom(P, Pre),
    term_to_atom(A, After),
    P<A.

This predicate first checks if the subject and property have the correct types, then transforms the time points into numerical values using term_to_atom, and finally compares them to check if Pre is smaller than After.

Prolog classes

The definition of computable prolog classes is similar to Prolog properties. You simply need to describe the class (here: DrinkingMug) and a binary predicate (here: comp_objectsOnTable(Inst, Class) ) that computes either instances of a class of the class of an instance.

  <computable:PrologClass rdf:about="#computeObjectOnTable">
    <computable:command rdf:datatype="&xsd;string">comp_objectsOnTable</computable:command>
    <computable:cache rdf:datatype="&xsd;string">cache</computable:cache>
    <computable:visible rdf:datatype="&xsd;string">unvisible</computable:visible>
    <computable:target rdf:resource="&knowrob;#DrinkingMug"/>
  </computable:PrologClass>  

SQL computables

SQL computables used SQL queries for reading external data. They are currently deactivated, but the code is still available in the rdfs_computable module. You need to make sure that ODBC is set up correctly. The following paragraphs have been kept for archival reasons, but SQL computables are currently not functional.

SQL properties

As mentioned before, the first step is to define the target to be computed. In this example, which can be found in ias_gram_human.owl, we choose to compute a property ias_human:xCoord, which is a specialisation of knowrob:xCoord (which is defined with the domain SpatialThing) for Point2D.

  <owl:DatatypeProperty rdf:ID="xCoord">
    <rdfs:domain rdf:resource="&kitchen;#Point2D"/>
    <rdfs:range rdf:resource="&xsd;#float"/>
    <rdfs:subPropertyOf rdf:resource="&kitchen;#xCoord"/>
  </owl:DatatypeProperty>

We use this property as the target for the computable that is arbitrarily named 'computeX'. If we wanted to compute knowrob:xCoord, we would have to use rdf:resource=“&kitchen;#xCoord” instead.

  <computable:SqlProperty rdf:ID="computeX">
    <computable:target rdf:resource="#xCoord"/>
    <computable:valueSelect rdf:datatype="&xsd;#string">
          SELECT robX FROM human_places_nom WHERE CONCAT(robX,robY) = '~frame~'
    </computable:valueSelect>
    <computable:frameSelect rdf:datatype="&xsd;#string">
          SELECT CONCAT(robX,robY) FROM human_places_nom WHERE robX = '~value~'
    </computable:frameSelect>
    <computable:frameValueSelect rdf:datatype="&xsd;#string">
          SELECT CONCAT(robX,robY), robX FROM human_places_nom
    </computable:frameValueSelect>
    <computable:user rdf:datatype="&xsd;#string">&db_user;</computable:user>
    <computable:password rdf:datatype="&xsd;#string">&db_pwd;</computable:password>
    <computable:database rdf:datatype="&xsd;#string">&db_db;</computable:database>
    <computable:cache rdf:datatype="&xsd;#string">nocache</computable:cache>
    <computable:visible rdf:datatype="&xsd;#string">unvisible</computable:visible>
  </computable:SqlProperty>

Apart from the target and some auth information to access the database, the most important parts are the three SQL queries. Depending on which variables in the query are bound (subject, object, or none of them), the system automatically chooses the right one. If the subject is bound and the object unbound, it uses valueSelect, if the object is bound and the subject unbound, it uses the frameSelect, and if both are unbound, it uses the frameValueSelect.

The results are further processed: In the case of datatype properties, they are wrapped in the literal(…) predicate, specifying their XSD type. For object properties, the result is extended with the namespace of the property's range and, if the resp. instance does not exist yet, it is asserted according to the property's range.

The above property can then be called with

 rdf_triple(ias_human:xCoord, Obj, X).

SQL classes

The definition of computable SQL classes is rather similar to properties and will only be shortly explained. Obviously, the target class has to exist for the method to work. computeReaching reads human motion frames labeled as 'Reaching' from the database:

  <computable:SqlClass rdf:ID="computeReaching">
    <computable:target rdf:resource="&kitchen;#Reaching"/>
    <computable:command rdf:datatype="&xsd;#string">
          SELECT &action_id; FROM &tab_arm_beg; WHERE GOAL="Reaching"
    </computable:command>
    <computable:testCommand rdf:datatype="&xsd;#string">
          SELECT &action_id; FROM &tab_arm_beg; WHERE &action_id;=~instance~
    </computable:testCommand>
    <computable:user rdf:datatype="&xsd;#string">&db_user;</computable:user>
    <computable:password rdf:datatype="&xsd;#string">&db_pwd;</computable:password>
    <computable:database rdf:datatype="&xsd;#string">&db_human_db;</computable:database>
    <computable:cache rdf:datatype="&xsd;#string">nocache</computable:cache>
    <computable:visible rdf:datatype="&xsd;#string">unvisible</computable:visible>
  </computable:SqlClass> 

Here, we do not have the frame/value scheme, but rather one command for creating instances (command) and one for checking if an instance belongs to the respective class (testCommand).

Debugging

When something does not work, check the following. Most likely, there is a minor inconsistency in the OWL names that makes the whole process break.

 guitracer, spy(yourpredicate), rdf_triple(knowrob:pred, Subj, Obj). for Prolog computables
 guitracer, spy(rdfs_computable_sql_triple), rdf_triple(knowrob:pred, Subj, Obj). for SQL computables

Some general remarks: