This is an old revision of the document!


Define computables

Computables serve for computing relations instead of inferring them. This can be done by querying external sources of information or by combining the information in the knowledge base in order to create new statements. This kind of 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:

  • computable classes, which create instances of their target class, and
  • computable properties, which compute relations between instances.

For each of them, two techniques are supported:

  • SQL computables, which use SQL queries for reading external data, and
  • Prolog computables, which evaluate a binary Prolog predicate that computes an OWL relation

Some general remarks:

  • Computables should be defined in their own module; the computables for temporal relations (before, after, during etc), for example, are defined in the module comp_temporal. This helps to resolve conflicts if there are different computables for a relation (e.g. one observes and another one predicts a relation).
  • The &bla; identifiers are XML entities that are replaced with the string specified at the beginning of the file when the file is being loaded. They are useful for making the code a bit shorter and more readable, and also for ensuring consistency.

We will explain the two techniques (SQL and Prolog) for computable properties, while computable classes work in a rather similar way and will only briefly be described.

General concept

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

  • the property to be computed, including its domain and range (datatype, object prop and one-of supported)
  • an instance of ComputableProperty that has this property as its target
  • either a set of SQL queries or a Prolog predicate that is accessible when the query is executed

For including computable relations into the reasoning process, use rdf_triple(P, S, O) 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)
   ; rdfs_computable_compute_property_concatenation(SubProperty, Frame, Value)
   ; catch( rdfs_computable_triple(SubProperty, Frame, Value), error(instantiation_error, _), fail)
   ; user:rdf_triple_hook(SubProperty, Frame, Value)
   ).
rdf_triple first searches for sub-properties of the current property, and for each of them, calls first rdf_has for reading information asserted in the knowledge base directly, then tries to find property concatenations (currently unused), calls all computable triples and finally creates a hook where other modules can attach (currently e.g. GrAM action models).

rdfs_computable_triple handles caching issues and calls rdfs_computable_triple_1, which simply looks for and executes computables for SQL and Prolog.

 rdfs_computable_triple_1(Property, Frame, Value) :-
   catch(rdfs_computable_sql_triple(Property, Frame, Value), error(instantiation_error, _), fail)
   ; catch(rdfs_computable_prolog_triple(Property, Frame, Value), error(instantiation_error, _), fail).
The whole code for managing the computables is contained in rdfs_computable.pl in the module semweb.

Caveats

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.

  • is the right property being computed? knowrob:objectActedOn is something else than ias:objectActedOn
  • is there a typo anywhere in the namespaces or base URLs?
  • check if there is a hash sign # between the URL and the property name (if using XML entities, check if the hash is either part of the entity or written where the entity is being used in the code)
  • debug with the following calls and step through to check that the right computable is being found, that the right query is sent, or that your predicate performs the right computations.

 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

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).

Prolog properties

For Prolog properties, we will have a look at the knowrob:after relation between two temporal events. It assumed to be rather general, thus defined in knowrob.owl, and 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 computable that is attached to this property needs to be specified:

  <computable:PrologProperty rdf:about="#computeAfter">
      <computable:command rdf:datatype="&xsd;string">comp_after</computable:command>
      <computable:cache rdf:datatype="&xsd;string">dontCache</computable:cache>
      <computable:visible rdf:datatype="&xsd;string">unvisible</computable:visible>
      <computable:target rdf:resource="#after"/>
  </computable:PrologProperty>

Note that the target is described as in SQL properties, but instead of covering the different cases of bound/free variables with different SQL queries, we only specify one Prolog predicate (comp_after) that is supposed to handle them correctly. comp_after needs to be specified somewhere where it is available once knowrob.owl is loaded, which, in our case, is the gram_base.pl.

  % 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 really earlier than After.

  • Prolog computables can do much more than just compare values: Using the Java interface JPL, we included the ehow.com plan import as a Prolog computable datatype property which links Strings like “set a table” to plan specifications in OWL. The same technique was used to interface Prolog to ROS and read object poses from the jlo service. Rule knowledge (for unary or binary predicates) can be encoded in Prolog computables, when the body of the rule is checked in the computable.
  • When trying to use rdf_assert inside a Prolog computable, you are likely to get an error “operation would deadlock”. This happens when trying to modify the rdf database while rdf choicepoints are still open, e.g. not all solutions to all rdf_has have been found. Workarounds are sometimes possible by packing rdf_has inside a findall and by iterating over the results with member, or, if just one solution shall be found, by using the cut operator '!'.

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).

Prolog classes

The definition of computable prolog classes is similar to the preceding ones, 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>