A.I. programming in Prolog and Assembler

February 15, 2009

Assembly Language for Visual Prolog Meta-programming

(This is an experimental repost – for testing purposes, using  Scribefire. Original post is here). (more…)


July 20, 2008

Assembly Language for Visual Prolog Meta-programming

Visual Prolog Integrated...Image via Wikipedia
Back in 2005, while working in large-scale programming projects for data-mining in G.I.S. and Hydrology, I wrote a Prolog interpreter called G.I.S. Prolog, equipped with many extra predicates (such as functions to locate points inside polygons, etc).The G.I.S. Prolog interpreter was originally based on the “PIE interpreter” (included as free source-code in Visual Prolog) but it ended up enhanced with many extra predicates, as well as an improved core-level inference mechanism.
Ever since I started using the Visual Prolog compilers (and the PDC Prolog compilers preceding them) I was fascinated by the possibilities of implementing additional ISO-Prolog functionality in Visual Prolog through Assembly Language and ‘C’. Of course, such attempts are inherently limited by the internal design of Visual Prolog compilers. So, the only way to implement ISO-Prolog functionality in Visual Prolog is to extend the “PIE Interpreter” (and G.I.S. Prolog as its offspring). A multitude of extra predicates, implemented in pure Assembly language, became available through G.I.S. Prolog for easy immediate experimentation: Coding in G.I.S. Prolog produced immediate results, without any need for (often tedious) EXE-file compilation. Code modifications could therefore be done very quickly and most mistakes were (semi-)automatically corrected by the interpreter’s own enhanced error-checking capabilities.

Recently, I discovered some Assembly language techniques to enhance G.I.S. Prolog even further, potentially valuable for a multitude of other purposes. They also have an intrinsic fascination in themselves, as general tools for Prolog meta-programming.

E.g. here is an Assembly language predicate, that takes as inputs another (external) predicate’s memory-address and a (Visual Prolog-) argument-list, and calls this (external) predicate, using the (arbitrary-length-) list of N arguments, as arguments of “arity N”:

apply_func(PRED, [Arg,Arg2,…]) <=> PRED(Arg1,Arg2,…)

Now, in ISO-Prolog there is a standard predicate known as “univ”, written as “=..“, which turns a list like [PRED,ARG1,ARG2,ARG3…] into a predicate call such as PRED(ARG1,ARG2,…). However, this does not exist in Visual Prolog, which sacrifices such “luxuries” for speed (which is the reason I also often use ISO-Prolog compilers, such as LPA-WinProlog and SWI-Prolog).

Anyway… The code you are about to see can be useful more generally, as an example of Prolog meta-programming, implemented in Assembly Language. The only difference between the way it works for Visual Prolog and the way it might work for another Prolog (or -indeed- ANY programming language, using a ‘C’-calling convention) is the Visual-Prolog-specific structure of a LIST, which in Visual Prolog has a different form than in all other languages. If you understand Assembly Language and intend to use this code for other (meta-programming) tasks, all you have to do is modify just a couple of lines in the code that follows. However, before you (even begin to) look at the Assembly Language Code, the following simple definitions in Visual Prolog (5.*) are a prerequisite for easier understanding:

 	-(i,i,i) language c % <-- example domain
apply_func(DWORD,ListDomain) -(i,i) language c
% where arg-1 is a predicate-domain, such as "dom_iii"

After you compile the Assembly language code, you could create a simple “EasyWin” Visual Prolog project, with the following ines:

 % converts a predicate to a doubleword/address

 add3: dom_iii
func2dword(FUNC,DW):- DW = cast(dword,FUNC).

add3(_X,_Y,_Z,Out):- Out = _X+_Y+_Z,
 	write("out = ",Out), nl, !
 	write("error!\n"), Out=-1, !.
Out = apply_func(DW,[10,20,30]),
write("result = ",Out), nl, readchar(_).

%This program should produce "result = 60" (sum of [10,20,30]).

OK, so here is the Assembly language code:

; ==================== _apply_func.asm =====================
; Code for TASM 5 Assembler, command-line call for compilation:
; C:\TASM\BIN\TASM32.EXE /p /z /w2 /m2 /ml _apply_func.asm
MODEL    flat
public _apply_func    ; (i,i)
PROC _apply_func near
ARG    func:dword, list:dword
LOCAL    fcnt:dword
push    esi        ;
push    edi        ;
push    ebx        ;
push    ecx        ;
mov    ecx,[func]  ; function............ ARG 1
mov    esi,[list]  ; list................ ARG 2
xor    ebx,ebx     ; make EBX=0
mov    [fcnt],ebx  ; initialize local variable 'fcnt' to 0
lodsd              ; load the 1st list-element's "element-flag"
dec    al          ; decrement it, to check if it was a 1
jnz short @@x1     ; exit if not (i.e. if it's the list's end)
; ----------------- else...
@@L1:             ; loop to read the (Visual-Prolog-) arg-list
inc    ebx        ; increment ebx (counter for number_of_args)
lodsd             ; load next list-element (arg. of function)
push    eax       ; push it into the stack (for a function-call)
lodsd             ; load the pointer to next list-element in EAX
mov    esi,eax    ; now ESI = (pointer-to-) next list-element
lodsd             ; load element-flag of next list-element
dec    al         ; decrement it, to check if it was a 1
jz short @@L1     ; if so, not yet the list's end, so repeat!
; ================= else...
mov    [fcnt],ebx  ; store the number_of_args in local var. 'fcnt'
call   ecx         ; call the (external) function (given in ARG-1)
mov    ecx,[fcnt]  ; get the function's number of args from 'fcnt'
jcxz @@x2          ; if the called function had NO args, exit
; ------------------ else...
@@L3:              ; loop to POP function-args after the call
pop        edx     ; recover next argument from the stack
dec        ecx     ; decrement the remaining number_of_args
jnz short @@L3     ; if not zeroed, continue popping args...
; ------------------
pop        ecx     ;
pop        ebx     ;
pop        edi     ;
pop        esi     ;
ENDP _apply_func


  • A not-so-obvious advantage of this code is that any Prolog interpeters written on the basis of Visual Prolog’s “PIE engine” (such as G.I.S. Prolog) make extensive use of calls such as this, inside their inference engine; using Prolog-lists of arguments to be called by turning them into proper predicate calls of arity=N (where N is the size of the list). So, an Assembly language implementation of such a calling mechanism can speed up such an interpreter considerably, especially inside recursive calls or loops, which call other predicates repeatedly countless times…
  • Another not-so-obvious advantage is that -in this way- we managed to… trick Visual Prolog into doing “forbidden” predicate calls, such as PRED(arg1,arg2,….), where both the predicate’s functor and the arguments may appear as static data, stored in a Visual Prolog facts’ database.
  • Don’t ask me (yet) how to implement such tricks in Visual Prolog 6.* or 7.*; I still use the version 5.* compilers a lot, because of their speed, as well as robustness in foreign language calls.
Zemanta Pixie

September 27, 2007

reading/writing/sorting Prolog variables, using the original variable-names (LPA Prolog code)

Filed under: LPA Win-Prolog, Prolog, source code — Omadeon @ 2:17 pm

Typically, Prolog variables are assigned by the compiler “internal names”, so that it is impossible to sort them using their original names (those provided by the user or by an input file).

However, in LPA Win-Prolog it is possible to preserve the original variable names, as well as sort them on the basis of these names. Finally it is also possible to retrieve the variables with their original names. Some examples follow:

1) LPA Prolog has predicates handling variable names (eread/2 and eprint/2). E.g. if you want Prolog to read a term with variables, preserving user-given variable names and then printing them out, you can use code like this:

| ?- eread(EXP,Vars), nl, eprint(EXP,Vars), nl, nl, nl.
|: this(THING,V,X,W).
EXP = this(_38218,_38220,_38226,_38232) ,
Vars = [('THING',_38218),('V',_38220),('X',_38226),('W',_38232)]
| ?-  

In LPA Prolog, eread/2 reads a term with variables and the it produces a list of names-and-variables [(Name,Var)|…] as a second argument. This has elements like (‘THING’,_38218) -in this example- where ‘THING’ is the user-defined variable name and _38218 is an “internal variable code”, generated by the compiler. The second predicate eprint/2 is similar: If the second argument of eprint/2 is bound to the names-and-variables-list (extracted previously) then the result is a printout of the expression as it was originally entered, preserving all the user-defined variable names.

Now, here is another example, only slightly more complicated. This time, it uses a small source-code file, which you can create easily, by copying and pasting the code that follows into a text file (of extension ‘.pl’).

The program asks the user to type a list (consisting of variables and constants) and then it is required to sort the variables, finally printing-out the resulting list with Variables sorted, but with names exactly the same as those typed originally. So, here is a piece of code that reads such a list from a user-prompt, sorts the list with respect to its variables, and then prints out the resulting list, with all the variables sorted:

test:- repeat, write('type a list of variables and constants:'), nl,
    eread(List,VL), sort(VL,VLsorted), sort(List,List1), varsort(List1,VLsorted,ListOut),
    write('sorted w.r.t. variables: '), eprint(ListOut,VL), nl, 
    write('press escape to exit, any other key to go on: '), get0(CHAR), CHAR = -1, !.
removevar(V,[A|L],L):- V == A, !.
removevar(V,[A|L],[A|Lx]):- removevar(V,L,Lx).

varsort([],_,[]):- !.
varsort(L,[],L):- !.
varsort(L,[(_Name,V)|VL],[V|XL]):-  removevar(V,L,L2), !, varsort(L2,[(_,V)|VL],XL).
varsort(L,[_|VL],XL):- !, varsort(L,VL,XL).

This piece of code is complete; you can copy it, paste it to a file ando compile it in LPA Win-Prolog. After doing this, type ‘test’ at the Prolog prompt. You will get a dialogue such as this:

| ?- test1.
type a list of variables and constants:
|: [A,D,C,2,B,34,X,F,D].
sorted w.r.t. variables: [A,B,C,D,F,X,2,34]
press escape to exit, any other key to go on: |:
| ?-

The main predicate ‘test’ calls ‘eread/2’, which reads user- (or file-) input expressions and parses them into Prolog terms with variables. Then the variable-name-list is sorted. The original list is also sorted, and then the sorted variable names’ list is used to rearrange the sorted original list a second time, this time sorting it as regards variable names.

A very crucial predicate here is ‘removevar/3’, which is similar to the built-in predicate ‘remove/3’, removing an element of a list and producing the list without this element each time it’s called. However, unlike the built-in predicate ‘remove/3’, this one only deletes list-elements which are “identical to the first argument”, without doing any unification. I.e. it is capable of removing variables, if they exist in the list (of arg 2) but does not confuse them with other variables through unification.

Another new predicate in the code above is ‘ varsort’. It assumes that arg-1 contains an input-list (a mixture of variables and constants) and it makes use of the sorted list of variable names, to rearrange the list so that all the variable names are sorted, in the third (output-)argument:

[A,D,C,2,B,34,X,F,D] becomes [A,B,C,D,F,X,2,34] .

As an exercise, if you have some Prolog experience you can now try to write a similar piece of code that works on ANY kind of Prolog term, not just a list. If you do write such code, you can also send it as a comment in this posting, or an e-mail to omadeon@hotmail.com (with your name and any other details you’d like to see included), and I will publish it in this blog (with your name or alias) exactly as you’ve written it (provided of course that… it works 🙂 )!

September 21, 2007

Reading EXCEL CSV-files as Prolog Clauses (SWI-Prolog source-code)

stylized depiction of a csv text file
Image via Wikipedia

If you need to convert into Prolog terms “raw data” supplied in EXCEL csv-files, read on! The source code in this posting will read any CSV file, converting each semicolon-delimited line (or record) of the CSV file into a Prolog clause, asserted in RAM. It is also possible to use the same code to read data deliberately provided (e.g. by another application) as a CSV-file, but which is specifically intended for use as a set of Prolog clauses.

This code also uses a couple of specification predicates: time_field_type/1, field1_as_functor/1, and conv_csvhead/2. These predicates control the behaviour of the conversion process, as follows:

time_field_type/1 :

  • time_field_type(0). In this case, time-fields in the CSV file (of the form “HH:MM” or “HH:MM:SS…”) are translated into minutes, ignoring seconds or hundredths of a second.
  • time_field_type(1). In this case, time-fields in the CSV file (of the form “HH:MM” or “HH:MM:SS…”) are translated into seconds, ignoring hundredths of a second.
  • time_field_type(2). In this case, time-fields in the CSV file are kept as they are, as atoms (e.g. ’03:35′, ’12:45:20′, etc).


  • field1_as_functor(0): Each line in the CSV-file is interpreted as a prolog clause, where the functor of the clause is the first field of the record, and the other fields are arguments.
  • field1_as_functor(foo) (where ‘foo’ can be any atom): Each line in the CSV file is interpreted as a prolog clause, where the functor of the clause is foo (or any atom supplied as 1st argument to field1_as_functor/1) and all the fields are arguments.


  • This predicate is used to convert the contents of the first field (of the CSV-file) into a (user-defined) internal Prolog representation. It is used only if “time_field_type(0)” exists. For example, to convert records where the first field is a Prolog functor ‘job’ but the actual contents of this field are ‘j’ (for brevvity), using a definition “conv_csvhead(j,job)” will convert each ‘j’ into a functor ‘job’. (Use of conv_csvhead/2 is optional; in the default case, it does nothing!)

Finally, some notes:

  • The main predicate to call is “loaddb(CSVfile)“, where CSVfile can be e.g. “test.csv”.
  • Provision has been taken for special fields which contain Lists of items, comma-delimited. In EXCEL these fields will appear as longish strings, but this code was written to parse them as Prolog atom-lists. (Comment-out this section if you don’t need it).
  • The only type of field that is currently not converted into any meaningful internal representation is DATE. Dates are converted to atoms, just as they appear, without parsing their actual contents. (As an exercise, you can re-use parts of the same code to parse date-fields!) The honest reason for this omission is that… I didn’t need dates (in an application I am developing, for which this code was also written).

The source-code follows. There are useful comments inside this code. You can just copy and paste what follows from this point onwards, into a text file saved for compilation by SWI-Prolog, ending in “.pl”: (more…)

September 20, 2007

SWI-Prolog source code: Converting hours-and-minutes to integers (e.g. for use in CLP)

Filed under: CLP, Conversions, Prolog, source code, SWI-Prolog, time-predicates — Omadeon @ 5:31 pm

This short posting is about a useful piece of SWI-Prolog code I keep (re-)using, ever since I wrote it. It is a predicate that converts time (in an EXCEL-compatible format ‘HH:MM’ or ‘HH:MM:SS’) to integers expressing minutes only, e.g. integers suitable for use in CLP applications (Constraints Logic Programming over finite integer domains). I am developing a serious CLP application, during the last few weeks and I regard the following (bi-directional) conversion code as indispensable:

%%% Conversion of Hours-and-minutes to integers and vice-versa (e.g. for CLP problems)
%%% converts number of minutes to a valid time-string e.g. '03:05':
mins2hourmin(MINS,OUTX):- nonvar(MINS), MINS > 0,
    Hours is MINS // 60, Minsx is MINS mod 60,
    num2str2(Hours,S1x), num2str2(Minsx,S2x),
    swritef(OUTX,'%w:%w',[S1x,S2x]), !
    MINS = 0, OUTX = '00:00', !.
mins2hourmin(HMINx,HRi):- nonvar(HRi),
    sub_atom(HRi,0,2,_,A1x), atom_number(A1x,HOURx),
    sub_atom(HRi,3,2,_,A2x), atom_number(A2x,MINSx),
    HMINx is MINSx + 60*HOURx, !.
mins2hourmin(MINS1,OUTX):- nonvar(MINS1), MINS1 < 0,
    MINS is -MINS1,
    Hours is MINS // 60, Minsx is MINS mod 60,
    num2str2(Hours,S1x), num2str2(Minsx,S2x),
    swritef(OUTX,'-%w:%w',[S1x,S2x]), !.
%% the same predicate operating on Lists of time-entities: 
mins2hourmin_list([],[]):- !.
mins2hourmin_list([M|ML],[X|XL]):- mins2hourmin(M,X), !, mins2hourmin_list(ML,XL).

%%% an auxilliary predicate for mins2hourmin/2:
num2str2(N,Sx):- N >= 10, swritef(Sx,'%w',[N]), !
    swritef(Sx,'0%w',[N]), !.


Bridging gaps between Prologs (SWI-Prolog predicates implented in LPA Win-Prolog)

Filed under: Code Conversion, LPA Win-Prolog, Prolog, source code, SWI-Prolog — Omadeon @ 4:36 pm

Today I spent too much time trying to force a SWI-Prolog project (of timetable scheduling, custom-made for a specific company) to run in a different compiler: LPA Win-Prolog. I needed badly to use certain graphics routines and other goodies of LPA Prolog (a commercial compiler), entire volumes of them in fact. So, I ended up writing code in LPA Prolog that implements some quite common SWI-Prolog predicates. Here are some of them:

The SWI-Prolog predicate ‘between/3’ generates (non-deterministically) a number, ranging from a minimum value to a maximum Value (as ‘bound’ 1st and 2nd arguments). I.e., in the SWI-Prolog console:

?- between(1,3,X).
X = 1 ;
X = 2 ;
X = 3 ;

Well, here is an LPA Win-Prolog implementation of this predicate (also valid in any other ISO-compatible Prolog):

between(Min,Max,Out):- M2 is Min+1, M2 =< Max, between(M2,Max,Out).

OK, This was an easy example, while most probably the same code already exists in elementary Prolog textbooks. Here are some other (not-so-obvious) examples:

In LPA Prolog there are some very special, very efficient unique commands, like ‘find/3, which operates on ‘input streams’ to locate (sub-)strings inside them. Now, the so-called ‘input stream’ can itself (effectively) be just another string (turned into a stream through the special LPA command ‘<~’). The use of this predicate, ‘find/3’ to write quickly efficient code for non-deterministic search (of substrings inside larger strings) is a natural happy consequence. E.g.

findsubs(SubSTR,STR,Px):- len(SubSTR,Len), findrep(SubSTR,Len,Px) <~ STR.

findrep(_,Len,Px):- inpos(EndP), EndP > 0, Px is EndP-Len.
findrep(SubSTR,Len,Px):- find(SubSTR,0,Sx), +Sx=``, findrep(SubSTR,Len,Px). 

I wrote this code after understanding the (well-documented) similar non-deterministic predicate ‘replace’ (not a built-in command but given as simple source-code in LPA-Prolog’s Reference Quide, page 226). The reason I wrote it is because I needed it as a sub-predicate to implement of SWI-Prolog‘s superb predicate ‘sub_atom‘. (This was already used -alas in several places- inside the SWI-Prolog project, which was to be converted into LPA WIn-Prolοg).So, here is the resulting LPA-Prolog implementation of ‘sub_atom‘, valid for (almost) all possible flow-patterns (at least those used in my project, plus a few more):

(a description of sub_atom/5 from SWI-Prolog's Open Source documentation):
sub atom(+Atom, ?Before, ?Len, ?After, ?Sub)
    ISO predicate for breaking atoms. It maintains the following relation: Sub is a sub-atom of Atom
    that starts at Before, has Len characters and Atom contains After characters after the match.
?- sub_atom(abc, 1, 1, A, S).
 A = 1, S = b
   The implementation minimises non-determinism and creation of atoms. This is a very flexible
   predicate that can do search, prefix- and suffix-matching, etc.
% HERE is my LPA Win-Prolog (exact) implementation of 'sub_atom/5':
%%%%%%%%%% (also valid in most other ISO-ish Prologs) %%%%%%%%%%%%
% (i,i,i,o,o)
   nonvar(Atom), nonvar(Start), nonvar(Len), var(LenAfterX), var(SubX),
   cat(Lx,Atom,[Start,Len]), Lx = [_,SubX,End], len(End,LenAfterX).
% (i,o,i,i,o)
   nonvar(Atom), nonvar(Len), nonvar(LenAfter), var(Start), var(SubX),
   len(Atom,LenTotal), Start is LenTotal - LenAfter - Len,
   cat(Lx,Atom,[Start,Len]), Lx = [_,SubX,_].
% (i,o,o,o,i)  (effectively a non-deterministic search-function)
   nonvar(Atom), nonvar(Sub), var(SubLenx), var(LenAfterx), var(Startx),
   len(Sub,SubLenx),  atom_string(Atom,STR), atom_string(Sub,SubSTR), len(STR,Slen),
   findrep(SubSTR,SubLenx,Startx) <~ STR, LenAfterX is Slen-Startx-SubLenx.
% where 'findrep/3' was written previously as a part of 'findsubs' (top of this post).
   nonvar(Atom), nonvar(Start), var(Len), var(LenAfterX), var(SubX),
  cat(Lx,Atom,[Start]), Lx = [_,End], len(End,Len2),
  between(0,Len2,Lenx), cat(Lxx,End,[Lenx]),
  Lxx = [SubX,End2], len(End2,LenAfterX), Len=Lenx.
   nonvar(Atom), var(Start), var(Len), var(LenAfterX), var(SubX),
   len(Atom,Len1), between(0,Len1,Pos),
  cat(Lx,Atom,[Pos]), Lx = [_,End], len(End,Len2),
  between(0,Len2,Lenx), cat(Lxx,End,[Lenx]),
  Lxx = [SubX,End2], len(End2,LenAfterX), Len=Lenx, Start=Pos.
   nonvar(Atom), var(Start), nonvar(Len), var(LenAfterX), var(SubX),
   len(Atom,Len1), LenPre is Len1-Len, between(0,LenPre,Pos),
  cat(Lx,Atom,[Pos,Len]), Lx = [_,Mid,End],
  SubX = Mid, LenAfterX is Len1-Pos-Len, Start=Pos.

%%%%%%%%%% (end of code) %%%%%%%%

Well, that’s it, for the moment, I’m afraid.

I must go back to my project now, but (rest assured) I will be coming back here, soon, again and again, and again…

Blog at WordPress.com.