dlvhex  2.5.0
The C++ Plugin Framework

Data Structures

class  PluginAtom
 Interface class for external Atoms. More...

Detailed Description

Introduction

The dlvhex reasoner evaluates Answer Set Programs with external atoms. One important design principle was to provide a mechanism to easily add further external atoms without having to recompile the main application. A plugin is a shared library that provides functions to realise custom external atoms. Furthermore, a plugin can supply rewriting facilities, which may alter the input logic program prior to evaluation. Plugins can be written in C++ as described below or in Python as described here; the latter does not have all features of the C++ version but should be sufficient in almost all cases.

This Section gives an overview of dlvhex plugins and external atoms.

The External Atom Function

Formally, an external atom is defined to evaluate to true or false, depending on a number of parameters:

However, it is more intuitive and convenient to think of an external atom not as being boolean, but rather functional: Depending on a given interpretation and a list of input constants, it returns output tuples. For instance, the external atom to import triples from RDF files has this form:

   &rdf[uri](X,Y,Z)

where uri stands for a string denoting the RDF-source and X, Y, and Z are variables that represent an RDF-triple. The function associated with this atom simply returns all RDF-triples from the specified source. Obviously, in this case the interpretation is ignored.

Information Flow

The interface that is used by dlvhex to access a plugin follows very closely these semantics. For each atom, a retrieval function has to be implemented, which receives a query-object and has to return an an answer-object. The query-object carries the input interpretation as well as the ground input parameters of the external atom call, while the answer object is a container for the output tuples of the external atom's function.

Types of Input Parameters

Theoretically, it is completely up to the atom function how to process the interpretation together with the input constants, which are basically only names. In practice however, only parts of the interpretation might be needed (if at all). Considering this as well as for efficiency reasons, we created two (in the implementation three, see below) categories of input parameters:

A parameter of type "Constant" is not related to the interpretation at all, like in the previous example of the RDF-atom. A parameter is of type "Predicate" means that all facts in the interpretation with this predicate are necessary for the atom. Let's assume, we have an external atom that calculates the overall price of a number of books given by their ISBN number:

   &overallbookprice[isbn](X)

The single input parameter of this atom would be of type "Predicate", meaning that not the constant itself is necessary for the atom's function, but the part of the interpretation with this predicate. So if we have, e.g.,

\[ I=\{{\rm isbn}({\rm 0{-}19{-}824183{-}6}), {\rm isbn}({\rm 0{-}201{-}99954{-}4}), p(a), q(b),\ldots\} \]

the atom's function will be called with a "reduced" interpretation:

\[ I=\{{\rm isbn}({\rm 0{-}19{-}824183{-}6}), {\rm isbn}({\rm 0{-}201{-}99954{-}4})\} \]

Specifying the type of input parameters not only helps to single out the relevant part of the interpretation, but also supports dlvhex in calculating the dependencies within a HEX-program.

Writing a C++ Plugin

We wanted to keep the interface between dlvhex and the plugins as lean as possible. Necessary tasks are:

Usual tasks for implementing a plugin interface are at least one of the following. We give the most usual implementation tasks first:

In particular, the task of defining external atoms which can be used in the HEX-program is done by implementing a class derived from PluginAtom and registering it via PluginInterface::createAtoms. Each such class defines exactly one external predicate (e.g. &concat) by implementing the method PluginAtom::retrieve, which comes in two overloaded versions depending on whether customized learning techniques shall be used or not.

For details about each of these tasks see the respective method documentation, the test plugin in testsuite/TestPlugin.cpp, the internal plugins

Implementing External Atoms

For implementing external computations there are two very different possibilities: ComfortPluginAtom and PluginAtom.

It is recommended to start prototyping using ComfortPluginAtom and then later reimplement performance-critical external computations in the PluginAtom interface. (The HEX programs do not change at all, just the implementation of the external atom.)

In addition to the actual semantics of an external atom, the class PluginAtom allows allows for defining customized learning functions. To this end, the method PluginAtom::retrieve comes with an overloaded version which gets a pointer to a NogoodContainer where customized nogoods can be added to restrict the search space. For instance, the nogood { p(a), -q(a), -&diff[p,q](a) } encodes that whenever the atom p(a) is true and the atom q(a) is false, then the atom &diff[p,q](a) must be true (i.e. must not be false) since constant a will be in the output of the set difference of p and q. We refer to the classes Nogood and NogoodContainer for details. Moreover, the class ExternalLearningHelper contains some methods which help with the construction of nogoods.

In TestPlugin.cpp, some plugin atoms are implemented both using PluginAtom and ComfortPluginAtom in order to provide an example of the differences.

Building Plugins

We provide a toolkit for building plugins based on the GNU Autotools (http://sourceware.org/autobook/) environment. This means that you will need the respective tools installed on your system - which is usually no problem, since they are provided as packages by all major linux distributions. You need packages for libtool, automake, and autoconf. We also provide a dlvhex.m4 script for easier configuration of DLVHEX plugins, see for its usage the dlvhex-stringplugin or the dlvhex-scriptplugin.

Using a C++ Plugin

In order to load a Python-implemented plugin stored as shared object in a directory PATH, pass the additional option

 --plugindir=PATH 

to dlvhex. Alternatively, you make install the plugin in the global plugin directory by calling make install.