Simple console application

The "naive reverse" benchmark has a long history of being one of the most quoted and least predictive (!) indicators of Prolog implementation performance. So, with a nod toward irony, it is reproduced here as a model for simple console applications. It uses the standard, single-threaded startup entry (main/0) and contains no embedded C. It may be interpreted but uses no interpreted code when compiled.

To compile, link and run this example you need to create a directory that contains the three files provided here. You do not need to create an environment file for this application and it does not use a database. Open a command prompt window at the directory to execute the build process and run the program.

The build process itself is performed by two files. The build.bat file invokes apc32.exe and link.exe which should be found in your operating system PATH. Linking is invoked using the file objlist.txt. While for this example this seems unnecessary, it is done to reinforce the need to explicitly reference arity32i.lib which is not searched as a library automatically.

Of course, most programmers use some form of automated make facility, the details of which are unimportant here.

The two files for the build process are:

build.ari
apc32 simple /q -FoC:\ArityPrologTest\Examples\Simple\BLD\simple.obj
link /OUT:simple.exe /SUBSYSTEM:CONSOLE /ENTRY:main @objlist.txt /VERBOSE


objlist.txt
C:\ArityPrologTest\Examples\Simple\BLD\simple.obj
C:\ArityPrologTest\lib\arity32i.lib

After build, the program can be invoked directly as a console application. Make sure that arity32.dll is in the same directory as simple.exe or can be found in your operating system PATH.

The program itself (simple.ari) is as follows:

% ***************************************************************************
%
%    (simple.ARI) -- Simple console application
%
%    Copyright (C) 2013 Headspace Sprockets, LLC.
%
%    All rights reserved. This document may not be copied in any
%    form, whatsoever, without the express written permission of
%    Peter Gabel.
%
% ***************************************************************************

:- public main/0.

:- mode
    nrev(+,-/+):det,
    append(+,+,-/+):det,
    for(+,+,-),
    genlst(+,-).

main :-
    writeIntro(Intro),
    write(Intro),
    loop.

writeIntro('
Simple console application based on naive reverse.
(Not the best benchmark for Prolog, by the way.)
Try Length = 30 and Iterations = 1000000.
').

loop:-
    write('Length: '), read_line(0, SLength),
    write('Iterations: '), read_line(0, SIters),
    int_text(Length, SLength),
    int_text(Iters, SIters),

    do_nrev(Length, Iters, Lips, Time),
    nl,
    write('Lips: '), write(Lips), nl,
    float_text(Time, StringTime, fixed(3)),
    write('Time: '), write(StringTime), nl,
    nl, nl,
    loop.

do_nrev(Length, Iters, Lips, Time) :-
    genlst(Length, List),
    abstime(StartTime),
    runtest(Iters, List),
    abstime(MidTime),
    runcontrol(Iters, List),
    abstime(EndTime),
    nrev(List, List1),
    computeavgtime(EndTime, MidTime, StartTime, Iters, Ave, Time),
    LI is ((Length+1) * (Length+2)) / 2 + 1,
    Lips is integer(LI/Ave).


runtest(N, List) :-
    for(1, N, _),
    runtestonce(List),
    fail.
runtest(_, _).

runcontrol(N, List) :-
    for(1, N, _),
    runcontrolonce(List),
    fail.
runcontrol(_, _).    

runtestonce(List) :- nrev(List, _), !.

runcontrolonce(List) :- control(List, _), !.

nrev([], []).
nrev([H|T], L) :- nrev(T, L1), append(L1, [H], L).

append([], X, X).
append([H|T], X, [H|T1]) :- append(T, X, T1).

control(_, _).

computeavgtime(EA, MA, SA, Iters, AveTime, Time) :-
    Time is ((MA-SA) - (EA-MA)),
    AveTime is Time / Iters.

abstime(AbsTime) :-
    time(time(Hr,Min,Sec,Hun)),
    AbsTime is Hr*3600 + Min*60 + Sec + Hun/float(100).

for(I, I, I) :- !.
for(I, J, I).
for(I, J, K) :- inc(I, I1), for(I1, J, K).

genlst(0, []) :- !.
genlst(N, [N|X]) :- dec(N, N1), genlst(N1, X).

% end of file here