Monthly Archives: February 2009

CLPSE 2009 workshop

I’m co-organizing, together with Ulrich Neumerkel, an ICLP’09 workshop on software engineering:

If you’re working in any topic related to software engineering in the context of logic programming applications or developing a sizable logic programming application consider submitting your work to the 4th International Workshop on (Constraint) Logic Programming and Software Engineering. See the URL above for details.

Using both object proxies and regular objects

During the last three days I was working with Artur Miguel Dias, the author of CxProlog, rewriting P-FLAT, a Prolog toolkit for teaching Formal Languages and Automata Theory, as a Logtalk application, tentatively named L-FLAT. We made great progress and the final version of L-FLAT is going to be smaller, more portable, and both simpler to maintain and extend than the original plain Prolog application. One of our goals is to allow users to use both object proxies and regular objects when representing Turing Machines, Pushdown Automata, Context Free Grammars, and other concepts and mechanisms supported by L-FLAT. This flexibility allows users to represent e.g. a simple Finite Automaton with a small number of states and transitions as an object proxy (i.e. as a Prolog compound term; see my previous post) that might be entered interactively at the command-line:

    1,                                    % initial state
    [1/a/1, 1/a/2, 1/b/2, 2/b/2, 2/b/1],  % transitions
    [2]                                   % final states

It also allows users to represent e.g. a complex Turing Machine with dozens of transitions as a regular object, defined in a source file:

:- object(copyTM,
        q1/a/'X'/'R'/q2,   q1/b/'Y'/'R'/q5,   q1/'B'/'B'/'L'/q7,
        q2/a/a/'R'/q2,     q2/b/b/'R'/q2,     q2/'B'/'B'/'R'/q3,
        q3/a/a/'R'/q3,     q3/b/b/'R'/q3,     q3/'B'/a/'L'/q4,
        q4/a/a/'L'/q4,     q4/b/b/'L'/q4,     q4/'B'/'B'/'L'/q4,
                           q4/'X'/'X'/'R'/q1, q4/'Y'/'Y'/'R'/q1,
        q5/a/a/'R'/q5,     q5/b/b/'R'/q5,     q5/'B'/'B'/'R'/q6,
        q6/a/a/'R'/q6,     q6/b/b/'R'/q6,     q6/'B'/b/'L'/q4,
        q7/'X'/a/'L'/q7,   q7/'Y'/b/'L'/q7
:- end_object.

Using both object proxies and regular objects requires that all predicates that expect e.g. a Regular Expression to accept both an object identifier and an object proxy (a compound term) as argument. This might sound as an additional hurdle until you realize that an object proxy is also an instantiation of the identifier of a parametric object. As long as the parametric object defines the straightforward predicates that give access to its parameters, everything will work as expected. But how do we relate the regular objects and the parametric objects? Easy. If you want to represent e.g. some finite automata as instances of class fa and other finite automata as object proxies, simply define a parametric object as an instance of class fa. The parametric object parameters will be the properties that might be unique for a specific finite automaton. The parametric object define the predicates that give access to these properties. These predicates are the same that are used in class fa in the definition of all predicates that need access to finite automaton properties:

:- object(fa(_Initial, _Transitions, _Finals),
    initial(Initial) :-
        parameter(1, Initial).
    transitions(Transitions) :-
        parameter(2, Transitions).
    finals(Finals) :-
        parameter(3, Finals).
:- end_object.

Thus, using both object proxies and regular objects becomes trivial, fully transparent, and just a matter of defining the necessary parametric objects.

Efficient representation of data objects

Some Logtalk applications need to represent large numbers of immutable objects. These objects typically represent data that must be validated or used for data mining. This kind of data is often exported from databases and must be converted into Logtalk objects for further processing. The application logic is usually represented by a set of hierarchies with the data objects at the bottom. Although data conversion is most of the time easily scriptable, the resulting objects can take up significantly more space than a straightforward representation as Prolog facts. Logtalk object representation is simply not optimized for this kind of objects. Fortunately, this is one of those cases where you can eat the cake and keep it. The solution is to represent data as compact Prolog facts and to interpret those facts as object proxies. An object proxy is simply a Prolog compound term that can be interpreted as a possible instantiation of the identifier of a parametric object.

For a toy example, assume that your data represents geometric circles with attributes such as the circle radius and the circle color:

% circle(Id, Radius, Color)
circle('#1', 1.23, blue).
circle('#2', 3.71, yellow).
circle('#3', 0.39, green).
circle('#4', 5.74, black).
circle('#5', 8.32, cyan).

We can define the following parametric object for representing circles:

:- object(circle(_Id, _Radius, _Color)).
    :- public([
        id/1, radius/1, color/1,
        area/1, perimeter/1
    id(Id) :-
        parameter(1, Id).
    radius(Radius) :-
        parameter(2, Radius).
    color(Color) :-
        parameter(3, Color).
    area(Area) :-
        Area is 3.1415927*Radius*Radius.
    perimeter(Perimeter) :-
        Perimeter is 2*3.1415927*Radius.
:- end_object.

The circle/3 parametric object provides a simple solution for encapsulating a set of predicates associated with a given compound term. But how do we perform computations with the object proxies? We cannot send messages to Prolog facts! Or can we? Logtalk provides a handy notation for working with object proxies. For example, in order to construct a list with all circle areas we can write:

| ?- findall(Area, {circle(_, _, _)}::area(Area), Areas).
Areas = [4.75291, 43.2412, 0.477836, 103.508, 217.468]

The message sending control construct, ::/2, accepts as receiving object the term {Proxy}. Logtalk proves Proxy as a Prolog goal and, if successful, sends the message to the resulting term. Backtracking over the Proxy goal is supported, allowing all matching object proxies to be processed by a simple failure-driven loop (as implicit in the findall/3 call above).

You can find the full source code of this example in the current Logtalk distribution. In real applications, data objects, represented as object proxies, are tied to large hierarchies representing both knowledge about data and how to reason with it.

Writing portable Logtalk applications

Portable Logtalk applications often need to call built-in predicates whose name, arguments, and semantics differ for each supported back-end Prolog compiler. This is quite frequent as the current Prolog ISO standard only covers basic functionality. A common solution for these cases is to define a protocol abstracting common functionality and to implement this protocol in a set of objects, one for each back-end Prolog compiler. An alternative solution is to use Logtalk conditional compilation directives. As also found in some Prolog compilers (e.g. ECLiPSe, SWI-Prolog, or YAP), Logtalk supports if/1, elif/1, else/0, and endif/0 directives. The arguments of the if/1 and elif/1 directives are goals that are evaluated at compilation time, switching on and off the compilation of blocks of code. Together with the prolog read-only compiler flag, it is easy to define a single object encapsulating code for different back-end Prolog compilers. For example, assuming that your portable Logtalk application (running on GNU Prolog, SWI-Prolog, and YAP) needs access to the CPU time in seconds, you could write:

:- object(timing).
    :- public(cpu_time/1).
    :- mode(cpu_time(-number), one).
    :- info(cpu_time/1, [
        comment is 'Current CPU time in seconds',
        argnames is ['Seconds']]).
    :- if(current_logtalk_flag(prolog, gnu)).
    cpu_time(Seconds) :-
        Seconds is Miliseconds/1000.
    :- elif(current_logtalk_flag(prolog, swi)).
    cpu_time(Seconds) :-
        Seconds is cputime.
    :- elif(current_logtalk_flag(prolog, yap)).
    cpu_time(Seconds) :-
        statistics(cputime, [Miliseconds, _]),
        Seconds is Miliseconds/1000.
    :- else.
    cpu_time(_) :-
        throw(error(resource_error(predicate), cpu_time/1)).
    :- endif.
:- end_object.

A second example, cc, can be found on the current Logtalk distribution.

The conditional compilation directives can be used anywhere, as long as they encapsulate groups of directives or predicate clauses. Both solutions, using an object per back-end Prolog compiler or a single object with conditional compilation directives, have their pros and cons. The hard work, however, is usually to find the best abstraction subsuming the diversity of implementations.

Logtalk 10th anniversary

I have been so busy in the last weeks that I simply overlooked the Logtalk 10th anniversary a few days ago! The development of Logtalk 2.x started in January 1998, and the first stable version was released in February 9, 1999. Ten years later, developing Logtalk is still fun and rewarding, thanks to all the contributions from users and Prolog implementors. Keep your feature requests and bug reports coming! Work in the next stable version is progressing nicely and, with your help, I plan to keep developing and improving Logtalk for the next ten years. If I can make a wish: don’t be shy about what you’re doing with Logtalk. Stop by the Logtalk forums, talk a bit about your applications, and share your development experience.

Making your Logtalk objects multi-threading ready

Even if you’re not currently using Logtalk high-level multi-threading support to speed up your application in your shining new multi-core hardware, it’s quite easy to make your Logtalk objects and libraries multi-threading ready. Here’s how:

First, locate all your objects defining predicates that have side-effects. For example, predicates that perform input/output operations or use the (object) dynamic database. Second, add synchronized/1 directives for those predicates. Third, well, there is not third step.

A simple example, based on the Logtalk gensym library object:

:- public(gensym/2).
:- synchronized(gensym/2).
gensym(Base, Unique) :-
    retract(base_(Base, OldInt)) ->
    asserta(base_(Base, NewInt)),
    number_codes(NewInt, NewCodes),
    atom_codes(NewAtom, NewCodes),
    atom_concat(Base, NewAtom, Unique).

Using the synchronized/1 directive guarantees that two or more threads concurrently calling the gensym/2 predicate will not step on each other’s toes. Synchronized predicates are silently compiled as normal predicates when using back-end Prolog compilers that don’t support multi-threading programming, so there’s no penalty when running single-threaded.

New GNU Prolog version (1.3.1)

GNU Prolog is one of my favorite Prolog compilers. True, it’s not the fastest system nor the one with most features. It’s, however, one of the free and open source Prolog compilers that more closely complies with the ISO Prolog Part 1 standard. GNU Prolog is one of the compilers I use daily to develop and check the portability of the Logtalk code base. Daniel Diaz just released version 1.3.1:

Support for this new version is already included in the latest Logtalk development version (r4695).

Prolog development tip: whenever you need to check the ISO Prolog standard and you don’t a have a copy at hand, take a look at the GNU Prolog manual. ISO Prolog predicates are clearly marked and described in detail (including template, modes, and exception terms).

SICStus Prolog “spdet” utility

Is unwanted backtracking hurting your application performance? Getting some puzzling answers that should not be there? SICStus Prolog includes a determinacy checker, spdet, originally written by Dave Bowen and Peter Schachte, for spotting non-deterministic predicates. A must have tool. Have you tried it recently in your code? You might be surprised by the results.

Revamped Logtalk “report” compiler option

The next Logtalk stable release will feature a revamped report compiler option. A new option value, warnings, reduces compilation reporting to warnings. If your Logtalk application comprises a large number of source files, defining a large number of entities, I suspect that you will appreciate the simplified compilation reports. If you don’t want to wait for the next stable release, the new warnings option is already available in the current development version.

ECLiPSe 6.x and singleton variables

ECLiPSe 6.x, recently released, features an improved compiler, which, among other goodies, improves detection of singleton variables:

Additional singleton warnings: The new compiler will detect additional cases of singleton variables, namely those that occur only once in a branch of a disjunction.

This may sound like a mandatory feature until you realize that most other Prolog compilers fail to detect such cases of singleton variables.