🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #1363

The Craft of Prolog pp. 126-130

#1363
From: Anjo Anjewierden
Date: Fri, 02 Nov 1990 16:27
92 lines
3686 bytes
I read:

	Richard A. O'Keefe, "The Craft of Prolog", MIT Press 1990.

with great interest.  There is at least one section that may be
inconsistent with statements made elsewhere in the book.  Section 4.4
gives the following problem (the section is about reducing the
search space):

The problem is as follows:

	"D1, D2, ..., D9 are distinct decimal digits, none of them
	zero, such that for each 1 <= n <= 9 the n digits D1 ... Dn
	form a number which is divisible by n." [p. 126]

A Prolog program solving this problem is the following (I have paired
the select/3 and divisible/2 calls inside answer/1):

%   "The Craft of Prolog", p. 127

divisible(N, Ds) :-
	divisible(Ds, 0, N).

divisible([], 0, _).
divisible([D|Ds], R0, N) :-
	R1 is (R0*10 + D) mod N,
	divisible(Ds, R1, N).

%   "The Craft of Prolog", p. 127 (adapted)

answer(Solution) :-
	Solution = [D1,D2,D3,D4,D5,D6,D7,D8,D9],
	R0 = [1,2,3,4,5,6,7,8,9],
	select(D1, R0, R1),	divisible(1, [D1]),
	select(D2, R1, R2),	divisible(2, [D1,D2]),
	select(D3, R2, R3),	divisible(3, [D1,D2,D3]),
	select(D4, R3, R4),	divisible(4, [D1,D2,D3,D4]),
	select(D5, R4, R5),	divisible(5, [D1,D2,D3,D4,D5]),
	select(D6, R5, R6),	divisible(6, [D1,D2,D3,D4,D5,D6]),
	select(D7, R6, R7),	divisible(7, [D1,D2,D3,D4,D5,D6,D7]),
	select(D8, R7, R8),	divisible(8, [D1,D2,D3,D4,D5,D6,D7,D8]),
	select(D9, R8, R9),	divisible(9, [D1,D2,D3,D4,D5,D6,D7,D8,D9]).

If you study the remainder of the book it is not at all difficult
to see what is wrong with this program: why is the partial solution
represented as a list?  By the time answer/1 gets to the last sub-goal
it will have considered D1 8 times, D2 7 times (etc.).

Applying the principle of not wasting space and time I arrived at:

%   Anjo Anjewierden, University of Amsterdam, 02/10/90

%   d(+N, +Value, +Digit, -NewValue)
%
%   Is true if appending Digit to Value is divisble by N
%   (all base 10).  Example: d(3, 12, 3, 123) is true
%   because 123 is divisible by 3.

divisible(N, Value, Digit, NewValue) :-
	NewValue is (10 * Value) + Digit,
	0 is NewValue mod N.


answer([D1,D2,D3,D4,D5,D6,D7,D8,D9]) :-
	R0 = [1,2,3,4,5,6,7,8,9],
	select(D1, R0, R1),	divisible(1,  0, D1, V1),
	select(D2, R1, R2),	divisible(2, V1, D2, V2),
	select(D3, R2, R3),	divisible(3, V2, D3, V3),
	select(D4, R3, R4),	divisible(4, V3, D4, V4),
	select(D5, R4, R5),	divisible(5, V4, D5, V5),
	select(D6, R5, R6),	divisible(6, V5, D6, V6),
	select(D7, R6, R7),	divisible(7, V6, D7, V7),
	select(D8, R7, R8),	divisible(8, V7, D8, V8),
	select(D9, R8, []),	divisible(9, V8, D9, _).

In Quintus Prolog 2.4 the O'Keefe version takes 0.9 seconds and my
version takes 0.5 seconds.  If you want you can apply the same
problem specific optimisations that O'Keefe uses and make it a lot
faster still.

I would greatly appreciate any comments on the above as I'm
currently writing a review of the book.

:- Anjo, !.

%--------------------------------------------------------------------------
%			    Anjo Anjewierden	NET: anjo@swi.psy.uva.nl
%
%   Department of Social Science Informatics
%   University of Amsterdam, Herengracht 196	TEL: +31 20 525 2337
%         1016 BS Amsterdam, The Netherlands    FAX: +31 20 525 2347
%---------------------------------------------------------------------------
Technical Details
Message-ID: <4473@swi.swi.psy.uva.nl>
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!mcsun!hp4nl!swi.psy.uva.nl!anjo

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!mcsun!hp4nl!swi.psy.uva.nl!anjo
From: anjo@swi.psy.uva.nl (Anjo Anjewierden)
Newsgroups: comp.lang.prolog
Subject: The Craft of Prolog pp. 126-130
Message-ID: <4473@swi.swi.psy.uva.nl>
Date: 2 Nov 90 16:27:04 GMT
Reply-To: anjo@swi.psy.uva.nl ()
Organization: SWI, UvA, Amsterdam
Lines: 92