An CLP PDF
An CLP PDF
An CLP PDF
nski
Chair of Knowledge Engineering
Department of Informatics and Communication
Economic University
PL 40-226 Katowice, Poland
e-mail: antoni.niederlinski@ae.katowice.pl
c Antoni Niederli
Limited Copyright
nski
A secured PDF le of this publication may be reproduced, transmitted,
or stored in computer systems without written permission of the author.
It is freely downloadable from http://www.anclp.pl.
No part of this publication may be printed in any form or by any means.
ISBN 978-83-62652-08-2
Published by
Jacek Skalmierski Computer Studio
PL-44-100 Gliwice
ul. Pszczy
nska 44
tel. +48 (0)32 7298097, (0)506132960
fax +48 (0)32 7298549,
pkjs@pkjs.com.pl
Gliwice, 2014
Printed and bound in Poland
Alle Beschr
ankung begl
uckt.
Arthur Schopenhauer (1788-1860), Parerga und Paralipomena
Three friends, a Politician, a Doctor and a Mathematician, started on a summer walk-out in the enchanting Silesian Beskidy Mountains, when the Politician noticed a single black sheep in the middle of a grassland. All Silesian
sheep are black, he remarked. No, my friend, replied the
Doctor, Some Silesian sheep are black. At which point the
Mathematician, after a few seconds thought, said blandly:
In the Silesian Beskidy Mountains, there exists at least
one grassland, in which there exists at least one sheep, at
least one side of which is black.
Anonymouse
Contents
Forword
0.1 Main assumptions . .
0.2 What is in the book? .
0.3 How to use the book?
0.4 Acknowledgments . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1 Introduction
1.1 What is Constraint Logic Programming? .
1.2 Why use Constraint Logic Programming?
1.3 What do we mean by constraints ? . . . .
1.4 Constraint logic programming and
articial intelligence . . . . . . . . . . . .
1.5 Constraint logic programming and
operations research . . . . . . . . . . . . .
1.6 Constraint logic programming and
knowledge engineering . . . . . . . . . . .
1.7 Classifying problems . . . . . . . . . . . .
2 In the beginning was Prolog
2.1 Prolog basics . . . . . . . . . . .
2.1.1 Domain of inference . . .
2.1.2 Prolog and CLP programs
2.1.3 Modes of variables . . . .
2.1.4 Operations . . . . . . . .
2.1.5 Constraint propagation .
2.1.6 Tree search with no trees
2.1.7 Failing usefully . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
.
i
. iii
. viii
. xi
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
1
1
2
5
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
9
10
.
.
.
.
.
.
.
.
13
13
14
17
19
21
23
24
28
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 30
. 32
. 34
. 36
. 39
. 40
. 40
. 41
. 44
. 47
. 47
. 50
. 50
. 53
. 55
. 57
. 58
. 59
. 66
. 68
. 69
. 71
. 75
. 75
. 80
. 87
. 90
. 90
. 92
. 95
. 99
. 102
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2.2
2.3
2.4
2.5
2.6
2.7
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
113
113
114
114
116
116
3.3
3.4
3.5
3.6
3.7
3.8
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
117
119
120
123
124
129
129
131
133
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
138
143
144
145
147
148
149
151
152
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
159
159
160
162
164
164
165
167
169
172
174
175
178
179
181
181
184
192
195
4.7
4.8
4.9
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
196
199
200
207
208
208
208
211
212
214
222
222
226
233
236
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
245
245
246
247
247
249
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
249
251
251
252
254
256
256
259
261
263
265
268
269
271
274
280
solutions
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
280
284
286
289
291
293
295
297
300
302
302
304
307
311
314
317
317
320
320
324
328
333
334
339
341
346
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
357
357
358
360
361
363
366
367
370
371
373
376
6.12
6.13
6.14
6.15
6.16
6.17
6.18
6.19
Reading newspapers 2 . . . . . . . . . . . . . . . . . . . . .
Reading newspapers 3 . . . . . . . . . . . . . . . . . . . . .
Assembling bicycles . . . . . . . . . . . . . . . . . . . . . .
Ship unloading and loading . . . . . . . . . . . . . . . . . .
What is a job-shop? . . . . . . . . . . . . . . . . . . . . . .
A job-shop scheduling problem - benchmark MT6 . . . . . .
A dicult job-shop scheduling problem - benchmark MT10
Traveling Salesman Problems . . . . . . . . . . . . . . . . .
6.19.1 Hamiltonian circuits . . . . . . . . . . . . . . . . . .
6.19.2 Scheduling a process line . . . . . . . . . . . . . . .
6.19.3 Scheduling a salesman . . . . . . . . . . . . . . . . .
6.20 Appendices . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.20.1 The circuit.ecl module . . . . . . . . . . . . . . . .
6.20.2 The distance matrix.ecl module . . . . . . . . . .
6.21 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
380
385
389
403
408
412
416
430
431
433
436
441
441
442
442
488
Glossary
490
Bibliography
500
Index
506
List of Figures
1
2
3
4
5
6
.
.
.
.
.
.
.
.
.
. .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. viii
. ix
. ix
.
x
. xi
. xii
1.1
1.2
1.3
1.4
1.5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
3
4
5
6
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
2.14
2.15
21
27
37
42
44
47
60
60
63
64
65
76
79
80
81
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2.16
2.17
2.18
2.19
2.20
2.21
2.22
2.23
2.24
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
3.10
3.11
3.12
3.13
116
118
119
120
121
122
126
127
127
128
128
129
140
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
184
190
191
215
224
226
236
242
243
5.1
5.2
5.3
5.4
canibals
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
by
. .
. .
. .
. .
. .
. .
. .
. .
solution 1
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 86
. 89
. 90
. 92
. 95
. 97
. 99
. 102
. 110
.
.
.
.
.
.
.
.
.
5.5
5.6
5.7
5.8
5.9
5.10
5.11
5.12
5.13
5.14
5.15
5.16
5.17
5.18
5.19
5.20
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
6.10
6.11
6.12
6.13
6.14
6.15
6.16
6.17
6.18
6.19
6.20
6.21
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
359
363
367
368
372
375
375
381
381
391
392
393
394
395
396
396
409
413
417
418
428
6.22
6.23
6.24
6.25
6.26
6.27
6.28
428
429
429
431
432
435
439
446
List of Tables
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
3.1
4.1
4.2
4.3
4.4
4.5
4.6
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. .
. .
. .
. .
. .
x. .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . .
. . . .
. . . .
. . . .
. . . .
option
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
required, . . . . . . .
18
18
20
21
22
23
35
66
176
178
179
216
216
223
272
280
287
299
303
308
314
328
5.9
5.10
5.11
5.12
5.13
5.14
5.15
5.16
5.17
5.18
5.19
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
335
346
349
349
349
350
352
353
353
355
356
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
6.10
6.11
6.12
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
361
377
404
412
434
443
443
444
444
445
445
446
7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
7.9
7.10
7.11
7.12
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
456
461
467
470
471
472
482
483
483
484
484
485
Foreword
0.1
Main assumptions
ii
Foreword
iii
0.2
iv
Foreword
the relations between CLP and Operation Research, Articial Intelligence and
Knowledge Engineering.
Chapter 2 (In the beginning was Prolog) presents Prolog - the predecessor
of all CLP languages. It was the rst language that allowed the programmer to
specify only what is known about the problem and what goal is to be pursued,
while abstracting from mechanisms used to exploit the knowledge. The emphasis
is on ideas that were later on developed and extended in CLP languages, but
which are perhaps easier to grasp in a more simple setting. The examples
presented there belong to four categories, like all other CLP programs:
1. Examples of determining a feasible state (FS) in the problem state-space,
or simply said, at determining a full descriptions of some situations on the
basis of partial but sucient data. They include a.o. a set of examples
about conguring a system consisting of three dierent components with
dierent costs and dierent compatibility requirements. Their purpose
is to introduce the reader to the basic mechanisms of tree search and
constraint propagation as unication. The examples illustrate exhaustive
search and backtracking search for nding feasible congurations.
2. Examples of determining an optimum state (OS) in the problem state
space. This is illustrated by determining the least expensive feasible conguration using branch-and-bound search.
3. Examples of determining a feasible state trajectory (FST) in the statespace from some well-dened initial states to some well-dened nal states.
This is illustrated by the well-known Towers of Hanoi problem.
4. Examples of determining an optimum state trajectory (OST) in the statespace. This is illustrated by a number of well-known maze-walking, rivercrossing and jug lling puzzles.
The classes seem to exhaust all possible Prolog and CLP applications. The
Author never came across Prolog or CLP problems that could not be accommodated in one of those categories.
All examples in Chapter 2 are using Prolog as provided by the ECLi P S e
platform, referred to as ECLi P S e P rolog. Prolog programs have the extension
.pl. Compiling any Prolog program makes ECLi P S e use only those mechanisms
and standard constraints that belong to standard Prolog.
The question may well be asked, Why start with ECLi P S e P rolog, why
not with the much more powerful ECLi P S e CLP ? All the more so because
the mechanism of Prolog (standard backtracking with constraint propagation
via unication) diers from the mechanism of CLP (enhanced backtracking
with constraint propagation via consistency techniques). The answers to those
objections concentrate on purely tutorial reasons and are as follows:
1. Ideas that were later on developed and extended in CLP languages (like
declarativity, constraint propagation, logical inference by search with backtracking, branch-and-bound ) have their roots in Prolog, and are easier to
grasp in the more simple Prolog settings2 .
2. The basic elements of Prolog programs are the same as those for CLP
programs.
3. Prolog programs structure closely resembles CLP programs structure.
4. Prolog (in contrast to CLP) may be used to easily program exhaustive
search, which is a rather inecient search method and may be used only
for simple problems, but is the ancestor of all other search methods and
the knowledge of its mechanism promotes understanding of more ecient
and advanced search methods.
5. Last but not least - Prolog is readily available on the ECLi P S e platform.
Many examples solved in Chapter 2 are again invoked in later chapters to
show their solution with the help of more advanced CLP mechanisms.
All examples in Chapters 3,...,6 are using CLP as provided by the ECLi P S e
platform, referred to as ECLi P S e CLP . CLP programs have the extension .ecl.
Compiling any CLP program makes ECLi P S e use only those mechanisms and
standard constraints, which are supported by the CLP libraries declared at the
head of the program.
The topics presented in Chapters 3,...,6 have been dichotomized into following categories:
1. Goal -dependent categories:
the goal is to determine feasible solutions, which may be given by
either feasible states (FS) or feasible state trajectories (FST) ;
2 Thew
idea is: Start with the simple, gain mastery, move gradually to the complex.
vi
Foreword
vii
viii
Foreword
scribed by predicates, so the term predicate seems to obliviate the term function: there are no discernable operational dierences between their meaning.
So the term function will not be used further. Similarly, the name compound
term denotes either a predicate or a structure. No compound terms may
be found that are not dened as predicates or structures.
0.3
The reader is encouraged to solve all examples discussed in the book, in their
original version and in any conceivable modication, as well as examples provided in the Exercise sections. While doing this it should be remembered that
learning CLP is essentially a mix of trial and error with explorations aimed at
nding why something doesnt work. While learning CLP the old ski principle holds: if you dont fall, you wont learn! Learning CLP gives ample
opportunities for making mistakes, from simple formal mistakes detected by
ECLi P S e /, CLP , to sophisticated, dicult to diagnose, logical mistakes.
The basic software needed, available on the ECLi P S e website
http://www.eclipseclp.org/,
has to be downloaded. At the time of writing this book (2013), the software
available was in the Release 6.0_201 le dated 19-Feb-2013. The user is encouraged to read the installation notes, README_UNIX for Unix/Linux systems,
or README_WIN.TXT for Windows systems. The download results (for Windows
systems) in the directory
Program Files\ECLiPSe6.0,
in the C catalogue, and from the ECLiPSe6.0 directory the TKEclipse6.0 icon
may be put onto the desktop, (Figure 1).
ix
Foreword
The Compile option from this menu enables the loading and compilation of
any program with extension .pl (a Prolog program) or with extension .ecl (a
CLP program). All programs presented in this book are activated by inputting
the universal query top. Because top is used for all programs, it is worthwhile
to clean the memory before using it for another program. This can be done by
activating the option Clear toplevel module.
The option Help makes available the menu from Figure 4.
0.4 Acknowledgments
xi
user to paste a small CLP program and activate it with ENTER. The command
mode may be also used to run any CLP program by clicking its .ecl name.
0.4
Acknowledgments
The Author did not have the good luck to meet - early in his career - people
knowledgeable in Prolog or CLP, and enthusiastic about them. Having a controlengineering academic background and position, his education on Prolog and
CLP was entirely self-inicted, with the help of books and papers he read, and
software he used; they were authored mostly by people he has never even met.
Nevertheless, it seems they deserve to be given credit for the inspiration they
provided by their writing and their software.
The rst and most inuential book to be mentioned was authored by K.L.
Clark and F.G. McCabe (see [Clark-84]). It was a splendid tutorial, which
caused the Author to get Prolog-infected. He went through all their examples
in the early 80-ties, using a SINCLAIR ZX Spectrum microcomputer for a
microProlog interpreter running under CP/M, and distributed on audio cassette
tapes. It was with the help of this software that the Author started running
courses on Prolog for students at the Automation and Robotics stream at the
xii
Foreword
0.4 Acknowledgments
xiii
That was the beginning of fruitful and inspiring friendly contacts. Professor
Bart
aks insightful talks at a series of Workshops on Constraint Programming
for Decision and Control, run at the Institute of Automation of the Silesian
University of Technology in Gliwice, Poland, during years 1999-2005, was an important boost to the Authors work and the work of some of his Ph.D students
as well.
Thanks to the initiative of Professor Jerzy Goluchowski from the Economic
University (EU) in Katowice, the Author had the good chance to pursue his
CLP interest at the Chair of Knowledge Engineering (EU), starting 2009 with a
series of CLP lectures based on ECLi P S e CP S. The Author is indebted to Professor Goluchowski for relieving him from chores like attending meetings about
planning, proposals and policy, and from activities like fund raising, consulting,
interviewing. The writing of this book has been also inspired by the interest
shown by colleagues from the Chair.
The Author is grateful to his former Ph.D. students, especially Dr. L
ukasz
Domagala and Dr. Wojciech Legierski, for many fruitful discussions on CLP
and interesting examples of CLP.
His former colleagues from the Computer Control Group at the Faculty of
Automatic Control, Electronics and Computer Science of the Silesian University
of Technology in Gliwice, Poland: Drs. Jerzy Mosci
nski, Dariusz Bismor and
Krzysztof Czyz, helped him a lot by explaining peculiarities of Miktex used for
writing this book. He owe thanks to Dr. Jacek Loska for constantly keeping his
hardware and software alive and up-to-date.
The Author is grateful to Hakan Kjellerstrand from Sweden, who - at a
rather short notice - read the typescript of the rst edition of the book and
provided valuable feedback on many topics of importance.
Last but not least, the work done on this book would be unthinkable but
for the understanding and support of the Authors Wife Teresa, who patiently
tolerated for years his prolonged spiritual absence at home.
Obviously, the Author is solely responsible for all mistakes and misrepresentations that may eventually be found in this book.
Finally, the Author oers his deepest apologies to whomever he has neglected
to mention.
Gliwice, January 2014
Chapter 1
Introduction
1.1
Introduction
Readers familiar with Integer Programming will recognize the problem from
Figure 1.3 as such, see chapters 5 and 6.
1.2
A salient feature of combinatorial CSP and COP is that all variables take values
from nite domains. It follows that in theory any CSP and COP can either be
shown to have no solution or be solved using an algorithmically simple exhaustive
search or direct enumeration 2 approach. Therefore the wisdom of developing
special tools for such problems may be questioned. Why are present-day tools
for solving combinatorial CSP and COP, outlined in this book, better than
exhaustive search? The answer to this question is as follows:
2 I.e. generating one by one all n-tuples of the Cartesian product of variable domains and
testing whether they satisfy all constraints of the problem.
1. Because of the numerical eectiveness of determining CSP and COP solutions, which for exhaustive search and large numbers of variables is very
bad indeed. It means that the number of enumerations needed to get those
solutions may be exorbitant. E.g. consider a particular case of 30 variables, each one of them assuming 100 dierent values3 . The total number
of 30-variable sets (constituting what is usually called the state space)
amounts to 10030 = 1060 . Because humans are notoriously bad at understanding how large is a large number 4 , it is worthwhile to convert such
numbers into time. Suppose that the evaluation of a particular set of constraints for any of the 30 variable sets will take a microsecond. Evaluating
all sets will take 1054 seconds or 1054 /3600 hours or 1054 /(3600 24 365)
years. Obviously:
1054 /(3600 24 365) > 1054 /(10000 100 1000) = 1045 ,
so exhaustive search would need more than 1045 years, i.e. a time considerably in excess of the estimated age of the universe ( 1.4 1010 years). This
is what we mean by combinatorial explosion, or what Richard Bellman
(see [Bellman-61]) referred to as the curse of dimensionality. CLP lan3 This
4 This
is really a small problem compared with e.g. average university timetabling problems.
is best seen while watching budgetary discussions in any Parliament.
Introduction
guages cope (to some extent, not entirely) with such problem by early and
judicious use of problem constraints5 and use of implicit feasible problemspecic heuristics in order to substantially decrease the number of sets to
be tested.
2. Because of the declarativity of Prolog and CLP programs. Declarativity
means that a properly formalized description of the solved problem is tantamount to the program solving the problem. It is contrasted with imperativity (procedurality) based on designing algorithms needed to solve
problems. Declarativity means further that while using Prolog or CLP
languages no algorithms for problem solving need to be designed. The algorithms, which are of course necessary for any computer-based problem
solving, have been embedded into Prolog or CLP compilers. To simplify
a bit, it may be stated that the art of Prolog and CLP consists in designing such problem descriptions that are understood by Prolog or CLP
language compilers, and that ensure an ecient determination of the solution6 . However, it should be kept in mind that non-trivial complete Prolog
5 Those
6 Although
and CLP programs cannot entirely get rid of imperativity since they need
to some extent the xing of order for clauses to be executed, and need
commands for data to be imported and messages to be generated.
1.3
The term constraints deserves some attention. It is understood to mean anything that limits the freedom of action. Constraints are ubiquitous: any program
we write in any language is full of them. However, their meaning in imperative languages (like Pascal, C, C++) diers considerably from their meaning
in CLP languages. In imperative languages constraints are passive; that means
they may be used only if all their variables are grounded, and they are used as
tests for choosing the next step taken, see Figure 1.4.
Constraints in CLP languages are active; that means they may be used also
if some or all of their variables are free. Active constraints (denoted by various
symbols like # for nite domains or $ for real or symbolic domains) are used for
initiating a search for such variable groundings that satises them, see Figure
1.5.
(see e.g. [Apt-07]), and declarative programs are easier to understand, develop and modify,
it does not mean that using Prolog or CLP techniques is always plain sailing. It simply
means that diculties experienced while producing ecient algorithms are no longer present,
but instead a new set of diculties (luckily less formidable) appear while attempting to
design ecient declarative programs making judicious use of available built-ins. We never
get something for nothing.
Introduction
1.4
this is an operation costing both time and money. The developed application has minimized the number of times paints need to be changed in
lling customer orders, resulting in considerable savings;
scheduling production at a large manufacture and marketer of home appliances in order to better match customer demand and reduce response
time, while keeping low inventories of nished goods;
designing multi-constrained time-tables for engineers monitoring on a 24hour basis all computer and telecommunication systems in a large nancial
institution.
This set of examples has been considerably extended by Simonis (see [Simonis-10]),
who quotes the following interesting applications:
assembly line scheduling for Mirage 2000 ghter aircraft production;
various crew rostering systems like personnel planning for the guards in
jails or nurses in hospitals;
production of Belgian chocolates;
design of advanced signal processing chips;
design of print engine controller in Xerox copiers;
assigning ships to berths in container harbor;
scheduling Bandwidth on Demand.
Researchers, designers and users of AI products have always been confronted
with the need to solve dicult complex problems, see e.g. [Luger-98]. Exactly
the same problems are solved using constraint programming technology.
It is also worthwhile to note that the closeness of the connection between
Prolog/CLP and AI has deeper, more fundamental roots. This is so because AI
as known today may be dated from the failure of the General Problem Solver
(GPS) project7 .The critical step in solving a problem with GPS was the denition
of the problem space in terms of the initial state, the goal state to be achieved,
and the transformation rules dening feasible moves from state to state. Using an inference method called means-end-analysis, GPS would determine the
7 GPS was a computer program created in 1959 by Herbert A. Simon, J.C. Shaw, and Allen
Newell at the Carnegie-Mellon University in Pittsburgh, PA, USA.
Introduction
so called syntactic dierence between any initial state and the nal state, as
well as determine a logical operator that decreases this dierence. This strategy
proved successful for solving formalized symbolic problem, like e.g. theorems
proofs, geometric problems and chess playing. Encouraged by initial success,
Newell and Simon made attempts to increase the prowess of GPS by incorporating smarter reasoning techniques using more clever search algorithms, and
hoping it will eventually allow them to solve real-world problems outside the
nd a trajectory in problem space scheme. By and large, it proved a failure:
developing programs that could prove theorems of logic did not seem to provide techniques that could be readily adapted to other tasks. At the end of the
day these programs were very smart at logic, but still stupid when it came to
anything else. It was then widely recognized that a main characteristic of intelligent behavior was not so much general principles of reasoning applicable to
any eld of human activity, but rather detailed concrete knowledge of the very
narrow areas relevant to the problem solved. It turned out that for solving realworld problems plenty of relevant problem knowledge is needed, but the necessary
logical instrumentation is rather modest. Because it was impossible to model
intelligent behaviour which did not rely both upon specic domain knowledge
and sound reasoning, an AI paradigm emerged based on the requirement to put
both components in any AI programs. An obvious next step was to separate
(logically, structurally) in AI programs those two crucial components: domain
knowledge (usually presented in some declarative form and residing in one part
of the program) and reasoning available as a service provided by some other
program or another part of the entire program8 .
1.5
under constraints:
Ax = b
where x is an n-dimensional column vector of real or 0-1 decision variables, A
is an m n matrix of reals or 0-1 elements, and c is an m-dimensional column
vector of reals or 0-1 elements. Modern CLP platforms (including ECLi P S e )
provide ecient solvers for this type of problems. Whats more, CLP modelling and solving of operation research problems usually do not need the prior
transformation of those problems into some canonical form, and provide a large
number of global constraints that simplify both problem formulation and solution. The CLP- and OR- approaches to solving optimization problems have
been compared in a number of insightful publications, see e.g. [Hansen-03] and
[Milano-04]. A trend to integrate traditional OR techniques with CLP is also
clearly visible, see [Hooker-00] and [Hooker-07].
1.6
10
Introduction
1.7
Classifying problems
11
1. FS-type problems concerned with nding feasible states i.e. states satisfying all constraints of the problem. To this category belong most puzzles
and mind-teasers, for which partial data describing some situation is given
and the solver is expected to provide the missing facts so as to get a consistent situation. The importance of such puzzles for learning Prolog is
well illustrated by a number of specialized Prolog-Puzzle websites (see
e.g. [Edmund-10] or http://brownbualo.sourceforge.net/). They convey
in simple form problems that are present in such complicated real-world
applications as university time-tabling and industrial time-tabling. Unfortunately, those real-world applications are so complex and need so many
variables that they are hardly suitable for learning Prolog and CLP. FStype problems may be farther divided into:
Feasible conguration problems , which aim at selecting - from some
set - subsets meeting constraints of belongness and compatibility constraints .
Feasible assignment problems, aiming at nding - for any element of
some set - elements of another sets so as to fulll some constraints.
A type of assignment problems is often referred to as transportation
problems.
Feasible timetabling problems, aiming at pairing elements of some set
with elements of a set of time intervals.
2. FST-type problems concerned with nding feasible state trajectories i.e.
sequences of feasible states from some well dened feasible initial state to
some well-dened feasible nal state. This class of problems is generally
more dicult than the previous one. To this category belong puzzles
and mind-teasers, for which some moves need to be accomplished, e.g.
nding the way out of a maze, bringing people across a river or nding
the shortest path a traveling salesman has to take. They convey in simple
form problems that are present in many important industrial and business
applications. like scheduling of operations or routing of vehicles. FST-type
problems may be farther divided into:
Feasible sequencing problems, aiming at ordering elements of some
set so as to fulll some precedence constraints.
Feasible scheduling problems, aiming at ordering elements of some
set so as to fulll some precedence constraints and constraints on
available resources.
12
Introduction
Chapter 2
2.1
Prolog basics
13
14
(for a limited set of predicates) of universal character. This means that problem descriptions are in Prolog separated (in a conceptual and in a software
sense) from techniques needed to solve the problems. This means also that
Prolog/CLP are declarative: the problem description is the problem model is
the problem modeling program is the problem solving program. By problem description is meant a description understandable for the Prolog/CLP compiler
and assuring an ecient determination of the solution. Once more, the art of
Prolog/CLP programming consists of formulating such descriptions.
2.1.1
Domain of inference
15
16
predicate, e.g.:
likes(graduate_student(Somebody),
computer_science_subject(Something)).
A special case of predicates are functions 6 : all functions are predicates,
but not all predicates are functions. Therefore no distinction will further
be made between them. Because for some functions inx notation with
standard operators is normally used (e.g. X1 + X2, where "+" is the standard operator), such inx notation is also accepted by Prolog and CLP.
Predicates may be divided into:
1. Standard predicates (built-in predicates), dened and designed by
Prolog or CLP language designers, and made available to users.
They are farther divided into elementary predicates, dening basic
relations as given in libraries ic and branch_and_bound, with arguments contained at most in one list, and global predicates, dening
advanced relations as given in libraries ic_global, ic_cumulative,
ic_edge_finder, ic_edge_finder3, with arguments usually contained in many lists.
2. Private predicates, dened and designed by Prolog or CLP program
designers, with names dierent from those of standard predicates,
and with arbitrary number of lists.
a structure is presenting a tuple of a xed number of atoms, called its
arguments. Any structure has a name (which looks like an atom). The
number of arguments of a structure is called its arity. The name and
arity of a structure are together called its functor and is often written as
name/arity. Functors could be seen as general data types, arguments as
dening instances of those data types. Structures correspond to records
in other languages. Although structures look deceivably like predicates,
they dier from them because they do not contain variables; therefore are
always true.
a list of terms, including an empty list. A (nonempty) list may look like:
[a, b, "CDE", 5, F], an empty list is denoted by []. For details see
Section 2.1.8.
6 For a set of n variables with declared domains, a function is declaring - for some subset of
values of n-1 variables (called arguments) a unique value of the n-th variable, called (called
outputs)
2.1.2
17
18
Conclusion
True
False
True
False
Conclusion :- Condition
True
True
False
False
Condition
True
False
False
True
Conclusion
True
False
True
False
Condition Conclusion
True
True
True
False
19
1. The naming of private predicates 8 is entirely arbitrary save they are different from names of built-ins 9 .
2. Private predicate names may not convey any meanings, e.g. instead of
writing:
likes(Somebody, Something)
we could write as well:
blah_blah(Somebody, Something)
swapping likes in the entire program by blah_blah without aecting the
functioning of the program. However, humans inspecting such program
may have problems in guessing what its all about. For the sake of program
readability, modiability and maintenance, it pays to use predicate names
that correspond to the predicate meaning.
3. The naming of variables needs to be consistent only in rules, but not outside rules. The same variable may bear dierent names in dierent rules
without aecting the program functioning. Prolog (and CLP ) recognizes
variables not by their names, but by their position in predicates. However, for the sake of program readability, modiability, and maintenance,
it pays to use the same variable names in dierent rules.
The described features have an advantage and a disadvantage:
the advantage is the ease of incorporating third party programs into our
own programs: it suces to paste them and provide calls from within our
program. No name adjustment is necessary;
the disadvantage is the possible muddle caused by using inappropriate
names for variables and predicates. In extreme cases it may make the
understanding of a Prolog (or CLP ) program a really tough job.
2.1.3
Modes of variables
The word mode denotes the role played by a variable as argument of a built-in
predicate: the variable may be:
an input, i.e. it is determined outside the predicate considered: it must be
declared as bounded to some other predicate, or list, or atom or number;
8 Private
20
Variable
grounded
(++X)
An input
bounded to a
grounded predicate
or list, to
an atom or number
Variable
free
(-X)
An output
bounded to
nothing
Variable
any mode
(?X)
An input or
output, bounded
or free
21
2.1.4
Operations
The basic arithmetical operations available in Prolog are shown in Table 2.4.
They may be used in either inx form or prex form, see Full documentation...
in Figure 5.
Symbol
+
/
//
mod
^
Operation
addition
subtraction
multiplication
real division
integer division
modulus
power
22
Operation
terms inside brackets
exponents and roots
multiplication and division
addition and subtraction
Binding strength
strong
|
weak
Precedence value
low
|
high
Operator class
prex
inx
postx
23
Associativities
fx, fy (unary) or fxx, fxy (binary)
xfx, xfy, yfx
xf, yf
2.1.5
Constraint propagation
24
2.1.6
25
to all decision variables, the state space is given by all groundings of domain
values to all decision variables, a feasible state is a state for which all constraints
are satised, a contracted state means any grounding of domain values to some
decision variables12 .
The goal of any Prolog (and CLP ) program is to satisfy a query that is the
head of some rule. The Prolog (CLP ) compiler contains an inference system
that searches the state space for a feasible state that will satisfy the query. This
is done by generating sequences of contracted states leading to the feasible state,
provided a feasible state exists. If so, Yes is followed by some detailed messages.
If no feasible state exists, No will be printed. All Prolog (and CLP ) programs
discussed farther will always have the query top; this makes for convenient
testing.
Search denotes the following sequence of steps:
1. Selecting a decision variable from the body of the rule dening the query;
2. Grounding the selected decision variable, i.e. assigning to it a value from
its domain. Thereby a contracted state is generated and the selected decision variable is termed grounded ;
3. Spreading the value of the grounded decision variable to all its instances
in the body of the rule;
4. Testing the satisfaction of all predicates in the body of the rule using
unication:
if this is not possible because some predicates are not grounded, steps
1, 2 and 3 are repeated for the next nearest variable or for the rule
dening this predicate, until eventually all predicates are grounded
and satised;
if all predicates in the body of the query are grounded and satised,
the query is satised and the variable values used for grounding are
displayed as the program solution;
if some predicate in the body of the query fails, the latest selected
variable is degrounded, a return is performed leftwards to the nearest
tested predicate with variables not yet grounded to some values from
12 The concept of state is - to the best knowledge of the Author - not particularly en
vogue in the CLP community. The Author, because of his control-engineering and dynamic
system background, is missing it from ever since, and uses this opportunity to show its broad
usefulness while discussing CLP.
26
their domains, and one of the variables is regrounded. While returning, all variables that have been successfully grounded between the
said nearest tested predicate and the failed predicate, are degrounded
as well. The return, the degrounding, and the regrounding is named
backtracking, and the predicate with variables of yet untested values
to which the return was performed, is named choice point.
It should be emphasized that any variable grounded to some value may
be grounded to another value only as the result of backtracking.
This is illustrated by the following simple Prolog program 2_1_search.pl:
/*1*/
a(X,Y) :-
/*2*/
/*3*/
b(X),
c(X,Y).
/*4*/
b(1).
/*5*/
/*6*/
b(&).
c(&,"A").
The programs query is a(X,Y). This means that the program aims at nding such values for decision variables X and Y that satisfy a(X,Y). The program
contains one rule (lines /*1*/, /*2*/, and /*3*/) and three facts (lines /*4*/,
/*5*/, and /*6*/). The indentation for lines /*2*/ and /*3*/ is used to make
the rule better readable. The domains for variables X and Y are dened implicitly by the facts: the domain of X is (1,&), the domain of Y is "A".
The rule states that in order to satisfy a(X,Y) such value for X has to be
found that satises b(X), and such value for Y has to be found that together
with the value for X satises c(X,Y). The conditions for the rule are queried in a
top-down fashion, so the rst value found for X is X=1. Because the domain of X
contains another value &, a choice point is created for b(X). Next, the value X=1
is spread to line /*3*/ resulting in c(1,Y), which does not unify with c(&,"A")
from line /*6*/. So c(1,Y) is unsatised, X is degrounded from its value 1 and
a return to the choice point for b(X) follows. Now X is regrounded with &, the
regrounding is spread to line /*3*/ resulting in c(&,Y) that successfully unies
with c(&,"A") from line /*6*/ giving the solution X = &, Y = "A".
The process described may be interpreted as running according to the search
tree from Figure 2.2 that reects the program structure.
For obvious reasons the search from Figure 2.2 is known as top-down search
or depth-rst search. The way returns are generated (as the result of violating
27
28
trees with no trees present in its entirety is of great practical signicance because
it allows Prolog and CLP languages to deal with problems corresponding to
search trees of exorbitant sizes.
An important regularity from the example deserves to be emphasized:
grounding of free variables occurs in top-down search any time a predicate
with free variables is encountered;
degrounding of grounded variables occurs when the last grounding results
in some constraint to be unsatised and a return to the nearest choice
point is done, where this (or some other free variable) may be regrounded.
There is no other way for grounded variables to change their values.
It should be emphasized, that Prologs search and unications constitute a
complete inference method. It means that if a solution to a CSP modelled in
Prolog exists, it will be determined13 .
2.1.7
Failing usefully
friend("Mark").
friend("Jack").
friend("Andrew").
who_are_your_friends_1:friend(Who),
write("Friend: "),write(Who),
nl.
29
/*9*/ who_are_your_friends_2:/*10*/
friend(Who),
/*11*/
write("Friend: "),write(Who),nl,
/*12*/
fail.
%
%
%
%
/*13*/ who_are_your_friends_3:/*14*/
friend(Who),
/*15*/
write("Friend: "),write(Who), nl,
/*16*/
fail.
/*17*/ who_are_your_friends_3:/*18*/
write("Those are all my friends."),nl.
Friend:
Mark.
Yes.
After clicking twice more in the Main Window from Figure 2 (to enforce other
solutions), the message is:
Friend:
Jack
Yes.
Friend:
Yes.
Andrew
Mark
Friend:
Friend:
Jack
Andrew
No.
Mark
Jack
Friend: Andrew
Those are all my friends.
Yes.
30
shows the impossibility of writing declarative programs that work without some
procedural crutches. It is worth remembering that fail/0 is functioning like
any predicate which is always false, e.g. 2 is 3.
2.1.8
Recursive denitions
membership(Member,[Member|_]).
31
and stating the recursive rule that a list member is the member of the list tail,
no matter what the head is:
/*2*/
/*3*/
membership(Member,[_|O]) :membership(Member,O).
top:-
/*7*/
membership(Member,[Member|_]).
/*8*/
membership(Member,[_|O]) :-
/*9*/
membership(E,[1,2,3,4]),
writeln(E),
fail.
top:writeln("Those are all elements of the list.").
membership(Member,O).
The programs query is top. The logical constant top will be used in the
sequel for all Prolog/CLP programs in the book. Prolog compiler attempts
to satisfy the query, i.e. make top true. In order to do it, it has to satisfy
the predicate in line /*2*/. This invokes the denition from line /*7*/, E is
grounded to /*1*/, and because of the other part of the denition (lines /*8*/
and /*9*/, a choice point is created for the predicate membership(). The
predicate fail/0 is a built-in that cannot be satised, so a backtrack to the
choice point is made generating the next element of the list and another choice
point, and so on, until (thanks to removing head after head by the action of line
/*7*/, /*8*/ and /*9*/ predicates) the list becomes empty.
32
2.1.9
The recursion with heads removal starts with a [H|T] list, the heads of
which are successively removed and processed, until the list is empty. The
recursion occurs between the list [H|T] (in the head of the rule) and the
tail of the list T (in the recurred predicate in the rule body).
2. Adding - as heads - successive elements, generated by some constraints,
to a list which is initially entirely or partially empty. This is continued
until some special list is generated, as shown in the following example:
recursive_predicate(Tail_of_list,....):% The head is determined and added:
determine_the_head(Head),
........................
recursive_predicate([Head|Tail_of_list],....).
33
The recursion with adding heads start with an entirely or partially empty
Tail_of_list, to which are successively added Heads generated by some
constraints, until the list is some Special_list. The recursion occurs
between the Tail_of_list (in the head of the rule) and the head-addedlist [Head|Tail_of_list] in the recurred predicate in the rule body.
The important thing to remember is that only heads may be removed from a
list, and only heads me be added to a list.
This is illustrated by program 2_4_reversal.pl that reverses the order of
list elements using two private predicates:
1. my_reverse(Initial_list, Reversed_list)
2. my_reverse(Initial_list, Reversed_list,
Accumulator_of_reversed_list)
The name my_reverse was chosen to distinguish it from the built-in reverse/2,
which does exactly the same job.
The program is removing successively heads from the the Initial_list
and adding the removed heads successively to the initially empty list named
Accumulator_of_reversed_list. When the Initial_list is empty (i.e. when
all its elements have been transferred in reverse order to the Accumulator_of_
reversed_list), the Reversed_list is unied with the accumulator.
The program looks like this:
/*1*/
/*2*/
/*3*/
top:-
/*4*/
/*5*/
/*6*/
my_reverse(Initial_list,Reversed_list):my_reverse(Initial_list,Reversed_list,[]).
my_reverse([],A,A).
/*7*/
/*8*/
my_reverse([H|T],Reversed_list,A):my_reverse(T,Reversed_list,[H|A]).
my_reverse([a,b,c,d],Reversed_list),
write(Reversed_list).
34
The program uses two predicates with the same name but dierent arity
(my_reverse/2 and my_reverse/3), which is perfectly O.K. Dierent arities
make the names distinguishable to the compiler.
The basic rule is in lines /*7*/ and /*8*/: there the head H of the initial
list [H|T] is removed from this list and added as head to the list A, resulting in
[H|A].
The use of accumulator deserves some comments. In Prolog/CLP accumulators are articial variables 14 that allow to write so-called tail-recursive rules,
i.e. rules with the head calling itself at the end of the body; the rule in lines
/*7*/ and /*8*/ is just a trivial example of a tail-recursive rule. Tail-recursion
is the most parsimonious type of recursion as far as stack space is concerned: it
does not need any stack at all.
2.1.10
Generating lists
in this sense that they do not correspond to any of the original problem variables.
35
Model
Clunker SUV
Clunker Great Tour
Clunkerlac
Clunker Family
Clunkerdes
Clunker Electric
Clunker Green
Mileage
29000
60000
47000
38000
46000
75000
52000
Year
2008
2009
2007
2009
2008
2005
2006
Price
1500
1900
1200
2200
3100
1100
1300
Color
Black
Green
Champagne
Blue
Silver
Red
Silver
top:mean_price_for_all_cars,
mean_mileage_for_selected_cars.
/*4*/ mean_price_for_all_cars:/*5*/
findall(Price,offer(_,_,_,Price,_),List),
/*6*/
writeln("List of prices for all cars":List),
/*7*/
length(List, N),
/*8*/
Sum is sum(List),
/*9*/
MeanPrice is Sum/N,
/*10*/
writeln("Mean car price":MeanPrice),nl.
/*11*/ mean_mileage_for_selected_cars:/*12*/
findall(Mileage,selected_cars(Mileage),List),
/*12*/
writeln("List of mileage for cars costing less than 1900 and "),
writeln("not of red color and not older than 2006":List),
/*14*/
length(List, N),
/*15*/
Sum is sum(List),
/*16*/
MeanMileage is Sum/N,
/*17*/
writeln("Mean mileage for cars costing less than 1900 and "),
writeln("not of red color and not older than 2006":MeanMileage).
/*18*/ selected_cars(Mileage):/*19*/
offer(_,Mileage,Year,Price,Color),
/*20*/
Year > 2006,
36
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
Notice the presence of anonymous variables in line /*5*/, due to the circumstance that we need only values of the Price variable.
Readers familiar with database languages may notice that Prolog is also an
elegant language for database queries, equivalent to a powerful subset of SQL.
2.1.11
Backtracking in Prolog is automatic. That means each time the search for
solution needs backtracking (i.e. each time some predicate fails), Prolog backtracks. This is both advantageous and disadvantageous: the advantage consists
of relieving programmers from coding backtracking into Prolog programs; the
disadvantage is that backtracking may sometimes be not quite desirable because
it increases the time to get a solution or generates partial solutions of no interest.
This can be avoided using the built-in !/0 referred to as cut. The properties
of cut are summarized in Figure 2.3, were black arrows denote possible backtracking. Program 2_6_playing_with_cut.pl illustrates all usages of cut/0:
/*1*/
/*2*/
top:a.
/*3*/
a :-
37
/*4*/
b, write("
/*5*/
/*6*/
write("
write("
write("
/*7*/
/*8*/
/*9*/
/*10*/
write("
/*11*/
/*12*/
write("
write("
/*13*/
/*14*/
write("
write("
/*15*/ b :/*16*/
c(X),
/*17*/
d(X),
/*18*/
!,
38
/*19*/
/*20*/
/*21*/
e(Y),
f(Y),
g(X).
/*22*/ b:/*23*/
write(" We are here 0!"),nl.
/*24*/ c(1).
/*25*/ c(2):/*26*/
write("We are here 1!"),nl,
/*27*/
write("
Backtrack is possible before the cut!"),nl,nl.
/*28*/ c(3).
/*29*/ d(2).
/*30*/ e(1).
/*31*/ e(2) :/*32*/
write("We are here 2!"),nl,
/*33*/
write("
Backtrack is possible after the cut!"),nl,nl.
/*34*/ f(2) :/*35*/
write("We are here 3!"),nl,
/*36*/
write("
However, no backtrack is possible from below the place "),nl,
/*37*/
write("
cut has been placed in the first clause for b up above "),nl,
/*38*/
write("
the place cut has been placed in this clause."),nl,nl.
/*39*/ g(3).
The message while lines /*25*/, /*26*/ and /*27*/ are present:
We are here 1!
Backtrack is possible before the cut!
We are here 2!
Backtrack is possible after the cut!
We are here 3!
However, no backtrack is possible from below the place
cut has been placed in the first clause for b up above
the place cut has been placed in this clause.
We are here 4!
Because the Prolog compiler called the cut in
the first clause for b, it is not possible to
39
The message while lines /*25*/, /*26*/ and /*27*/ are removed:
We are here 0!
The Prolog compiler did not call the cut.
Thanks to that, because the first clause for b
could not be fulfilled, a is true
because the second clause for b was fulfilled.
2.1.12
The Reader has perhaps already noticed that there is rather little logic in Prolog,
considering the massive stock of knowledge covered by the name logic. Whats
more, this little logic used in Prolog is sometimes strangely twisted to account
for the fact that Prolog (and CLP ) programs are running on single processors, that process the program clauses and the body predicates sequentially in
time, from programs top to programs bottom, and from body left to body right.
Consider the rule structure. The sequence of predicates in the rules body
had been referred to as conjunction. As we know from logic, conjunction is commutative; that is changing the order of conjuncted arguments does not change
the logical value of the conjunction. However, this does not always hold for
rules. The program 2_5_clunkers.pl gives a good opportunity to demonstrate
this limitation of logic as used in Prolog. Suppose the line /*5*/ was put after
line /*8*/. The program compiles but when queried produces the message:
"instantiation fault in (0, _347, _355)".
The reason is obvious: predicates in the rules body are (because of the single
processor limitation) tested in the order they appear, from left to right. Therefore we cant use (in lines /*7*/ and /*8*/) data for the ungrounded variable
List: it has not yet been grounded by the moved predicate from line /*5*/.
40
2.2
2.2.1
Conguration problems
Conguring a 3-element system
To build some system, elements belonging to three classes are needed: a single
A-class element, a single B-class element, and a single C-class element. Each
class contains a number of dierent types of elements:
A-class elements may be of type a1, a2, and a3;
B-class elements may be of type b1, b2, b3, and b4;
C-class elements may be of type c1 and c2,
with dierent prices (in Monetary Units, MU):
a1 price is 1900; a2 price is 750; a3 price is 900;
b1 price is 300; b2 price is 500; b3 price is 450; b4 price is 600;
c1 price is 700; c2 price is 850,
and dierent compatibility restrictions:
c1 is not compatible with a2;
b2 is not compatible with c2;
c2 is not compatible with b3;
b4 is not compatible with a2;
b3 is not compatible with a1;
a3 is not compatible with b3;
There are two problems to be solved: (1) determine all congurations consisting
of three compatible elements A, B, and C with overall price not larger than 2100
MU15 , ( 2) determine all optimum congurations consisting of three compatible
15 This
is an FS-type problem.
41
elements A, B, and C with overall minimum price16 . Such problems are generic,
which means they are representatives of a group of concrete problems of similar
logical structure, like conguring a lunch menu, conguring a leisure outt,
conguring computer hardware.
2.2.2
Exhaustive search
The most naive approach to solving the conguring problem is exhaustive search:
it amounts to generating consecutively all states (A, B , C) of the state space and
only then testing whether they satisfy all constraints of the problem. This is
done notwithstanding the fact that with luck the feasible solution may be found
for the rst state generated and with no luck it may be found after generating
some substantial number of states. However, with bad luck it may be found
for the last state generated, and to play safe, the entire state space has to be
tested. For the conguration example 3 4 2 = 24 tests have to be performed.
Assuming further that A is grounded rst, B next, and C last, the search may be
depicted for - the sake of compatibility with backtracking search - by the search
tree from Figure 2.4.
Exhaustive search starts (according to the assumption made) with variable A
bounded to a1, variable B bounded to b1, and variable C bounded to c1. The resulting conguration (a1,b1,c1) is too expensive, so the next state is generated
and so on. The system may be congured in 24 ways (thats the dimension of
the state space) from which 13 conguration contain non-compatible elements,
and 7 congurations costs more than the threshold price of 2100. Following
four congurations are feasible:
Conguration(a2, b1, c2) priced at 1900;
Conguration(a3, b1, c1) priced at 1900;
Conguration(a3, b1, c2) priced at 2050;
Conguration(a3, b2, c1) priced at 2100.
The exhaustive search may be performed by program 2_7_conf_es.pl:
/*1*/ top:/*2*/
assert(upper_price_limit(2100)),
/*3*/
upper_price_limit(Upper_price_limit),
16 This
is an OS-type problem.
42
/*4*/
configuration(Upper_price_limit).
/*5*/ configuration(Upper_price_limit):/*6*/
member(A,[a1,a2,a3]),
/*7*/
member(B,[b1,b2,b3,b4]),
/*8*/
member(C,[c1,c2]),
/*9*/
not(incompatibility([A,B])),
/*10*/
not(incompatibility([A,C])),
/*11*/
not(incompatibility([B,C])),
/*12*/
price(A,Price_of_A),
/*13*/
price(B,Price_of_B),
/*14*/
price(C,Price_of_C),
/*15*/
Total_price is Price_of_A+Price_of_B+Price_of_C,
/*16*/
Upper_price_limit>=Total_price,
/*17*/
write("Configuration("),write(A),write(","),
/*18*/
write(B),write(","),write(C),write(")"),
/*19*/
write(" priced at "),write(Total_price),
/*20*/
43
nl,fail.
/*21*/ configuration(Upper_price_limit):/*22*/
write("Those are all configurations "),
/*23*/
write("priced at no more than "),
/*24*/
write(Upper_price_limit),write(".").
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
/*34*/ incompatibility([X,Y]):-incompatible(X,Y).
/*35*/ incompatibility([X,Y]):-incompatible(Y,X).
44
2.2.3
Backtracking search
The poor performance of exhaustive search is due to testing constraints only for
complete states. It is obvious that some constraints may be tested earlier, for
contracted states. This has been shown on Figure 2.5.
Figure 2.5: Search tree for depth-rst search with standard backtracking
As can be seen from Figure 2.5, variable A is rst grounded to a1. Because
this is not the only possibility of grounding A (that may be grounded also to a2
and a3), so a choice point for A has to be created. Next, variable B is grounded
to b1 while another choice point is created for B that may be grounded to b2,
b3, and b4 as well. The contracted state (A,B) = (a1,b1) corresponds to a
partial conguration that costs more than the threshold price, so there is no
point in going deeper in the search tree: backtracking is initiated consisting of:
degrounding the last bounded variable B = b1;
45
top:assert(upper_price_limit(2100)),
upper_price_limit(Upper_price_limit),
configuration(Upper_price_limit).
/*5*/ configuration(Upper_price_limit):/*6*/
member(A,[a1,a2,a3]),
/*7*/
price(A,Price_of_A),
/*8*/
Price_of_A =< Upper_price_limit,
/*9*/
member(B,[b1,b2,b3,b4]),
/*10*/
not(incompatibility([A,B])),
/*11*/
price(B,Price_of_B),
/*12*/
Price_of_AB is Price_of_A+Price_of_B,
/*13*/
Price_of_AB =< Upper_price_limit,
/*14*/
member(C,[c1,c2]),
/*15*/
not(incompatibility([A,C])),
/*16*/
not(incompatibility([B,C])),
/*17*/
price(C,Price_of_C),
46
/*18*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
Total_price is Price_of_A+Price_of_B+Price_of_C,
Total_price =< Upper_price_limit,
write("Configuration("),write(A),write(","),
write(B),write(","),write(C),write(")"),
write(" priced at "),write(Total_price),
nl,fail.
/*21*/ configuration(Upper_price_limit):/*22*/
write("Those are all configurations "),
/*23*/
write("priced at no more than "),
/*24*/
write(Upper_price_limit),write(".").
/*25*/ price(a1,1900). price(a2,750). price(a3,900).
/*26*/ price(b1,300). price(b2,500). price(b3,450).
/*27*/ price(b4,600). price(c1,700). price(c2,850).
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
incompatible(c1,a2).
incompatible(b2,c2).
incompatible(c2,b3).
incompatible(b4,a2).
incompatible(b3,a1).
incompatible(a3,b3).
2.3
2.3.1
47
Quite often we are interested in nding only an17 optimum conguration for
which the conguration price (considered to be the objective function) is minimized. This can be done by a slight modication of the 2_7_conf_es.pl program that transforms it into a branch-and-bound search program. Branch-andbound performs also depth-rst search with backtracking, but does it dierently,
as shown in Figure 2.6.
48
/*17*/
/*18*/
/*19*/
Price is Price_AB+Price_C,
update_optimum_configuration([A,B,C],Price),
fail.
/*20*/ top:/*21*/
write("The least expensive configuration is: "),nl,
/*22*/
optimum_configuration([A,B,C],Price),
/*23*/
write("Configuration("),write(A),write(","),
/*24*/
write(B),write(", "),write(C),write(")"),
/*25*/
write(" priced at "),write(Price), nl,
/*26*/
fail.
/*27*/ top:/*28*/
write("Those are all optimum configurations.").
/*29*/ update_optimum_configuration([A,B,C],Price):/*30*/
optimum_configuration(_,Smallest_price_so_far),
/*31*/
Smallest_price_so_far > Price,
/*32*/
retract_all(optimum_configuration(_,_)),
/*33*/
assert(optimum_configuration([A,B,C],Price)),!.
/*34*/ update_optimum_configuration([A,B,C],Price):/*35*/
optimum_configuration(_,Smallest_price_so_far),
/*36*/
Smallest_price_so_far = Price,
/*37*/
assert(optimum_configuration([A,B,C],Price)),!.
/*38*/ update_optimum_configuration(_,Price):/*39*/
optimum_configuration(_,Smallest_price_so_far),
/*40*/
Smallest_price_so_far<Price,!.
/*41*/ price(a1,1900). price(a2,750). price(a3,900).
/*42*/ price(b1,300). price(b2,500). price(b3,450).
/*43*/ price(b4,600). price(c1,700). price(c2,850).
/*44*/
/*45*/
/*46*/
/*47*/
/*48*/
/*49*/
incompatible(c1,a2).
incompatible(b2,c2).
incompatible(c2,b3).
incompatible(b4,a2).
incompatible(b3,a1).
incompatible(a3,b3).
49
50
2.4
2.4.1
Assignment problems
Golfers
Problems with negative information (i.e. stating that something is not true)
may be quite cumbersome to solve, even if the negative information is scarce.
A good illustration of such problems is given by the following example18 :
A foursome of golfers (Fred, Joe, Bob, Tom) is standing at a tee, in a line
from left to right. Each golfer wears dierent colored pants:
one is wearing red pants;
the golfer to Freds immediate right is wearing blue pants;
Joe is second in line;
Bob is wearing plaid pants;
Tom isnt in position one or four, and he isnt wearing the hideous orange
pants.
In what order are the four golfers standing at the tee, and what color are
each golfers pants? This is a good opportunity to demonstrate ECLi P S e muscles!
The modeling starts with dening a number of private predicates. They may
be the following:
conditions(Golfers_position,Golfers_name, Color_of_golfers_pants)
all_positions_are_different(Position_1,Position_2,Position_3,Position_4)
all_colors_are_different(Color_1, Color_2, Color_3,Color_4)
18 This FS-type problem has been rst formulated and solved using the Jess Rule Engine
for the Java Platform, see [Friedman-Hill-03].
51
wearing_red_pants(Position_1, Pants_color_for_golfer_on_position_1,
Position_2, Pants_color_for_golfer_on_position_2,
Position_3, Pants_color_for_golfer_on_position_3,
Position_4, Pants_color_for_golfer_on_position_4)
blue_pants_right_on_Fred(Position_1, Pants_color_for_golfer_on_position_1,
Position_2, Pants_color_for_golfer_on_position_2,
Position_3, Pants_color_for_golfer_on_position_3,
Position_4, Pants_color_for_golfer_on_position_4)
colors(colors_name)
position(positions_number).
top:-
% Fred is standing somewhere (position P1) and has pants of some color (color C1):
/*2*/
conditions(P1,"Fred",C1),
% 3)Joe is second in line (position P2, color of pants C2):
/*3*/
conditions(P2, "Joe",C2),
/*4*/
P2 is 2,
% 4)Bob is wearing plaid pants (and stands at position P4):
/*5*/
conditions(P4, "Bob", C4),
/*6*/
C4 = plaid,
% 5)Tom isnt in position one or four, and he isnt
% wearing the hideous orange pants (stands at position P3 and has pants of color C3) :
/*7*/
conditions(P3,"Tom", C3),
/*8*/
C3 \== orange,
/*9*/
P3 =\= 2,
/*10*/
P3 =\= 4,
/*11*/
/*12*/
52
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
conditions(Number,_,Color) :position(Number),
color(Color).
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
wearing_red_pants(_,C1,_,_,_,_,_,_)
C1 = red,!.
wearing_red_pants(_,_,_,C2,_,_,_,_)
C2 = red,!.
wearing_red_pants(_,_,_,_,_,C3,_,_)
C3 = red,!.
wearing_red_pants(_,_,_,_,_,_,_,C4)
C4 = red,!.
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
/*39*/
/*40*/
blue_pants_right_on_Fred(P1,_,P2,C2,_,_,_,_) :P2 is P1 + 1,
C2 = blue,!.
blue_pants_right_on_Fred(P1,_,_,_,P3,C3,_,_) :P3 is P1 + 1,
C3 = blue,!.
blue_pants_right_on_Fred(P1,_,_,_,_,_,P4,C4) :P4 is P1 + 1,
C4 = blue,!.
/*41*/
/*42*/
/*43*/
all_positions_are_different(X1, X2, X3, X4) :X1 =\= X2, X1 =\= X3, X1 =\= X4,
X2 =\= X3, X2 =\= X4, X3 =\= X4.
/*44*/
/*45*/
/*46*/
all_colors_are_different(X1, X2, X3, X4) :X1 \== X2, X1 \== X3, X1 \== X4,
X2 \== X3, X2 \== X4, X3 \== X4.
/*47*/
/*48*/
/*49*/
/*50*/
color(orange).
color(blue).
color(red).
color(plaid).
/*51*/
/*52*/
position(1).
position(2).
/*53*/
/*54*/
position(3).
position(4).
::::-
53
2.4.2
Three cubes
is an FS-type problem.
54
%(3) The number of the black cube is greater than the number on the white cube:
/*6*/
cube(black,_,Number_of_black_cube),
/*7*/
cube(white,_,Number_of_white_cube),
/*8*/
Number_of_black_cube > Number_of_white_cube,
%(4) The size of cube with number 3 is smaller than the size of the grey cube:
/*9*/
cube(_,Size_3, 3),
/*10*/
cube(grey,Size_of_grey_cube,Number_of_grey_cube),
/*11*/
smaller_size(Size_3,Size_of_grey_cube),
% The numbers are different:
/*12*/
Number_of_grey_cube =\= Number_of_white_cube,
/*13*/
Number_of_grey_cube =\= Number_of_black_cube,
/*14*/
Number_of_white_cube =\= Number_of_black_cube,
/*15*/
2 =\= Number_of_large_cube,
/*16*/
2 =\= Number_of_medium_cube,
/*17*/
Number_of_large_cube=\=Number_of_medium_cube,
% The colors are different:
/*18*/
Color_of_large_cube\==Color_of_medium_cube,
/*19*/
Color_of_large_cube\==Color_of_small_cube,
/*20*/
Color_of_small_cube\==Color_of_medium_cube,
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/ cube(Color,Size,Number):/*28*/
member(Color,[black,grey, white]),
/*29*/
member(Size,[small, large, medium]),
/*30*/
member(Number,[1,2,3]).
/*31*/ smaller_size(small, large).
/*32*/ smaller_size(small, medium).
/*33*/ smaller_size(medium, large).
/*34*/ brighter(white,grey).
/*35*/ brighter(white,black).
/*36*/ brighter(grey,black).
55
2.4.3
A substantial diculty while modeling problems in Prolog (or CLP ) is the design of relevant private predicates. This is best seen for the next example, where
the private predicates chosen are far from obvious. They are of course not the
only choice that may be used for modeling the problem.
The following criminal puzzle20 has to be solved21 :
Mike has been murdered. Alex, Ben and Colin are the only suspects. While
interrogated:
Alex said he is innocent, Ben was Mikes friend but Colin hated Mike.
Ben said that he was out of town on the day of the murder, besides he didnt
even know Mike.
Colin said he is innocent but he saw Alex and Ben with Mike just before the
murder.
Who killed Mark assuming that all except possibly the murderer are telling
the truth? The suspects statements are formalized using the private predicate:
statements_of_suspect(List_of_statements ).
The question is answered by program 2_12_who_killed.pl that uses the wellknown Sherlock Holmes principle: connect facts in a consistent system and the
solution follows.
/*1*/ top:/*2*/
find_murderer.
/*3*/ statements_of_Alex([innocent("Alex"),friends("Ben","Mike"),
hates("Colin","Mike")]).
20 This
21 This
56
/*4*/ statements_of_Ben([alibi("Ben"),did_not_know("Ben","Mike")]).
/*5*/ statements_of_Colin([innocent("Colin"),together("Colin","Mike"),
together("Ben","Mike"),together("Alex","Mike")]).
/*6*/ find_murderer:/*7*/
statements_of_Alex(Statements_of_Alex),
/*8*/
statements_of_Ben(Statements_of_Ben),
/*9*/
statements_of_Colin(Statements_of_Colin),
/*10*/
consistent_statements(Statements_of_Ben,Statements_of_Colin),
/*11*/
inconsistent_statements(Statements_of_Alex,Statements_of_Ben),
/*12*/
inconsistent_statements(Statements_of_Alex,Statements_of_Colin),
/*13*/
write("Alex is the murderer."),nl,!.
/*14*/ find_murderer:/*15*/
statements_of_Alex(Statements_of_Alex),
/*16*/
statements_of_Ben(Statements_of_Ben),
/*17*/
statements_of_Colin(Statements_of_Colin),
/*18*/
consistent_statements(Statements_of_Alex,Statements_of_Colin),
/*19*/
inconsistent_statements(Statements_of_Alex,Statements_of_Ben),
/*20*/
inconsistent_statements(Statements_of_Ben,Statements_of_Colin),
/*21*/
write("Ben is the murderer."),nl,!.
/*22*/ find_murderer:/*23*/
statements_of_Alex(Statements_of_Alex),
/*24*/
statements_of_Ben(Statements_of_Ben),
/*25*/
statements_of_Colin(Statements_of_Colin),
/*26*/
consistent_statements(Statements_of_Alex,Statements_of_Ben),
/*27*/
inconsistent_statements(Statements_of_Alex,Statements_of_Colin),
/*28*/
inconsistent_statements(Statements_of_Ben,Statements_of_Colin),
/*29*/
write("Colin is the murderer."),nl,!.
/*30*/ consistent_statements(Statement_1,Statement_2):/*31*/
not(inconsistent_statements(Statement_1,Statement_2)).
/*32*/ inconsistent_statements(Statement_1,Statement_2):/*33*/
cartesian_product(Statement_1,Statement_2,Cartesian_product),
/*34*/
test_pairwise_inconsistency(Cartesian_product).
/*35*/ cartesian_product([], _, []).
/*36*/ cartesian_product([H|T], L, M) :/*37*/
generate_pairs(H,L,M1),
/*38*/
cartesian_product(T, L, M2),
/*39*/
append(M1, M2, M).
/*40*/ generate_pairs(_, [], []).
/*41*/ generate_pairs(A, [B|L], [[A,B]|N] ) :/*42*/ generate_pairs(A, L, N).
/*43*/ test_pairwise_inconsistency([[H1,H2]|T]):-
57
/*44*/
not(inconsistent_pairs(H1,H2)),
/*45*/
test_pairwise_inconsistency(T).
/*46*/ test_pairwise_inconsistency([[H1,H2]|_]):/*47*/
inconsistent_pairs(H1,H2),
/*48*/
!.
/*49*/ inconsistent_pairs(P1,P2):/*50*/
inconsistency([P1,P2]).
/*51*/ inconsistent_pairs(P1,P2):/*52*/
inconsistency([P2,P1]).
/*53*/ inconsistency([hates("Ben","Mike"),friends("Ben","Mike")]).
/*54*/ inconsistency([friends("Ben","Mike"),did_not_know("Ben","Mike")]).
/*55*/ inconsistency([together("Ben","Mike"),did_not_know("Ben","Mike")]).
/*55*/ inconsistency([friends("Colin","Mike"),hates("Colin","Mike")]).
/*56*/ inconsistency([innocent("Alex"),guilty("Alex")]).
/*57*/ inconsistency([innocent("Colin"),guilty("Colin")]).
/*58*/ inconsistency([alibi("Ben"),together("Ben","Mike")]).
/*59*/ inconsistency([alibi("Ben"),guilty("Ben")]).
/*60*/ inconsistency([alibi("Colin"),together("Colin","Mike")]).
2.4.4
is an FS-type problem.
cases of the benchmark operate for chessboards accommodating hundreds of
23 Advanced
queens.
58
2. No two queens will ever appear in the same row provided the 8-tuple
X1,X2,...,X8 is equal to a permutation of the 8-tuple 1,2,3,4,5,6,7,8.
2.4.5
To program exhaustive search for queens, following private predicate are introduced:
eight_queens([X1,X2,...,X8]) with argument given by the list of queens
is the main predicate.
permutations(Permutation_List,Initial_List), which calculates consecutive permutations of the initial list [1,2,3,4,5,6,7,8].
save([New_queen_to_be_placed|List_of_queens_already_placed]),
which is fullled if the new queen to be placed is not attacking any queen
on the list of already placed queens.
no_attack(New_Queen_to_be_placed,List_of_queens_already_placed)
that initiates the checks of conicts between the New_Queen_to_be_placed
and the List_of_queens_already_placed.
no_attack(New_Queen_to_be_placed,List_of_queens_already_placed,
Shift_of_New_Queen_to_be_placed_on_the_diagonal)
that actually checks for the absence of conicts for feasible shifts of the new
queen to consecutive columns along the upward and downward diagonal,
starting with shift 1.
The exhaustive search generates consecutively all permutations of the 8-tuple
1,2,3,4,5,6,7,8, and next checks, whether it corresponds to a safe placement.
This is done by the 2_13_queens_es.pl program:
/*1*/
/*2*/
top:all_solutions.
/*3*/
/*4*/
/*5*/
eight_queens([X1,X2,X3,X4,X5,X6,X7,X8]):permutations([X1,X2,X3,X4,X5,X6,X7,X8],[1,2,3,4,5,6,7,8]),
safe([X1,X2,X3,X4,X5,X6,X7,X8]).
/*6*/
/*7*/
/*8*/
/*9*/
permutations([],[]).
permutations([X|Xs],Ls):remove(X,Ls,Rs),
permutations(Xs,Rs).
59
/*10*/ remove(X,[X|Xs],Xs).
/*11*/ remove(X,[Y|Ys],[Y|Rs]):/*12*/
remove(X,Ys,Rs).
/*13*/ safe([]).
/*14*/ safe([X|Xs]):/*15*/
no_attack(X,Xs),
/*16*/
safe(Xs).
/*17*/ no_attack(X,Xs):/*18*/
no_attack(X,Xs,1).
/*19*/ no_attack(_,[],_).
/*20*/ no_attack(X,[Y|Ys],Nb):/*21*/
X=\=Y-Nb,
/*22*/
X=\=Y+Nb,
/*23*/
Nb1 is Nb+1,
/*24*/
no_attack(X,Ys,Nb1).
/*25*/ all_solutions:/*26*/
eight_queens(X),
/*27*/
write(X),nl,
/*28*/
fail.
/*29*/ all_solutions:/*30*/
write("Thats all!").
There are 92 placements, from which only the rst and last two are presented:
[1, 5, 8, 6, 3, 7, 2, 4]
[1, 6, 8, 3, 7, 4, 2, 5]
........................
[8, 3, 1, 6, 2, 5, 7, 4]
[8, 4, 1, 3, 6, 2, 7, 5]
Thats all!
2.4.6
60
61
Then, instead canceling the last placement and returning to the nearest safe
placement, the placement of queens is continued, and only after all queens have
been placed, the safety of the placement is checked.
Exhaustive search could be improved upon by a following search strategy:
let the list [x1,x2,..xi] corresponds to a safe placement of the rst i queens.
Another queen is added to the list and a safety check is performed. If the
placement remains safe, yet another queen is added. If the safety check fails, a
return is initiated to such previous placement, for which some untested queen
choice is still possible. Such search strategy, recognized as depth-rst search
with standard backtracking, is performed by the program 2_13_queens_bs.pl.
The search may be made yet more eective by noticing that the used modeling
of placements dened by the list:
[X1,X2,...,Xi,...,X8]
where Xi is the number of the chessboard row, for which the queen is placed in
the ith column, has yet another important benets. It is, by its very nature,
fullling two constraints:
1. No two queens will ever be placed in the same column, because any Xi
occupies the unique ith position in the list.
2. No two queens will ever be placed in the same row, because the value of
any Xi is uniquely determined from a list of integers [1,2,3,4,5,6,7,8].
So search for safe placements has to be done only along the upward and downward diagonal of the chessboard.
To program depth-rst search with backtracking for queens, following private
predicate are introduced:
queens(List_of_queens_added_to_queens_placed,
List_of_queens_already_placed,
List_of_available_queens)
that is extracting queens from the List_of_available_queens using variables from the List_of_queens_added_to_queens_placed and testing
safety for the chosen queen to be added. Only if the new placement would
be safe, the chosen queen is actually added to the List_of_queens_already
_placed.
no_attack/2 has been dened in Section 2.4.5.
no_attack/3 has been dened in Section 2.4.5.
62
top:-
/*3*/
/*4*/
eight_queens(X):queens(X,[],[1,2,3,4,5,6,7,8]).
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
queens([],_,[]).
queens([X|Xs],Placed,List_of_available_queens):remove(X,List_of_available_queens,New_list_of_available_queens),
no_attack(X,Placed),
queens(Xs,[X|Placed],New_list_of_available_queens).
/*10*/
/*11*/
/*12*/
remove(X,[X|Xs],Xs).
remove(X,[Y|Ys],[Y|Rs]):remove(X,Ys,Rs).
/*13*/
/*14*/
/*15*/
no_attack(X,Placed):no_attack(X,Placed,1).
no_attack(_,[],_).
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
no_attack(X,[Y|Ys],Nb):X=\=Y-Nb,
X=\=Y + Nb,
Nb1 is Nb + 1,
no_attack(X,Ys,Nb1).
/*21*/
/*22*/
all_solutions:eight_queens(X),
/*23*/
write(X),nl,
/*24*/
/*25*/
/*26*/
all_solutions.
fail.
all_solutions:write("Thats all!").
The message generated by this program is the same as for the 2_13_queens_es.pl
program.
The recursive beauty of the denitions for no_attack/3 and queens/3 is
worth contemplating for a while. The role of variable X for determining the
queen to be added is worth noting: if the no_attack/2 predicate in line /*8*/
fails, backtracking is performed to line /*7*/ where a new value X is picked from
63
64
65
66
2.4.7
Quite often puzzles are saturated with negative knowledge i.e. knowledge about
what should not be done. Such puzzles present no special problem to Prolog as
shown by the following problem:
An examination room has 17 places arranged as shown in Table 2.8.
M5
M10
M1
M6
M11
M2
M7
M12
M15
M3
M8
M13
M16
M4
M9
M14
M17
top:L=[1,2,3,4],
member(M1,L),
member(M3,L),
member(M5,L),
member(M7,L),
member(M9,L),
member(M11,L),
member(M13,L),
member(M15,L),
member(M17,L),
/*19*/
M1 =\= M2,
/*20*/
M1 =\= M5,
/*21*/
M1 =\= M6,
/*22*/
M1 =\= M7,
/*23*/
M2 =\= M6,
/*24*/
M2 =\= M7,
24 This
/*3*/
/*5*/
/*7*/
/*9*/
/*11*/
/*13*/
/*15*/
/*17*/
is an FS-type problem.
member(M2,L),
member(M4,L),
member(M6,L),
member(M8,L),
member(M10,L),
member(M12,L),
member(M14,L),
member(M16,L),
67
/*25*/
M2 =\= M3,
/*26*/
M2 =\= M8,
/*27*/
/*29*/
M3 =\= M7,
M3 =\= M9,
/*28*/
/*30*/
M3 =\= M8,
M3 =\= M4,
/*31*/
M4 =\= M8,
/*32*/
M4 =\= M9,
/*33*/
/*35*/
M5 =\= M6,
M5 =\= M11,
/*34*/
/*36*/
M5 =\= M10,
M6 =\= M10,
/*37*/
M6 =\= M11,
/*38*/
M6 =\= M7,
/*39*/
/*41*/
M6 =\= M12,
M7 =\= M12,
/*40*/
/*42*/
M7 =\= M11,
M7 =\= M8,
/*43*/
/*45*/
M7 =\= M13,
M8 =\= M13,
/*44*/
/*46*/
M8 =\= M12,
M8 =\= M14,
/*47*/
M8 =\= M9,
/*48*/
M9 =\= M13,
/*49*/
/*51*/
M9 =\= M14,
M11 =\= M15,
/*50*/
/*52*/
/*53*/
/*54*/
/*55*/
/*57*/
/*56*/
/*58*/
/*59*/
/*61*/
/*60*/
/*62*/
/*63*/
/*64*/
write("
"),write(M1),write(", "), write(M2),
write(", "),write(M3),write(", "), write(M4),nl,
/*65*/
/*66*/
/*67*/
It took quite a long time (203 seconds on a na 2.0 GHz notebook running
under Windows XP). In Section 3.7.4 another more ecient way to solve the
problem as CLP problem will be presented.
68
2.4.8
Paradoxes in Prolog
top:-
/*3*/
/*4*/
shaves(barber,X):not(shaves(X,X)).
shaves(barber,barber).
25 It is interesting to know that this apparently simple theorem resisted a long series of attempts to prove it using mathematics. It nally succumbed to a computer-assisted proof (sort
of exhaustive search), which demonstrated the non-existence of plenary graphs that would
need ve colors to color them in the sense of the theorem, see [Lines-92]. The mathematicians
werent quite happy about it.
69
2.4.9
Nicklaus Wirth in his popular textbook [Wirth-75] presented the following story
(sometimes attributed also to Mark Twain) of a man complaining about the
wretchedness of his life26 :
I married a widow with a grown daughter. My father, who visited us frequently, fell in love with the daughter and took her as his wife. This made my
father my adopted son, and my adopted daughter became my stepmother.
After a year my wife gave birth to a son, who became the adopted brother
26 This
is an FS-type problem.
70
top:-
/*8*/
write("Everything is O.K.").
/*9*/
/*10*/
/*11*/
grandfather(Grandfather,Grandson):father(Grandfather,Grandfathers_son),
father(Grandfathers_son,Grandson).
/*12*/
/*13*/
/*14*/
grandmother(Grandmother,Grandson):mother(Grandmother,Grandmothers_daughter),
mother(Grandmothers_daughter,Grandson).
brother(Father,Brother_1,Brother_2):father(Father,Brother_1),
father(Father,Brother_2).
/*24*/
uncle(Father,Uncle,Nephew):-
/*25*/
/*26*/
brother(_,Father,Uncle),
father(Uncle,Nephew).
2.4.10
71
72
First Condition is called and if it succeeds any further solutions of Condition are cut and Then is called. Else is never called in this case regardless
of the outcome of Then.
If Condition fails, Else is called. In this case, Then is never called.
In Prolog programs for Else often stands True with obvious meaning. The
predicate may be used to simplify some Prolog programs as shown by the example:
Andrew, Barbara and Christopher have decided to attend some extracurricular lectures. Each one choose a dierent lecture, in dierent days, on dierent
hours, namely:
1) Andrew will attend the lecture by Professor Paul.
2) Tuesdays lecture does not start at 2:00 p.m.
3) The lecture on Knowledge engineering does not start at 5:30 p.m.
4) Thursdays lecture start at 3:45 p.m.
5) Christopher will attend the lecture on Econometric models.
6) Barbara would like to attend the Tuesday lecture.
7) The lecture on Articial Intelligence is delivered in Building D3.
8) Wednesdays lecture are delivered in Room 104.
9) Professor Smith is not delivering the lecture Econometric models.
10)Professor Jones is not delivering his lecture in Room K2.
A program that determines who will attend which lecture, where, when and
delivered by whom, is given by 2_25_lectures.pl:
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
top:students(Name_1,Name_2,Name_3),
lectures(Lecture_1,Lecture_2,Lecture_3),
professors(Professor_1,Professor_2,Professor_3),
rooms(Room_1,Room_2,Room_3),
days(Day_1,Day_2,Day_3),
hours(Hour_1,Hour_2,Hour_3),
/*8*/
/*9*/
/*10*/
constraints(Name_1,Lecture_1,Professor_1,Room_1,Day_1,Hour_1),
constraints(Name_2,Lecture_2,Professor_2,Room_2,Day_2,Hour_2),
constraints(Name_3,Lecture_3,Professor_3,Room_3,Day_3,Hour_3),
/*11*/
73
/*12*/
/*13*/
/*14*/ students(Name_1,Name_2,Name_3):/*15*/
name(Name_1),
/*16*/
name(Name_2),
/*17*/
name(Name_3),
/*18*/
all_different(Name_1,Name_2,Name_3).
/*19*/ lectures(Lecture_1,Lecture_2,Lecture_3):/*20*/
lecture(Lecture_1),
/*21*/
lecture(Lecture_2),
/*22*/
lecture(Lecture_3),
/*23*/
all_different(Lecture_1,Lecture_2,Lecture_3).
/*24*/ professors(Professor_1,Professor_2,Professor_3):/*25*/
professor(Professor_1),
/*26*/
professor(Professor_2),
/*27*/
professor(Professor_3),
/*28*/
all_different(Professor_1,Professor_2,Professor_3).
/*29*/ rooms(Room_1,Room_2,Room_3):/*30*/
room(Room_1),
/*31*/
room(Room_2),
/*32*/
room(Room_3),
/*33*/
all_different(Room_1,Room_2,Room_3).
/*34*/ days(Day_1,Day_2,Day_3):/*35*/
day(Day_1),
/*36*/
day(Day_2),
/*37*/
day(Day_3),
/*38*/
all_different(Day_1,Day_2,Day_3).
/*39*/ hours(Hour_1,Hour_2,Hour_3):/*40*/
hour(Hour_1),
/*41*/
hour(Hour_2),
/*42*/
hour(Hour_3),
/*43*/
all_different(Hour_1,Hour_2,Hour_3).
/*44*/ constraints(Name,Lecture,Professor,Room,Day,Hour):/*45*/
( (Name == "Andrew")-> Professor = "Paul"
/*46*/
; true
),
74
/*47*/
/*48*/
/*49*/
/*50*/
/*51*/
/*52*/
( ( Day == "Thursday")->
; true
),
/*53*/
/*54*/
( ( Name == "Christopher")->
; true
),
/*55*/
/*56*/
/*57*/
/*59*/
/*59*/
/*60*/
/*61*/
/*62*/
/*63*/
/*64*/
Day = "Tuesday"
Room = "D3"
/*65*/ all_different(Variable_1,Variable_2,Variable_3):/*66*/
Variable_1 \== Variable_2,
/*67*/
Variable_1 \== Variable_3,
/*68*/
Variable_2 \== Variable_3.
/*69*/ name("Andrew").
/*70*/ name("Barbara").
/*71*/ name("Christopher").
75
/*81*/ day("Tuesday").
/*82*/ day("Wednesday").
/*83*/ day("Thursdays").
/*84*/ hour("2:00 p.m.").
/*85*/ hour("5:30 p.m.").
/*86*/ hour("3:45 p.m.").
2.5
2.5.1
Sequencing problems
Farmer-wolf-goat-cabbage
This popular puzzle is a nice example of nding trajectories in the state space:
A farmer is standing on the west side of the river and with him are a wolf,
a goat and a cabbage. In the river there is a small boat. The farmer wants to
cross the river with all the three items that are with him. There are no bridges
and in the boat there is only room for the farmer and one item. However, the
crossings are danger-ridden:
If the farmer leaves the goat with the cabbages alone on the same side of
the river, the goat will eat the cabbages.
If the farmer leaves the wolf and the goat on the same side of the river,
the wolf will eat the goat.
Only the farmer can separate the wolf from the goat and the goat from the
cabbage. How can the farmer cross the river with all three items, without one
eating the other27 ?
27 This
76
The rst thing needed is to dene a state that accumulates all data needed
to properly determine the next move. The state of the system farmer-wolf-goatcabbage is given by declaring their whereabouts, see Figure 2.12. While crossing
the river no state may appear twice.
top:-
/*3*/
/*4*/
cross_the_river(Initial_state,Final_state):feasible_crossing(Initial_state,Final_state,
[Initial_state],Final_sequence),nl,
reverse(Final_sequence,Final_sequence_r),
write_feasible_crossing(Final_sequence_r),
fail.
cross_the_river(_,_):- nl, write("Those are all solutions!").
/*5*/
/*6*/
/*7*/
/*8*/
cross_the_river(state(w,w,w,w),state(e,e,e,e)).
/*9*/
feasible_crossing(Current_state,Final_state,
Final_sequence_accu,Final_sequence):/*10*/
crossing(Current_state,Next_state),
/*11*/
not(unsafe(Next_state)),
ecclesiastic, poet, mathematician and teacher from York, Northumbria. He wrote a textbook
Propositiones ad Acuendos Juvenes (in English: Problems to Sharpen the Young) containing
53 puzzles, some of them of the river crossing type.
/*12*/
/*13*/
/*14*/
not(member(Next_state,Final_sequence_accu)),
feasible_crossing(Next_state,Final_state,
[Next_state|Final_sequence_accu],Final_sequence).
feasible_crossing(Final_state,Final_state,
Final_sequence,Final_sequence):- !.
77
78
write(Y_translated),write("."),nl.
/*38*/ write_crossing(state(X,X,G,C), state(Y,Y,G,C)):/*39*/
translate(X,X_translated),
/*40*/
translate(Y,Y_translated),
/*41*/
write("Farmer moves with wolf from "),write(X_translated),
write(" to "),write(Y_translated),write("."),nl.
/*42*/ write_crossing(state(X,W,X,C), state(Y,W,Y,C)) :/*43*/
translate(X,X_translated),
/*44*/
translate(Y,Y_translated),
/*45*/
write("Farmer moves with goat from "),write(X_translated),
write(" to "),write(Y_translated),write("."),nl.
/*46*/ write_crossing(state(X,W,G,X), state(Y,W,G,Y)) :/*47*/
translate(X,X_translated),
/*48*/
translate(Y,Y_translated),
/*49*/
write("Farmer moves with cabbage from "),write(X_translated),
write(" to "),write(Y_translated),write("."),nl.
/*50*/ translate(w,"west bank").
/*51*/ translate(e,"east bank").
There are two solutions to this problem. The rst one is:
Farmer moves with goat from west bank to east bank.
Farmer moves from east bank to west bank.
Farmer moves with wolf from west bank to east bank.
Farmer moves with goat from east bank to west bank.
Farmer moves with cabbage from west bank to east bank.
Farmer moves from east bank to west bank.
Farmer moves with goat from west bank to east bank.
All safely crossed the river,
79
Figure 2.13: First solution river crossings for farmer, wolf, goat and cabbage
80
Figure 2.14: Second solution river crossings for farmer, wolf, goat and cabbage
done in line /*12*/: any new state Next_State may not belong to the list
Final_sequence_accu of states already accumulated. Unfortunately, this feature is only a fortuitous heuristics that just works for the example discussed,
but is not of general nature and does not work for all conceivable optimum state
trajectory problems.
2.5.2
81
are:
cross_the_river(Inital_state,Final_state,Boat_location)
feasible_crossing(Initial_state,Final_state,
Path_accumulator,Path,Boat_location)
The program is:
/*1*/
/*2*/
/*3*/
top:-
/*4*/
/*5*/
cross_the_river(Inital_state,Final_state,Boat_location):feasible_crossing(Inital_state,Final_state,[Inital_state],
Crossings,Boat_location), nl,
write_feasible_crossing(Crossings),
fail.
cross_the_river(_,_,_):write("Those are all solutions.").
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
feasible_crossing(Present_state,Final_state,Accu_of_crossings,
Crossings,Boat_location_before):crossing(Present_state,Next_state,Boat_location_before),
check_feasability(Next_state,Accu_of_crossings),
change_boat_location(Boat_location_before,Boat_location_after),
feasible_crossing( Next_state,Final_state,
[Next_state|Accu_of_crossings],Crossings,Boat_location_after).
82
/*41*/
Y1 is X1+1.
/*42*/
/*43*/
/*44*/
/*45*/
check_feasability(S1,Crossings):not(unsafe(S1)),
not(unfeasible(S1)),
not(member(S1,Crossings)).
/*46*/
/*47*/
change_boat_location(brb,blb).
change_boat_location(blb,brb).
unfeasible( state(M,_,_)):M<0.
/*56*/
/*57*/
unfeasible(state(_,K,_)):K<0.
/*58*/
/*59*/
unfeasible(state(M,_,_)):M>3.
/*60*/
/*61*/
unfeasible(state(_,K,_)):K>3.
/*62*/
/*63*/
/*64*/
/*65*/
/*66*/
write_feasible_crossing([H1,H2|T]):write_crossing(H1,H2),
write_feasible_crossing([H2|T]).
write_feasible_crossing([_|[]]) :writeln("All safely crossed the river.").
/*67*/
/*68*/
/*69*/
write_crossing(state(X,K,_),state(Y,K,_)):Y is X+1,
write("A missionary moved from left bank to right bank."),nl.
/*70*/
/*71*/
/*72*/
/*73*/
/*74*/
write_crossing(state(X,K,_),state(Y,K,_)):Y is X+2,
83
84
/*75*/
/*76*/
/*77*/
/*78*/
write_crossing(state(M,X,_),state(M,Y,_)):Y is X+2,
write("Two cannibals moved from left bank to right bank."),nl.
/*79*/
/*80*/
/*81*/
/*82*/
write_crossing(state(X,X1,_),state(Y,Y1,_)):Y is X+1,
Y1 is X1+1,
write("A missionary and a cannibal moved from left bank to "),
write("right bank."),nl.
/*83*/
/*84*/
/*85*/
write_crossing(state(X,K,_),state(Y,K,_)):Y is X-1,
write("A missionary moved from right bank to left bank."),nl.
/*86*/
/*87*/
/*88*/
write_crossing(state(M,X,_),state(M,Y,_)):Y is X-1,
write("A cannibal moved from right bank to left bank."),nl.
/*89*/
/*90*/
/*91*/
write_crossing(state(X,K,_),state(Y,K,_)):Y is X-2,
write("Two missionaries moved from right bank to left bank."),nl.
/*92*/
/*93*/
/*94*/
write_crossing(state(M,X,_),state(M,Y,_)):Y is X-2,
write("Two cannibals moved from right bank to left bank."),nl.
/*95*/
/*96*/
/*97*/
/*98*/
/*99*/
/*100*/
/*101*/
/*102*/
write_crossing(state(X,X1,_),state(Y,Y1,_)) :Y is X-1,
Y1 is X1-1,
write("A missionary and a cannibal moved from right bank to "),
write("left bank."),nl.
enumerate:retract(counter(Old)),
New is Old 1, +
assert(counter(New)).
state(0,
state(2,
state(3,
state(3,
to right
1, brb),
2, blb),
0, brb),
3, blb)]
bank.
85
Solution number 2:
Crossings = [state(0, 0, brb), state(0, 2, blb), state(0, 1, brb),
state(0, 3, blb), state(0, 2, brb), state(2, 2, blb),
state(1, 1, brb), state(3, 1, blb), state(3, 0, brb),
state(3, 2, blb), state(3, 1, brb), state(3, 3, blb)]
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two missionaries moved from left bank to right bank.
A missionary and a cannibal moved from right bank to left bank.
Two missionaries moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
All safely crossed the river.
Solution number 3:
Crossings = [state(0, 0, brb), state(1, 1, blb), state(0,
state(0, 3, blb), state(0, 2, brb), state(2,
state(1, 1, brb), state(3, 1, blb), state(3,
state(3, 2, blb), state(2, 2, brb), state(3,
A missionary and a cannibal moved from left bank to right
A missionary moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two missionaries moved from left bank to right bank.
A missionary and a cannibal moved from right bank to left
Two missionaries moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A missionary moved from right bank to left bank.
A missionary and a cannibal moved from left bank to right
All safely crossed the river.
1, brb),
2, blb),
0, brb),
3, blb)]
bank.
bank.
bank.
86
Solution number 4:
Crossings = [state(0, 0, brb), state(0, 2, blb), state(0,
state(0, 3, blb), state(0, 2, brb), state(2,
state(1, 1, brb), state(3, 1, blb), state(3,
state(3, 2, blb), state(2, 2, brb), state(3,
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two missionaries moved from left bank to right bank.
A missionary and a cannibal moved from right bank to left
Two missionaries moved from left bank to right bank.
A cannibal moved from right bank to left bank.
Two cannibals moved from left bank to right bank.
A missionary moved from right bank to left bank.
A missionary and a cannibal moved from left bank to right
All safely crossed the river.
1,
2,
0,
3,
brb),
blb),
brb),
blb)]
bank.
bank.
The general idea of missionaries and canibals is the same as for farmer-wolfgoose-cabbage: to any sequence of states already visited (and present in the
accumulator) a new feasible state is added till the new state is equal to the nal
87
2.5.3
Towers of Hanoi
Recursion was used for many predicates so far. Prolog people just love recursion
because of its succinctness and calculating power. A particularly convincing
argument for its virtues is given by the program solving the Towers of Hanoi
puzzle29 . This puzzle is due to the French mathematician Edouard Lucas (18421891). Lucas assumed the presence of three rods, onto any of them a number
of holed disks of dierent sizes can slide. The puzzle starts with the disks in a
stack of ascending order of diameters on one rod with the largest disk at the
bottom.
The goal is to move the entire stack disk-wise to another rod while fullling
the following constraints:
1. Only one disk may be moved at a time.
2. Each move consists of taking the top disk from some rod and sliding it
onto another rod.
3. No disk may be slid on top of a smaller disk.
Lets consider the general case of N disks. To move N disks from their initial
left rod to their nal right rod, it is necessary:
1. Move N 1 disks from the left rode to the middle rod using the nal rod
as intermediary. Assume that it done in TN 1 steps.
2. Move the last disk from the left rode to the right rode. Altogether TN 1 +1
steps are needed.
Now the situation is similar to the initial one, before step 1 was taken; the
dierence is that now N 1 disks have to be moved from the middle rod to the
right rod using as intermediary rod left. This can be done also in TN 1 steps.
All moves needed thus TN = 2TN 1 + 1 steps. The dierence equation:
TN = 2TN 1 + 1
29 This
is an FST-type problem.
88
top:-
/*6*/
/*7*/
hanoi(N) :move(N,"Left","Middle","Right").
89
90
2.6
2.6.1
A simple maze
The program 2_21_maze.pl nds the shortest path (measured by the number of
passed cells) from cell (0,0) to cell 6,6) for the maze from Figure 2.1831 . Only
horizontal and vertical transitions between cells are feasible. To nd the shortest
path, the branch-and-bound method used for nding optimum congurations
(see 2.3.1) has been applied.
top:-
/*4*/
/*6*/
/*8*/
/*10*/
/*12*/
/*14*/
/*16*/
/*18*/
/*20*/
/*22*/
/*24*/
/*26*/
/*28*/
/*30*/
31 This
assert(shortest_path([[]],80)),
maze.
from_to([0,0],[0,1]).
from_to([0,2],[0,3]).
from_to([0,4],[0,5]).
from_to([0,6],[1,6]).
from_to([0,4],[1,4]).
from_to([2,4],[3,4]).
from_to([0,1],[1,1]).
from_to([2,1],[2,2]).
from_to([2,3],[2,4]).
from_to([4,5],[4,6]).
from_to([4,3],[4,2]).
from_to([5,2],[6,2]).
from_to([6,1],[6,0]).
from_to([5,0],[4,0]).
is an OST-type problem.
/*5*/
/*7*/
/*9*/
/*11*/
/*13*/
/*15*/
/*17*/
/*19*/
/*21*/
/*23*/
/*25*/
/*27*/
/*29*/
/*31*/
from_to([0,1],[0,2]).
from_to([0,3],[0,4]).
from_to([0,5],[0,6]).
from_to([1,6],[2,6]).
from_to([1,4],[2,4]).
from_to([3,4],[4,4]).
from_to([1,1],[2,1]).
from_to([2,2],[2,3]).
from_to([4,4],[4,5]).
from_to([4,4],[4,3]).
from_to([4,2],[5,2]).
from_to([6,2],[6,1]).
from_to([6,0],[5,0]).
from_to([6,2],[6,3]).
/*32*/
/*34*/
from_to([6,3],[6,4]).
from_to([6,5],[6,6]).
91
/*33*/
from_to([6,4],[6,5]).
/*35*/ transition(A,B):/*36*/
from_to(A,B).
/*37*/ transition(A,B):/*38*/
from_to(B,A).
/*39*/ maze:/*40*/
path([[6,6]],Present_solution),
/*41*/
length(Present_solution,Present_length),
/*42*/
update_shortest(Present_solution, Present_length),
/*43*/
fail.
/*44*/ maze:/*45*/
shortest_path(Final_solution,Final_length),
/*46*/
write("Final_solution = "),write(Final_solution),nl,
/*47*/
write("Final_length ="),write(Final_length),nl,nl,
/*48*/
fail.
/*49*/ maze:/*50*/
write("Those are all solutions of minimum length."),nl.
/*51*/ path([Present_state|Path_covered],Final_solution):/*52*/
transition(Present_state,Next_state),
/*53*/
not(member(Next_state,Path_covered)),
/*54*/
path([Next_state,Present_state|Path_covered],Final_solution).
/*55*/ path([[0,0]|Path_covered],[[0,0]|Path_covered]).
/*56*/ update_shortest(Present_solution,Present_length):/*57*/
/*58*/
shortest_path(_,Final_length),
Present_length<Final_length,
/*59*/
/*60*/
retractall(shortest_path(_,_)),
assert(shortest_path(Present_solution,Present_length)),!.
shortest_path(_,Final_length),
Present_length=Final_length,
/*64*/
assert(shortest_path(Present_solution, Present_length)),!.
/*65*/ update_shortest(_,Present_length):/*66*/
shortest_path(_,Final_length),
/*67*/
Present_length>Final_length,!.
92
Final_Length =17
Final solution = [[0, 0], [0, 1], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4],
[3, 4], [4, 4], [4, 3], [4, 2], [5, 2], [6, 2], [6, 3], [6, 4],
[6, 5], [6, 6]]
Final_Length =17
Those are all solutions of minimum length.
The domain declaration is once again implicit and given by all facts from-to/2.
The state is obviously given by cell coordinates (horizontal,vertical ).
2.6.2
Mine eld
More complicated maze problems are given by mine elds, for which a path that
minimizes the overall danger is to be found32 . For the simple mine eld from
Figure 2.19 with dangers declared in cells, the least dangerous path from cell
(0,0) to cell (3,3) is to be found, assuming danger being additive.
The state of the mine eld is - as for the maze - given by cell coordinates
(horizontal, vertical ). The cell contain values of Danger associated with transiting the cell. The dangers do not belong to the state because they do not
inuence the moves to be made. Only vertical or horizontal moves are allowed.
The Overall_danger is the sum of Dangers transited cells. The corresponding program 2_22_mine_field.pl is as follows:
32 This
is an OST-type problem.
/*1*/
/*2*/
/*3*/
top:assert(safest_path([[]],50)),
mine_field.
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
from_to([1,0],[1,1]).
from_to([1,1],[1,2]).
from_to([1,2],[1,3]).
/*10*/
/*11*/
/*13*/
from_to([2,0],[2,1]).
from_to([2,1],[2,2]).
from_to([2,2],[2,3]).
/*14*/
/*15*/
/*16*/
from_to([3,0],[3,1]).
from_to([3,1],[3,2]).
from_to([3,2],[3,3]).
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
from_to([0,1],[1,1]).
from_to([1,1],[2,1]).
from_to([2,1],[3,1]).
/*23*/
/*24*/
/*25*/
from_to([0,2],[1,2]).
from_to([1,2],[2,2]).
from_to([2,2],[3,2]).
/*26*/
/*27*/
/*28*/
from_to([0,3],[1,3]).
from_to([1,3],[2,3]).
from_to([2,3],[3,3]).
/*29*/
/*30*/
/*31*/
/*32*/
transition(A,B):from_to(A,B).
transition(A,B):from_to(B,A).
/*33*/
/*34*/
/*35*/
/*36*/
danger([0,0],1).
danger([0,1],3).
danger([0,2],3).
danger([0,3],3).
/*37*/
/*38*/
/*39*/
danger([1,0],1).
danger([1,1],3).
danger([1,2],3).
93
94
/*40*/
danger([1,3],3).
/*41*/
/*42*/
/*43*/
/*44*/
danger([2,0],1).
danger([2,1],4).
danger([2,2],1).
danger([2,3],1).
/*45*/
/*46*/
/*47*/
/*48*/
danger([3,0],1).
danger([3,1],3).
danger([3,2],3).
danger([3,3],1).
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
/*59*/
/*60*/
mine_field:path([[3,3]],Path),
overall_danger(Path,Overall_danger),
update_safest(Path,Overall_danger),
fail.
mine_field:safest_path(Path,Overall_danger),
write("Safest path = "),write(Path),nl,
write("Overall danger = "),write(Overall_danger),nl,nl,
fail.
mine_field:write("Those are all solutions of minimum overall danger."),nl.
/*61*/
/*62*/
/*63*/
/*64*/
/*65*/
path([Present_state|Path_covered],Path):transition(Present_state,Next_state),
not(member(Next_state,Path_covered)),
path([Next_state,Present_state|Path_covered],Path).
path([[0,0]|Path_covered],[[0,0]|Path_covered]).
/*66*/
/*67*/
/*68*/
/*69*/
/*70*/
/*71*/
/*72*/
overall_danger([H|T],N):overall_danger([H|T],N,0).
overall_danger([],N,N).
overall_danger([H|T],N,A):danger(H,NN),
A_New is A+NN,
overall_danger(T,N,A_New).
/*73*/
update_safest(Path, Overall_danger):-
/*74*/
safest_path(_,Present_Danger),
/*75*/
/*76*/
Present_Danger>Overall_danger,
retractall(safest_path(_,_)),
/*77*/
assert(safest_path(Path,
Overall_danger)),!.
/*78*/
update_safest(Path, Overall_danger):-
/*79*/
safest_path(_,Present_Danger),
/*80*/
/*81*/
Present_Danger=Overall_danger,
assert(safest_path(Path, Overall_danger)),!.
/*82*/
/*83*/
/*84*/
95
update_safest(_,Overall_danger):safest_path(_,Present_Danger),
Present_Danger<Overall_danger,!.
2.6.3
Sometimes the distances of the mazes paths are not known. The number of forks
in the nal path may then be minimized. How to do it is shown by a program
solving the famous Hampton Court Maze. This is how Jerome K. Jerome in
his book Three Man in a Boat (To Say Nothing of the Dog) described what
happened to somebody trying to nd a way out of the famous hedge maze at
Hampton Court near London:
Harris asked me if Id ever been in the maze at Hampton Court. He said he went in once
to show somebody else the way. He had studied it up in a map, and it was so simple that it
seemed foolish - hardly worth the twopence charged for admission.
96
Well just go in here, so that you can say youve been, but its very simple. Its absurd
to call it a maze. You keep on taking the rst turning to the right. Well just walk round for
ten minutes, and then go and get some lunch.
They met some people soon after they had got inside, who said they had been there for
three-quarters of an hour, and had had about enough of it. Harris told them they could follow
him, if they liked; he was just going in, and then should turn round and come out again. They
said it was very kind of him, and fell behind, and followed.
They picked up various other people who wanted to get it over, as they went along, until
they had absorbed all the persons in the maze. People who had given up all hopes of ever
getting either in or out, or of ever seeing their home and friends again, plucked up courage
at the sight of Harris and his party, and joined the procession, blessing him. Harris said he
should judge there must have been twenty people, following him, in all; and one woman with
a baby, who had been there all the morning, insisted on taking his arm, for fear of losing him.
Harris kept on turning to the right, but it seemed a long way, and his cousin said he
supposed it was a very big maze.
Oh, one of the largest in Europe, said Harris.
Yes, it must be, replied the cousin, because weve walked a good two miles already.
Harris began to think it rather strange himself, but he held on until, at last, they passed
the half of a penny bun on the ground that Harriss cousin swore he had noticed there seven
minutes ago. Harris said: Oh, impossible! but the woman with the baby said, Not at all,
as she herself had taken it from the child, and thrown it down there, just before she met
Harris. She also added that she wished she never had met Harris, and expressed an opinion
that he was an impostor. That made Harris mad, and he produced his map, and explained
his theory.
The map may be all right enough, said one of the party, if you know whereabouts in
it we are now.
Harris didnt know, and suggested that the best thing to do would be to go back to the
entrance, and begin again. For the beginning again part of it there was not much enthusiasm;
but with regard to the advisability of going back to the entrance there was complete unanimity,
and so they turned, and trailed after Harris again, in the opposite direction. About ten minutes
more passed, and then they found themselves in the center.
Harris thought at rst of pretending that that was what he had been aiming at; but the
crowd looked dangerous, and he decided to treat it as an accident.
Anyhow, they had got something to start from then. They did know where they were,
and the map was once more consulted, and the thing seemed simpler than ever, and o they
started for the third time.
And three minutes later they were back in the center again.
After that, they simply couldnt get anywhere else. Whatever way they turned brought
them back to the middle. It became so regular at length, that some of the people stopped
there, and waited for the others to take a walk round, and come back to them. Harris drew
out his map again, after a while, but the sight of it only infuriated the mob, and they told
him to go and curl his hair with it. Harris said that he couldnt help feeling that, to a certain
extent, he had become unpopular.
They all got crazy at last, and sang out for the keeper, and the man came and climbed
up the ladder outside, and shouted out directions to them. But all their heads were, by this
time, in such a confused whirl that they were incapable of grasping anything, and so the man
told them to stop where they were, and he would come to them. They huddled together, and
waited; and he climbed down, and came in.
97
He was a young keeper, as luck would have it, and new to the business; and when he got
in, he couldnt nd them, and he wandered about, trying to get to them, and then he got lost.
They caught sight of him, every now and then, rushing about the other side of the hedge,
and he would see them, and rush to get to them, and they would wait there for about ve
minutes, and then he would reappear again in exactly the same spot, and ask them where
they had been.
They had to wait till one of the old keepers came back from his dinner before they got
out.
top:assert(shortest_path([[]],80)),
maze.
98
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
from_to([12,5],[13,12]).
from_to([12,5],[3,17]).
from_to([3,17],[5,22]).
from_to([3,17],[13,22]).
from_to([13,22],[7,24]).
from_to([13,22],[5,22]).
from_to([5,22],[6,28]).
from_to([6,28],[7,26]).
from_to([6,28],[10,30]).
from_to([10,30],[13,26]).
from_to([10,30],[9,16]).
/*20*/
/*21*/
/*22*/
/*23*/
transition(A,B):from_to(A,B).
transition(A,B):from_to(B,A).
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
maze:path([[18,16]],Present_solution),
length(Present_solution,Present_length),
update_shortest(Present_solution,Present_length),
fail.
/*29*/
/*30*/
/*31*/
/*32*/
maze:shortest_path(Final_solution,Final_length),
write("The shortest path is"),write(Final_solution),nl,
fail.
/*33*/
/*34*/
maze:write("Thats all!"),nl.
/*35*/
/*36*/
/*37*/
/*38*/
/*39*/
path([Present_state|Path_covered],Final_solution):transition(Present_state,Next_state),
not(member(Next_state,Path_covered)),
path([Next_state,Present_state|Path_covered],Final_solution).
path([[9,16]|Path_covered],[[9,16]|Path_covered]).
/*40*/
/*41*/
/*42*/
/*43*/
/*44*/
update_shortest(Present_solution,Present_length):shortest_path(_,Final_length),
Present_length<Final_length,
retractall(shortest_path(_,_)),
assert(shortest_path(Present_solution,Present_length)),!.
/*45*/
/*46*/
/*47*/
/*48*/
update_shortest(Present_solution, Present_length):shortest_path(_,Final_length),
Present_length=Final_length,
assert(shortest_path(Present_solution, Present_length)),!.
/*49*/
update_shortest(_,Present_length):-
/*50*/
/*51*/
99
shortest_path(_,Final_length),
Present_length>Final_length,!.
2.6.4
There are many water jugs problems. The one chosen is concerned with three
jugs of capacity 8, 5 and 3 liters. Neither has any measuring markers on it. The
8-liter jug is lled with water. How can this water be used to ll the remaining
two jugs exactly with four liters each while using only the three jugs that have
no measuring markers, and minimizing the number of pourings33 ?
33 This
is an OST-type problem.
100
top:Initial_state = state(8,0,0),
pour(Initial_state,Sequence_of_states),
length(Sequence_of_states, N),
assert(sequence_of_states(N,Sequence_of_states)),
fail.
top:assert(shortest_sequence_of_states(20,[])),
optimize.
/*10*/
/*11*/
pour(Initial_state,Sequence_of_states):pour(Initial_state,[Initial_state],Sequence_of_states).
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
pour(State,Accumulator,Sequence_of_states):state_transition(State,Next_state),
not(member(Next_state,Accumulator)),
pour(Next_state,[Next_state|Accumulator],Sequence_of_states).
pour(Final_state,Accumulator,Accumulator):final_state(Final_state),!.
/*18*/ final_state(state(4,4,0)).
% Possible pourings:
% pouring(From_jug_A, To_jug_B,
% With_limit_for_B, New_filling_of_A, New_filling_of_B):
% pouring from jug 1 to 2, 2 may contain no more than 5 liters:
/*19*/
state_transition(state(X,Y,Z),state(K,L,Z)):/*20*/
pouring(X,Y,5,K,L).
% pouring from jug 2 to 1, 1 may contain no more than 8 liters:
/*21*/
state_transition(state(X,Y,Z),state(K,L,Z)):/*22*/
pouring(Y,X,8,L,K).
% pouring from jug 1 to 3, 3 may contain no more than 3 liters:
/*23*/
state_transition(state(X,Y,Z),state(K,Y,M)):/*24*/
pouring(X,Z,3,K,M).
% pouring from jug 3 to 1, 1 may contain only 8 liters:
/*25*/
state_transition(state(X,Y,Z),state(K,Y,M)):/*26*/
pouring(Z,X,8,M,K).
pouring(X,Y,LimitY,K,L):check(X,Y,LimitY),
!,
NX is X - 1,
NY is Y + 1,
pouring(NX,NY,LimitY,K,L).
pouring(X,Y,_,X,Y).
/*38*/
/*39*/
/*40*/
check(X,Y,Limit):X > 0,
Y < Limit,!.
/*41*/
/*42*/
/*43*/
/*44*/
/*45*/
/*46*/
/*47*/
optimize:optimum_sequence_of_states,
shortest_sequence_of_states(N,Sequence_of_states),
reverse(Sequence_of_states, Reversed_sequence),
write("Optimum_solution : "),nl,
write(Reversed_sequence),nl,
write("Number of pourings: "),write(N).
/*48*/
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
optimum_sequence_of_states:sequence_of_states(X,Trajectory_X),
shortest_sequence_of_states(Y,Trajectory_Y),
update(X,Y,Trajectory_X,Trajectory_Y),
fail.
optimum_sequence_of_states.
/*54*/
/*55*/
update(X,Y,Trajectory_X,Trajectory_Y):X < Y,
/*56*/
!,
/*57*/
/*58*/
retract(shortest_sequence_of_states(Y,Trajectory_Y)),
assert(shortest_sequence_of_states(X,Trajectory_X)).
/*59*/
update(_,_,_,_).
101
102
Number of pourings: 8
The process of lling the three jugs is shown in Figure 2.23. Measuring markers
on jugs in Figure 2.23 have to illustrate the llings, but are not used to control
the llings.
2.7
Exercises
Domains
The domain declarations in Prolog programs are usually done implicitly
and sometimes hidden in strange places. Determine the variable domains
for all Prolog examples from the present chapter.
Fibonacci numbers
Leonardo Fibonacci (c. 1170 c. 1250) was an eminent mathematician
and mathematics teacher in the Republic of Pisa (now being part of Italy).
He is famous because of the attempt to model the growth of rabbit popu-
2.7 Exercises
103
lations, rabbits being at his time a widely craved source of meet and fur.
He assumed that a newly-born pair of rabbits of both genders are able to
mate at the age of one month so that at the end of its second month a
female can produce another pair of rabbits; assuming further that rabbits
never die and a mating pair always produces one new pair every month
from the second month on, the number of pairs of the rabbit population
increase in a month by month basis as follows:
0,1,1,2,3,5,8,13,21,34,55,89,144,...,
Denoting the number of rabbit pairs on the beginning of the nth monthlong period by Fn , the process may be described by the double recursion:
Fn = Fn1 + Fn2
where: F0 = 0, ,F1 = 1.
Write a program for calculating Fibonacci numbers that is not tail-recursive,
and another one that is tail-recursive.
Girl friends
John has ve girl friends: 1)Ann is blonde, 27 years old, is a Doctor of
Medicine, is married, has two children, a boy and a girl, likes swimming,
2)Beverly is blonde, 20 years old, is a student, single, no children, likes
cooking, 3)Colette is brunette, 24 years old, housewife, married, no children, likes acting, 4)Diana is blonde, 21 years old, a secretary, divorced,
one child - a girl, likes being entertained, 5)Edna is blonde, 25 years old,
a nurse, divorced, no children, likes classical music. Use findal/3 to establish data of all those girl friends that are not divorced, not older than
24, and like a non-sporting activity.
Games
At the local games evening, four lads were competing in the Scrabble and
chess competitions. Liam beat Mark in chess, James came third and the
16 year old won. Liam came second in Scrabble, the 15 year old won,
James beat the 18 year old and the 19 year old came third. Kevin is 3
years younger than Mark. The person who came last in chess, came third
in Scrabble and only one lad got the same position in both games. Write
a program to determine the ages of the lads and the positions in the two
games.
104
Musical recital
At a musical recital ve students (John, Kate, Larry, Mary and Nick)
performed ve musical pieces, two by Bach, two by Mozart and one by
Vivaldi. There were three violinists and two pianists. Each student performed only one piece, and played only one instrument. Find the order
of the students, their respective instruments and the composer, with the
following conditions: 1. The composers were not played consecutively.
Vivaldi was played last and Mozart was played rst. 2. There was one piano piece that was played between two violin pieces, and two violin pieces
between the rst and last piano piece. 3. There were no piano pieces by
Mozart. 4. Kate played third. 5. Nick played the piano, and immediately
followed John, who played a piece by Mozart. 6. Mary did not play a
piece by Vivaldi.
Master classes 34
The great mezzo-soprano Flora Nebbiacorno has retired from the international opera stage, but she still teaches master classes regularly. At a
recent class, her ve students were one soprano, one mezzo-soprano, two
tenors, and one bass. (The rst two voice types are womens, and the last
two are mens). Their rst names are Chris, J.P., Lee, Pat, and Val any
of which could belong to a man or a woman and their last names are
Kingsley, Robinson, Robinson (the two are unrelated but have the same
last name), Ulrich, and Walker. Write a program to nd the order in
which these ve sang for the class, identifying each by full name and voice
type, provided that:
1. The rst and second students were, in some order, Pat and the bass.
2. The second and third students included at least one tenor. 3. Kingsley
and the fth student (who isnt named Robinson) were, in some order, a
mezzo-soprano and a tenor. 4. Neither the third student, whose name is
Robinson, nor Walker has the rst name of Chris. 5. Ulrich is not the
bass or the mezzo-soprano. 6. Neither Lee or Val (who wasnt third) is
a tenor. 7. J.P. wasnt third, and Chris wasnt fth. 8. The bass isnt
named Robinson.
Jam making contest
At the recent inter-departmental jam making contest, four lucky candidates took part to make the juiciest strawberry jam. The ages of the
contestants were 14, 17, 20, 22. As it happens the person who came last
34 This
2.7 Exercises
105
was the oldest, whereas Stuart was three years older than the person who
came second. James was neither the oldest nor the youngest and Kev nished ahead of the 17 year old, but didnt win. John was also unlucky this
time and didnt win either. Write a program to determinate who nished
where and how old they are.
Bridge meeting
Four ladies meet each week on Thusday to play bridge. On each meeting
they decide what everyone has to bring for the next meeting. 1. Mrs.
Andrew will bring chocolate cake. 2. Neither Mrs. Brown, nor Viven,
nor Ann Clark will bring cookies. 3. Rachel, who is not from Davidsons
family, will bring coee. 4. Mary will not bring the wine. Write a program
to determine the whole name of each lady and what is she supposed to
bring next week.
Two jugs
You are given two jugs, a 4-gallon one and a 3-gallon one. Neither has
any measuring markers on it. There is a tap that can be used to ll the
jugs with water. Write a program to determine how can you get exactly
2 gallons of water into the 4-gallon jug.
Ships
There are 5 ships in a port35 . 1. The Greek ship leaves at six and carries
coee. 2. The ship in the middle has a black chimney. 3. The English
ship leaves at nine. 4. The French ship with a blue chimney is to the left
of a ship that carries coee. 5. To the right of the ship carrying cocoa
is a ship going to Marseille. 6. The Brazilian ship is heading for Manila.
7. Next to the ship carrying rice is a ship with a green chimney. 8. A
ship going to Genoa leaves at ve. 9. The Spanish ship leaves at seven
and is to the right of the ship going to Marseille. 10. The ship with a red
chimney goes to Hamburg. 11. Next to the ship leaving at seven is a ship
with a white chimney. 12. The ship on the border carries corn. 13. The
ship with a black chimney leaves at eight. 14. The ship carrying corn is
anchored next to the ship carrying rice. 15. The ship to Hamburg leaves
at six.
Write a program to determine which ship goes to Port Said and which
ship carries tea.
35 This
106
River crossing 1
Four adventurers (Alex, Brook, Chris and Dusty) need to cross a river in
a small canoe36 . The canoe can only carry 100 kg. Alex weighs 90 kg,
Brook weighs 80 kg, Chris weighs 60 kg and Dusty weighs 40 kg, and they
have 20 kg of supplies. Write a program showing how do they get across.
River crossing 2
Three humans and three monkeys (one big, two small) need to cross a river.
But there is only one boat, and it can only hold two bodies (regardless of
their size), and only the humans or the big monkey are strong enough to
row the boat. Furthermore, the number of monkeys can never outnumber
the number of humans on the same side of the river, or the monkeys will
attack the humans. Write a program to demonstrate how can all six get
across the river without anyone getting hurt.
River crossing 3
There is a family on one side of the river: 1. Father 2. Mother 3. Son
4. Daughter 5. Maid 6. Dog They need to get to the other side of the
river. Only 1 small boat is available to bring them across. The boat is big
enough for only 2 people OR 1 person + dog. Heres the tricky part: *
Only Father, Mother and Maid knows how to row the boat. At all times,
* Father cannot be alone with the Son, without the Mother, or else he
will hit the Son. * Mother cannot be alone with the Daughter, without
the Father, or else she will slap the Daughter * Maid MUST be with the
Dog, or else the Dog will bite anyone in sight. Write a program for the
family of 6 to get across the river, without getting hit, slapped or bitten.
River crossing 4
Three couples AA, BB and CC (the gents Andrew, Basil and Charles and
the corresponding ladies Ann, Barbara and Celine) had to cross a river in
a small boat that held only two people that. No husband would leave his
wife in the company of another man unless he himself was present. Besides
there are additional personal constraints which should not be violated:
- Andrew should not row alone because he is afraid of the river;
- Ann cannot row because of her advanced pregnancy;
- Barbara cannot row because her arm is broken;
- all other people could row;
- Andrew and Charles should not row together because the hate each
36 This
2.7 Exercises
107
other;
- for the same reason Andrew and Charles should not remain by themselves on the same river side.
Write a program for the couples o get across the river without jealousy
arising, and no personal constraint being violated.
Liars
It is known only one character is telling the truth. Mr. April says that
Mr. May tells lies. Mr. May says that Mr. June tells lies. Mr. June
says that both Mr. April and Mr. May tell lies. Write a program which
determines who is telling the truth.
Pets
At a recent Pets Anonymous reunion, the attendees were discussing which
pets they had recently owned. James used to have a dog. The person who
used to own a mouse now owns a cat, but the person who used to have a
cat does not have a mouse. Kevin has now or used to have a dog, I cant
remember which. Becky has never owned a mouse. Only one person now
owns the pet they previously had. Rebecca said very little throughout
the meeting and nobody mentioned the hamster. Write a program to
determine who owns which pet and what they used to own.
Snail racing
After the recent Brain-Bashers snail racing contest, the four contestants
were congratulating each other. Only one snail wore the same number as
the position it nished in. Alfreds snail wasnt painted yellow nor blue,
and the snail who wore 3, that was painted red, beat the snail who came
in third. Arthurs snail beat Annes snail, whereas Alices snail beat the
snail who wore 1. The snail painted green, Alices, came second and the
snail painted blue wore number 4. Annes snail wore number 1. Write a
program to work out whos snail nished where, its number and the color
it was painted.
Professions
Messrs Butcher, Baker, Carpenter and Plumber have met for the rst
time after college graduation. No-one is currently, nor ever has been in
the same profession as their name and on-one has had the same profession
twice. Charlie has never been a carpenter and Mr Butcher in now a
plumber. Dave used to be a butcher, whereas Mr Brian Baker never has.
108
2.7 Exercises
109
each other there were kissing. The same was true when a man and a
woman greeted each other. It is known 6 handshakes and 12 kisses have
been done in total. Write a program to determine how many guests arrived
at the dinner, how many of them were in couples and how many of them
were alone? Obviously, when two guests arrived as a couple they didnt
greet each other.
Politically correct missionaries and cannibals
Modify program 2_19_mac.pl so as to meet the criterium of political correctness presented by the footnote to Section 2.5.2.
Art theft
After a local art theft, six suspects were being interviewed. Below is a
summary of their statements:
Alan said: It wasnt Brian. It wasnt Dave. It wasnt Eddie.
Brian said: It wasnt Alan. It wasnt Charlie. It wasnt Eddie.
Charlie said: It wasnt Brian. It wasnt Freddie. It wasnt Eddie.
Dave said: It wasnt Alan. It wasnt Freddie. It wasnt Charlie.
Eddie said: It wasnt Charlie. It wasnt Dave. It wasnt Freddie.
Freddie said: It wasnt Charlie. It wasnt Dave. It wasnt Alan
Police know that exactly four of them told one lie each and all of the other
statements are true. From this information write a program to determine
who committed the theft.
Competition
Five friends were competing for jobs in the Huge International Corporation. After all interviews and examinations the results were presented to
the competitors. A bystander watching the friends overheard that:
Art sadly confessed he has not been ranked on the rst position;
Ben admitted he has been ranked as third after Carl
Art added that Carl has not been ranked second;
Ben added that Ed was neither the rst nor the last in the ranking;
Dusty admitted he was ranked just after Art.
110
Does the bystander has enough information to rank all ve friends? Write
a suitable program.
One more maze
For the maze from Figure 2.24 nd the shortest path (as measured by the
number of path forks) for the dragon to reach and ght the dinosaur.
2.7 Exercises
111
Fay lives on a higher oor than Debi, but on a lower oor than Herd.
Bob lives just above Nutter and just below this fellow who wrote 40
reports.
Airhead lives neither on the rst oor, nor on the six oor.
Al wrote half the number of reports as the resident from the six oor,
who wrote half the number of reports as Zero;
Debi does not live on the rst oor;
Bob wrote 20 reports more than Zero;
Zeros name is not Debi;
Nutter wrote 10 reports less than Airhead.
More uses of conditional predicates
Have a look at those examples from Chapter 2 which have been solved
with no use of the basic conditional predicate from Section 2.4.10. Can
any of them be solved using the conditional predicate? Design for some
of them a program.
Chapter 3
Elementary predicates
The range of built-ins made available to users is for CLP languages much greater
and decisively more powerful than for Prolog. They may be dichotomized into:
Elementary predicates which are predicates of fundamental functionality
over input variables contained at most in one lists. The are made available
by ic and branch_and_bound libraries.
Global predicates which are predicates of advanced functionality over a
number of input lists. The are made available by libraries like ic_global,
ic_cumulative, ic_edge_finder, ic_edge_finder3.
Obviously, the nature and usage of elementary predicates is simpler than of
global predicates. Elementary predicates form the basic building blocks of CLP
programs and their properties as well as the way they are handled deserve close
attention. Therefore we start with using them, while leaving the discussion and
application of global predicates to latter Sections 4 and 6.
113
114
3.2
3.2.1
Basic dierences
115
to right. This order is sometimes not the most ecient one, so CLP languages (including ECLi P S e ) makes available a number of search heuristics dierent from that realized by labeling/1, see 3.3.
7. While programming in ECLi P S e P rolog, no libraries need to be attached
to the program. On the other hand, while programming in ECLi P S e CLP ,
the program must start with a declaration of needed libraries. The most
often needed libraries are the following:
The ic (interval constraint) library that is a hybrid integer/real
interval arithmetic1 constraint solver. Its aim is to make it convenient for programmers to write hybrid solutions to problems, mixing
together integer and real constraints and variables. It is the basic
library, needed for the majority of problems discussed in chapters
3,..6.
The lib(branch_and_bound) library that implements a highly parameterized branch and bound algorithm, see chapters 5 and 6.
The eplex library with LP, MIP and quadratic programming solvers,
providing also the possibility of interfacing with third-party optimization software.
The ic_global library that implements a number of global constraints over lists of integer input variables.
The cumulative library that implements the cumulative scheduling
constraint, see Chapter 6.
The libraries ic_edge_finder and ic_edge_finder3 that implement stronger versions of the cumulative and disjunctive constraints
and cumulative scheduling constraints.
The ic_sets library that makes available a solver for constraints over
the domain of nite sets of integers.
The ic_symbolic library that makes available a solver for constraints
over ordered symbolic domains.
A detailed presentation of all libraries may be found in the ECLi P S e
Constraint Library Manual, available in the ECLiPSe Documentation, see
Figure 5.
1 Interval arithmetic - as contrasted with normal arithmetic - deals with arithmetic operations on real-valued intervals. The result of arithmetic interval operations is not given by
some set of state variable values, but by some set of state variable intervals. It will be used
intensively while discussing constraint solving for continuous variables.
116
3.2.2
Similarity
The main similarity between Prolog and CLP is that both infer using search
and propagation
The concepts mentioned will be illustrated by a number of examples, the
rst one is the queens placement problem.
3.2.3
So far two solutions for the queens placement problem were presented:
1. Exhaustive search, for which all possible permutations for
[X1,X2,...,Xn] = [1,2,...,n]
were consecutively generated and their safety was tested.
2. Depth rst search with standard backtracking, for which a safe partial
placement [Xj,Xk,...] was extended by adding another queen and testing the extended placement for safety; if it is safe we proceed with adding
yet another queen, if this test fails backtrack is done to the nearest placement for which there is still an untested choice of some queen to be added.
Standard backtracking is pruning some branches of the exhaustive search
tree, thereby contributing to the eciency of the search.
However, there are two drawbacks of depth rst search with standard backtracking:
1)backtracking is performed only as the result of violating some constraints;
2) trashing i.e. repeated failure due to the appearance of similar partial solu
tions, as shown in Figure 3.1.
117
3.2.4
118
119
Figure 3.3: Search tree for Forward Checking for four queens
3.2.5
Forward Checking has yet some drawbacks: it is not aware of consequences more
remote then the next search step and thus attempts to place queens on places
that result in empty domains not in the next step, but in the next plus one step.
Such situation is shown in Figure 3.4.
Looking Ahead is practically always used together with Forward Checking.
It initiates backtracking as soon as the violation of some constraint in the next
120
plus one search step is to be predicted2 . This is best illustrated for placing 4
queens, as shown in Figures 3.5 i 3.6.
Notice that:
Forward Checking alone is not testing non-empty domains of queens not
placed yet;
Looking Ahead + Forward Checking is testing whether non-empty domains
of queens not placed yet contain non-safe placements; if so, backtracking
is performed.
To end this Section, some words of consolation are due:
the ECLi P S e user is not expected to deal explicitly with the described
backtracking enhancements;
they are automatically provided by the mere declaration of stating some
goal.
The above discussion just aims to give the ECLi P S e user some idea about why
is it more ecient than Prolog.
3.3
Search heuristics
The queen placement problems shows that two decisions inuence the search
eectiveness. They are answers to following questions:
1. What variable should rst be chosen for grounding, what next, what afterwards, etc?
2 Obviously, this prediction must be cheaper in numerical terms than simply testing the
state for the next plus one search step.
121
122
Figure 3.6: Search tree for Looking Ahead+Forward Checkingfor four queens
2. What value (from the domain of the rst variable chosen) should be used
for grounding, what value (from the domain of the next variable chosen)
should be used for grounding, etc? .
For the queen placement examples the variables were chosen starting with
the head of the variable list, the head of the tail was chosen next, etc. It should
be noticed that this was not the best (in terms of search eciency) choice.
Starting near the middle of the list (e.g. choosing rst the second variable for
grounding), it can be seen from Figures 3.5 and 3.6 that the solution would be
obtained with a smaller number of backtracks.
For the queen placement examples the chosen variable was rst grounded
to the rst value from its domain, then to the second value, etc. It should be
noticed that this was also not the best choice. While starting near the middle
of the domain (e.g. grounding rst the variable on value 2), it can be seen from
Figures 3.5 and 3.6 that the solution would be obtained with a smaller number
of backtracks.
123
The ways to choose the variable order and value order are covered by an
umbrella term search heuristics:
1. The order of variable to be grounded depends upon the variable choice
heuristic.
2. The order of values to which the selected variable is grounded depends
upon the value choice heuristic.
In Chapter 5 search heuristics for a more advanced search predicate than
labeling/1 will be discussed.
However, it should be emphasized already at this point that there are no
means of knowing beforehand which search heuristics to choose for some particular problem. The only feasible approach (if eciency is of importance for
repeatedly using the same program with dierent data) is by exhaustively searching all heuristics made available by ECLi P S e .
3.4
Consistency techniques
124
Path consistency algorithms are seldom ever used, because path consistency may
be expressed in a simpler way. E.g. the case of path consistency for X = Y + Z
with corresponding domains DX , DY i DZ may be presented by a set of unary
constraints:
X >= min(DY ) + min(DZ )
X <= max(DY ) + max(DZ )
Y >= min(DX ) max(DZ )
Y <= max(DX ) min(DZ )
Z >= min(DX ) max(DY )
Z <= max(DX ) max(DY )
The eectiveness of existing consistency techniques has an important bearing on the methodology of CSP and COP: they must be modelled using integer
variables. This is sometimes easier said than done, and occasionally may look
strange indeed. However, this is something anybody learning CLP has to master.
Constraint propagation in CLP is an autonomous activity: it can sometimes
be used for inference purposes with no search.
3.5
In ECLi P S e programs symbols of arithmetic operations and relations for discrete variables have to be prexed by #. For better understanding of consistency
techniques let us consider a simple
example given by program 3_1_domain_0.ecl3:
/*1*/
:- lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
top :[X,Y,Z]::1..10,
get_domain(X,PX),
get_domain(Y,PY),
get_domain(Z,PZ),
write("X = "), write(PX),nl,
write("Y = "), write(PY),nl,
3 This
is an FS-type problem.
125
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
write("Propagation of constraint
Y#<Z,
get_domain(X,CX),
get_domain(Y,CY),
get_domain(Z,CZ),
write("X = "), write(CX),nl,
write("Y = "), write(CY),nl,
write("Z = "), write(CZ),nl,nl,
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
write("Propagation of constraint
X#=Y+Z,
get_domain(X,DX),
get_domain(Y,DY),
get_domain(Z,DZ),
write("X = "), write(DX),nl,
write("Y = "), write(DY),nl,
write("Z = "), write(DZ),nl,nl,
X = Y + Z results in:"),nl,
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
write("Propagation of constraint
X#=Z+3,
get_domain(X,TX),
get_domain(Y,TY),
get_domain(Z,TZ),
write("X = "), write(TX),nl,
write("Y = "), write(TY),nl,
write("Z = "), write(TZ),nl,nl,
X = Z + 3 results in:"),nl,
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
/*39*/
/*40*/
/*41*/
write("Propagation of constraint
X#>2+Z,
get_domain(X,TTX),
get_domain(Y,TTY),
get_domain(Z,TTZ),
write("X = "), write(TTX),nl,
write("Y = "), write(TTY),nl,
write("Z = "), write(TTZ),nl,nl,
/*42*/
/*43*/
write("Propagation of constraint
Y#=2*Z,
/*44*/
get_domain(X,SX),
/*45*/
/*46*/
get_domain(Y,SY),
get_domain(Z,SZ),
/*47*/
/*48*/
/*49*/
126
127
128
Y = [1, 2, 3, 4, 5, 6]
Z = [2, 3, 4, 5, 6, 7]
129
/*42*/ introduces a constraint inconsistent with this from line /*10*/; this
results in the domains of Y nd Z becoming empty. The program ends with
failure: the set of inequalities is inconsistent for the declared initial domains.
3.6
3.6.1
A simple example
:- lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
top :[X,Y,Z]::1..10,
get_domain(X,PX),
get_domain(Y,PY),
get_domain(Z,PZ),
write("X = "), write(PX),nl,
write("Y = "), write(PY),nl,
write("Z = "), write(PZ),nl,nl,
4 This
is an FS-type problem.
130
/*10/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33/
/*33*/
/*34*/
get_domain(X,SX),
/*35*/
/*36*/
get_domain(Y,SY),
get_domain(Z,SZ),
/*37*/
/*38*/
/*39*/
131
Below there are some more examples for which constraint propagation alone
is sucient for nding solutions.
3.6.2
The number of dierent combinatorial problems that can be modeled and solved
using integer domains is all-encompassing. Some applications seem to be quite
astonishing to the beginner. Let us consider the following puzzle5 :
Who went yesterday evening with whom when:
1. Andy enjoyed a concert.
2. Ben accompanied Olive.
3. Carl has not seen Eva.
4. Paula went to a cinema.
5. Eva was in a theater.
6. One boy and one girl went to an exhibition.
Dusty and Sabina belong also to the set of friends. Determine who went with
whom and where if every boy spend the evening with some girl.
The solution is given by program 3_3_who_with_whom.ecl6:
5 Taken
6 This
from [Bizam-75].
is an FS-type problem.
132
/*1*/
:-
lib(ic).
/*2*/
top:/*3*/
[Andy,Ben,Carl,Dusty]::[1..4],
/*4*/
[Olive, Eva,Paula,Sabina]::[1..4],
% concert=1, cinema=2, theater=3, exhibition=4
% It means: if eg. Ben=Olive=4, then
% Ben and Olive went to an exhibition
% Andy enjoyed a concert:
/*5*/
Andy#=1,
% Ben accompanied Olive:
/*6*/
Ben#=Olive,
% Carl has not seen Eva:
/*7*/
Carl#\=Eva,
% Paula went to a cinema:
/*8*/
Paula#=2,
% Eva was in a theater
/*9*/
Eva#=3,
% All persons are different:
/*10*/
Andy#\=Ben,
/*11*/
Andy#\=Carl,
/*12*/
Andy#\=Dusty,
/*13*/
Ben#\=Carl,
/*14*/
Ben#\=Dusty,
/*15*/
Carl#\=Dusty,
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
Olive#\=Eva,
Olive#\=Paula,
Olive#\=Sabina,
Eva#\=Paula,
Eva#\=Sabina,
Paula#\=Sabina,
/*22*/
/*23*/
The program contains no labeling(_) built-in, used for initiating search. Its
use would accelerate the inference. The solution generated is poorly under-
133
standable:
1 4 2 3
4 3 2 1
It means that:
Andy (first position on the boys list)
and Sabina (fourth position on the girls list)
enjoyed a concert (1).
Ben (second position on the boys list)
and Olive (first position on the girls list)
went to an exhibition (4).
Carl (third position on the boys list)
and Paula (third position on the girls list)
went to a cinema (2).
Dusty (fourth position on the boys list)
and Eva (second position on the girls list)
went to a theater (3).
3.6.3
Problems where propagation alone is sucient for obtaining a solution are sometimes astonishingly complex. This is the case for the following example taken
from [Bizam-75]:
Five students of ve nationalities spend their vacation on the Masurian
Lakes. Its a Pole, a Hungarian, a Finn, a Swede and a German. Determine
who speaks what language if:
1. Each student is uent in one o more foreign languages, but only in those
that are native for some of the remaining students.
2. There is no single language spoken by all of them.
3. Each student may speak with any other student using some language.
4. The common languages include native languages of all students.
134
:- lib(ic).
/*2*/
/*3*/
/*4*/
top :Students=["Pole","Hungarian","Finn","Swede","German"],
Languages=["Polish","Hungarian","Finnish","Swedish","German"],
/*5*/
Pole=[PP,PH,PF,PS,PG],
/*6*/
Hungarian=[HP,HH,HF,HS,HG],
/*7*/
Finn=[FP,FH,FF,FS,FG],
/*8*/
Swede=[SP,SH,SF,SS,SG],
/*9*/
German=[GP,GH,GF,GS,GG],
/*10*/
L=[Pole,Hungarian,Finn,Swede,German],
/*11*/
Pole::0..1,
/*12*/
Hungarian::0..1,
/*13*/
Finn::0..1,
/*14*/
Swede::0..1,
/*15*/
German::0..1,
% The meaning: if PF = 1, the Pole speaks Finnish;
% if PF = 0, the Pole does not speak Finnish.
/*16*/
/*17*/
7 This
%
%
PP#=1,
HH#=1,
constraint_0
Each student speaks its native language::
is an FS-type problem.
/*18*/
/*19*/
/*20*/
FF#=1,
SS#=1,
GG#=1,
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
% constraint_1
% Each student speaks one or more foreign language,
% but only those that are native
% languages of the remaining students:
PH+PF+PS+PG#>0,
HP+HF+HS+HG#>0,
FP+FH+FS+FG#>0,
SP+SH+SF+SG#>0,
GP+GH+GF+GS#>0,
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
% constraint_2
% There is no language spoken by all students:
HP+FP+SP+GP#<4,
PH+FH+SH+GH#<4,
PF+HF+SF+GF#<4,
PS+HS+FS+GS#<4,
PG+HG+FG+SG#<4,
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
/*39*/
/*40*/
% constraint_3
% Each student may speak with any other
% student using some language:
constraint_3(Pole,Hungarian),
constraint_3(Pole,Finn),
constraint_3(Pole,Swede),
constraint_3(Pole,German),
constraint_3(Hungarian,Finn),
constraint_3(Hungarian,Swede),
constraint_3(Hungarian,German),
constraint_3(Finn,Swede),
constraint_3(Finn,German),
constraint_3(Swede,German),
/*41*/
/*42*/
/*43*/
% constraint_5
% On average each student speaks two foreign languages:
PH+PF+PS+PG+HP+HF+HS+HG+FP+FH+FS+FG+
SP+SH+SF+SG+GP+GH+GF+GS#=10,
% constraint_6
% The Pole and the Hungarian speak three foreign languages:
PH+PF+PS+PG#=3,
HP+HF+HS+HG#=3,
%
%
%
constraint_7
While the Swede has been swimming, the remaining
four students could speak a common language:
135
136
/*44*/
constraint_7(HP,FP,GP,PH,FH,GH,PF,HF,GF,PG,HG,FG),
/*45*/
% constraint_8
% A common language could also be spoken while
% the Swede returned, but the Finn went rowing:
constraint_8(HP,SP,GP,PH,SH,GH,PS,HS,GS,PG,HG,SG),
/*46*/
% constraint_9
% In order to speak Swedish,two ,
% student had to leave the group:
PS+HS+FS+GS#=2,
/*47*/
/*48*/
/*49*/
/*50*/
/*51*/
% constraint_4
% The common languages include
% native languages of all students:
getval(p,1),
getval(h,1),
getval(f,1),
getval(s,1),
getval(g,1),
/*52*/
/*53*/
% constraint_10
% Polish and Finnish is spoken (as foreign language)
HP+FP+SP+GP#=1,
PF+HF+SF+GF#=1,
/*54*/
% constraint_11
% The Pole and Finn may communicate using,
% two languages, none of them being German:
constraint_11(PH,FH,FP,PF,PS,FS,PG,FG),
/*55*/
% constraint_12
% The Hungarian and the Swede have only one common language:
constraint_12(Hungarian,Swede),
/*56*/
solution(Students,L,Languages),!.
/*57*/
/*58*/
/*59*/
/*60*/
/*61*/
/*62*/
constraint_3([A1,A2,A3,A4,A5],[B1,B2,B3,B4,B5]):2#=A1+B1, setval(p,1);
%
attention: disjunction
2#=A2+B2, setval(h,1);
2#=A3+B3, setval(f,1);
2#=A4+B4, setval(s,1);
2#=A5+B5, setval(g,1).
/*63*/
/*64*/
/*65*/
/*66*/
constraint_7(HP,FP,GP,PH,FH,GH,PF,HF,GF,PG,HG,FG):HP#=1,FP#=1,GP#=1;
%
attention: disjunction
PH#=1,FH#=1,GH#=1;
PF#=1,HF#=1,GF#=1;
/*67*/
PG#=1,HG#=1,FG#=1.
/*68*/
/*69*/
/*70*/
/*71*/
/*72*/
constraint_8(HP,SP,GP,PH,SH,GH,PS,HS,GS,PG,HG,SG):HP#=1,SP#=1,GP#=1;
PH#=1,SH#=1,GH#=1;
PS#=1,HS#=1,GS#=1;
PG#=1,HG#=1,SG#=1.
/*73*/
/*74*/
/*75*/
constraint_11(PH,FH,FP,PF,PS,FS,PG,FG):constraint_11b(PG,FG),
constraint_11a(PH,FH,FP,PF,PS,FS).
/*76*/
/*77*/
/*78*/
/*79*/
/*80*/
/*81*/
/*82*/
constraint_11a(PH,FH,FP,PF,PS,FS):PH#=1,FH#=1,FP#=1;
PF#=1,FP#=1;
PS#=1,FS#=1,FP#=1;
PH#=1,PF#=1,FH#=1;
PH#=1,PS#=1,FH#=1,FS#=1;
PF#=1,PS#=1,FS#=1.
/*83*/
/*84*/
constraint_11b(PG,FG):PG#=0;FG#=0.
/*85*/
/*86*/
/*87*/
/*88*/
constraint_12([G1|_],[G2|_]):G1#=1,
G2#=1,
!.
/*89*/
/*90*/
/*91*/
constraint_12([G1|O1],[G2|O2]):constraint_12a(G1,G2),
constraint_12(O1,O2).
/*92*/
/*93*/
/*94*/
constraint_12a(G1,G2):G1#=0;
%
attention: disjunction
G2#=0.
/*95*/
/*96*/
/*97*/
/*98*/
/*99*/
/*100*/
/*101*/
/*102*/
/*103*/
solution1([1|O1],[G2|O2]):write("
"),writeln(G2),
solution1(O1,O2).
solution1([],[]).
/*104*/
solution1([0|O1],[_|O2]):-
137
138
/*105*/
solution1(O1,O2).
As seen, despite this problem complexity, it may be solved using only constraint
propagation.
3.6.4
ECLi P S e has a library of symbolic constraints (ic_symbolic), useful for symbolic variables (dened by names). Using this library operations on set variables
have to be prexed by &. The following example demonstrates its uses.
After the fall of communism in Absurdoland, a chain of Black and White
debating clubs mushroomed across the country. They were rather exclusive: its
139
membership was open only to former Secret Collaborators (of the resolved Communist Security Service) or former Righteous Oppositionists (hunted in the past
by the Communist Security Service). Such a membership prole proved to be
quite successful. It provided a fertile ground for contradictory discussions, loved
by the general public, Main Stream TV media and journalists. It boosted also
the consumption of all those beverages, which have a well-earned reputation of
facilitating the understanding of complicated situations. The attractiveness of
the discussions was further enhanced by the common knowledge that Righteous
Oppositionists always tell the truth, whereas Secret Collaborators lie and tell
the truth in alteration. The Main Stream tabloid News from the Sewer delegated to one of the clubs a Celebrated Journalist to write an in-depth report
promoting the idea of reconciliation of those foes of the past. Unfortunately,
the Celebrated Journalist had a problem: the club at the time of his arrival
was populated by just three members, of whom Member_1 and Member_2 argued
ferociously, evidently because they belonged to dierent groups of members.
The journalist, not wishing to disturb the adversaries, simply asked Member_3,
who did not take part in the argument, whether he was a former Righteous
Oppositionist, or a former Secret Collaborator. Unfortunately, Member_3 had
already been drinking too much of the mentioned beverages; therefore he simply mumbled something quite unintelligible under his breath. The Celebrated
Journalist asked therefore the remaining two members about what Member_3
had said. Member_1, who perhaps thanks to some practice could understand
the reply by Member_3, maintained that Member_3 said he was a former Righteous Oppositionist. Member_2 however rst said that Member_3 is a former
Secret Collaborator, and next added that Member_3 had been lying. Does the
Celebrated Journalist has sucient information to infer who is who8 ?
To gain some insight into the problem lets present its state space by a truth
table as shown in Figure 3.13. There are three Boolean input variables (M1,
M21 and M22), denoting correspondingly the logical values of what Member_1
said and what Member_2 said the rst and second time, with 0 meaning the
corresponding member was lying and 1 meaning the corresponding member
said the truth. Those three Boolean input variables can be combined in eight
ways, as shown by the map.
The numbers inside the squares of the truth table correspond to logical
values of the conjunction of all the problem constraints, 0 meaning the constraints failed, 1 meaning the constraints are satised:
8 This
is an FS-type problem.
140
Figure 3.13: Truth table for the state space of the RO-SC story
the rst column is clearly false: no club member ever tells two lies in
succession;
the second column corresponds to a self-contradictory situation: if Member_3
lied, then the rst statement by Member_2 cannot possibly by false;
the same applies to the fourth column: if Member_3 did not lie, then of
course the rst statement of Member_2 cannot possibly be true;
consider the bottom square of the third column: if the statement by
Member_1 is true, then both statements by Member_2 cannot possibly be
true;
what remains is the top square of third column, which corresponds to a
consistent state: if the statement by Member_1 is false, then both statements of Member_2 are true;
it follows that Member_1 and Member_3 are former Secret Collaborators,
and Member_2 is a former Righteous Oppositionist, Q.E.D.
Assured that a reasonable and unique answer exists, lets use ECLi P S e to produce it. This is done by program 3_5_black_and_white.ecl9:
9 This follows roughly the program presented by J. Schimpf to the Liars problem, see
[Schimpf-10a].
141
/*1*/
/*2*/
/*3*/
:- lib(ic).
:- lib(ic_symbolic).
:-local domain(club_member(righteous_oppositionist,secret_collaborator)).
/*4*/
/*5*/
top :solve(_).
/*6*/
ic_symbolic:indomain(Member_1),
ic_symbolic:indomain(Member_2),
ic_symbolic:indomain(Member_3),
writeln("Member_1":Member_1),
writeln("Member_2":Member_2),
writeln("Member_3":Member_3),
writeln("Member_2_said_first":Member_2_said_first),
writeln("Member_2_said_next":Member_2_said_next).
142
It should be remembered that the symbol => denotes an implication as dened in logic, see Table 3.1. It diers from the Prolog implications, see Table 2.1.
ConX
True
False
False
True
ConY
True
True
False
False
is an FS-type problem.
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
%
%
%
%
%
%
%
143
0). % No
1). % Yes
1). % No
% Yes
% No
% Yes
% No
3.7
The programs presented so far, which used only propagation, are exceptional.
Normally search is needed to get a solution11 . A series of example follows, for
which - despite their seemingly simplicity - search is mandatory.
11 Even for problems successfully solved with propagation only, search may be used to accelerate the solution.
144
3.7.1
Three equations
:- lib(ic).
/*2*/
/*3*/
top :[X,Y,Z]::0..6,
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
X + Y + Z #= 9,
write("Constraint X + Y + Z #= 9"),nl,
write("does not reduce domains:"),nl,
get_domain(X, LX),write("Domain of X ="),write(LX),nl,
get_domain(Y, LY),write("Domain of Y ="),write(LY),nl,
get_domain(Z, LZ),write("Domain of Z ="),write(LZ),nl,
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*14*/
2*X+4*Y+3*Z #= 28,
write("The additional constraint 2*X + 4*Y +3* Z #= 28"),
nl,write("neither reduces domains:"),nl,
get_domain(X, LLX),write("Domain of X ="),write(LLX),nl,
get_domain(Y, LLY),write("Domain of Y ="),write(LLY),nl,
get_domain(Z, LLZ),write("Domain of Z ="),write(LLZ),nl,
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
4*X+2*Y+Z #= 18,
write("At long last the constraint 4*X + 2*Y +Z #= 18"),
nl,write("reduces domains:"),nl,
get_domain(X, LLLX),write("Domain of X ="),write(LLLX),
nl,get_domain(Y, LLLY),write("Domain of Y ="),write(LLLY),
nl,get_domain(Z, LLLZ),write("Domain of Z ="),write(LLLZ),nl,
write("However, some values from the domains remain inconsistent."),nl,
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
labeling([X,Y,Z]),
write("Now,labeling is finishing the job of reducing domains:"),nl,
get_domain(X, KX),write("Domain of X ="),write(KX),nl,
get_domain(Y, KY),write("Domain of Y ="),write(KY),nl,
get_domain(Z, KZ),write("Domain of Z ="),write(KZ),nl,
write("and providing the unique solution:"),nl,
write("X = "),write(X),nl,
write("Y = "),write(Y),nl,
write("Z = "),write(Z),fail.
/*32*/
/*33*/
12 This
is an FS-type problem.
145
3.7.2
Golfers
:- lib(ic).
/*2*/
/*3*/
top :[Fred,Joe,Tom,Bob]::1..4,
% Tom - variable denoting Toms position in line.
13 This
is an FS-type problem.
146
/*4*/
[Red,Orange,Blue,Plaid]::1..4,
% Blue - variable denoting the position of blue pants in line.
labeling([Fred,Joe,Tom,Bob,Orange,
Blue,Red,Plaid]),
/*14*/
write("Fred,Joe,Tom,Bob"),nl,
/*15*/
write([Fred,Joe,Tom,Bob]),nl,
/*16*/
/*17*/
write("Red,Orange,Blue,Plaid"),nl,
write([Red,Orange,Blue,Plaid]),nl.
147
Red,Orange,Blue,Plaid
[3, 1, 2, 4]
It means that e.g. Joe is in position 2 in the golfers list and wears pants
of a color corresponding to number 2 in the colors list, i.e. blue pants. The
readability of the message will be taken care of in Section 4.4.4.
This time labeling/1 is also needed to get the solution: constraint propagation is clearly insucient.
3.7.3
Watchtowers
:- lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
14 This
Guards :: 0..12,
sum(Guards) #= 12,
NW + N + NE #= 5,
NE + E + SE #= 5,
NW + W + SW #= 5,
SW + S + SE #= 5,
is an FS-type problem.
148
/*10*/
labeling(Guards),
/*11*/
/*12*/
printf("%3d%3d%3d\n", [NW,N,NE]),
printf("%3d
%5d\n", [W,
E]),
/*13*/
printf("%3d%3d%3d\n", [SW,S,SE]).
2
3
0
0
3.7.4
Examination
A domain declaration may simplify the examination problem from Section 2.4.7
and accelerate its solution. This is shown by the 3_10_egzamination.ecl program15 :
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*7*/
/*9*/
/*11*/
/*13*/
/*15*/
/*17*/
/*19*/
/*21*/
/*23*/
/*25*/
/*27*/
/*29*/
/*31*/
/*33*/
/*35*/
15 This
:- lib(ic).
top :L=[M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,
M16,M17],
L :: 1..4,
M1
M1
M2
M2
M3
M3
M4
M5
M5
M6
M6
M7
M7
M8
M8
M9
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
#\=
M2,
M6,
M6,
M3,
M7,
M9,
M8,
M6,
M11,
M11,
M12,
M12,
M13,
M13,
M9,
M14,
/*6*/
/*8*/
/*10*/
/*12*/
/*14*/
/*16*/
/*18*/
/*20*/
/*22*/
/*24*/
/*26*/
/*28*/
/*30*/
/*32*/
/*34*/
/*36*/
is an FS-type problem.
M1 #\= M5,
M1 #\= M7,
M2 #\= M7,
M2 #\= M8,
M3 #\= M8,
M3 #\= M4,
M4 #\= M9,
M5 #\= M10,
M6 #\= M10,
M6 #\= M7,
M7 #\= M11,
M7 #\= M8,
M8 #\= M12,
M8 #\= M14,
M9 #\= M13,
M10 #\= M11,
#\=
#\=
#\=
#\=
#\=
#\=
#\=
M15,
M15,
M13,
M16,
M14,
M17,
M17,
/*38*/
/*40*/
/*42*/
/*44*/
/*46*/
/*48*/
M11
M12
M13
M13
M14
M15
149
/*37*/
/*39*/
/*41*/
/*43*/
/*45*/
/*47*/
/*49*/
M11
M12
M12
M13
M13
M14
M16
#\=
#\=
#\=
#\=
#\=
#\=
M12,
M16,
M15,
M17,
M16,
M16,
/*50*/
labeling([M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,
M11,M12,M13,M14,M15,M16,M17]),
/*51*/
write(M1),write(", "),write(M2),
write(", "),write(M3),write(", "),write(M4),nl,
/*52*/
/*53*/
/*54*/
This time the solution was obtained immediately. This is a good example of
the eciency of search and propagation performed by ECLi P S e CP S as
compared with search and unications performed by ECLi P S e P rolog.
3.7.5
Queens
16 This
is an FS-type problem.
150
/*1*/
/*2*/
/*3*/
/*4*/
:- lib(ic).
top :queens(L),
write(L).
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
queens([X1,X2,X3,X4,X5,X6,X7,X8]):[X1,X2,X3,X4,X5,X6,X7,X8]::1..8,
safe([X1,X2,X3,X4,X5,X6,X7,X8]),
labeling([X1,X2,X3,X4,X5,X6,X7,X8]),
write([X1,X2,X3,X4,X5,X6,X7,X8]),nl,
fail.
/*11*/
/*12*/
queens(_):write("Thats all!"),nl.
/*13*/
/*14*/
/*15*/
/*16*/
safe([]).
safe([H|T]):no_attack(H,T),
safe(T).
/*17*/
/*18*/
no_attack(X,Xs):no_attack(X,Xs,1).
/*19*/
no_attack(_,[],_).
/*20*/
no_attack(X,[Y|Ys],Nb):-
/*21*/
/*22*/
X #\= Y,
X #\= Y + Nb,
/*23*/
/*24*/
Y #\= X + Nb,
Nb1 is Nb+1,
/*25*/
no_attack(X,Ys,Nb1).
There are 92 placements, from which only the rst and last three are presented:
[1, 5, 8, 6, 3, 7, 2, 4]
[1, 6, 8, 3, 7, 4, 2, 5]
[1, 7, 4, 6, 8, 2, 5, 3]
.......................
[8, 2, 5, 3, 1, 7, 4, 6]
[8, 3, 1, 6, 2, 5, 7, 4]
[8, 4, 1, 3, 6, 2, 7, 5]
This time labeling/1 was also needed to get the solution; propagation alone
was clearly insucient.
3.7.6
151
Conguration
:- lib(ic).
top :Components=[A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2],
Components :: 0..1,
Cost:: 1..2100,
A_2
C_2
B_3
A_2
A_1
B_3
not
not
not
not
not
not
in
in
in
in
in
in
the
the
the
the
the
the
same
same
same
same
same
same
configuration
configuration
configuration
configuration
configuration
configuration
/*15*/
/*16*/
labeling(Components),
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
17 This
is an FS-type problem.
152
/*25*/
/*26*/
/*27*/
write_configuration([H1|T1],[_|T2]):H1 is 0,
write_configuration(T1,T2).
/*28*/
write_configuration([],[]).
3.8
Exercises
3.8 Exercises
153
Solution:
A=4, B=1, C=2, D=8, E=3, F=5, G=7, H=6
Equations and conditionals 2
Write a program to determine the smallest integer solution for the following equations and conditionals:
B+G=D
B+C=A
C+E+G=F
If D < A then C = 2
If D >= A then E = 2.
Solution:
A=5, B=4, C=1, D=7, E=2, F=6, G=3
A visit
The Smith family and their three children want to pay a visit but they do
not all have the time to do so. Following are few hints who will go and
who will not: If Mr Smith comes, his wife will come too. At least one of
their two sons Matt and John will come. Either Mrs Smith or Tim will
come, but not both. Either Tim and John will come, or neither will come.
If Matt comes, then John and his father will also come. Write a program
to determine who went and who did not.
Horse derby
At last horse derby, 10 ne horses completed the grueling 3 mile course.
Predictably, as per every year, the results mysteriously went missing. However, various marshals remembered the following snippets of information:
Sylvester lost to Zebra Wings. Zebra Wings beat Sylwester, Frogmans
Flippers and Tweetie Pie. Fizzy Pop lost to Minty Mouse, Sylvester and
CD Player. Frogmans Flippers beat Windy Miller, CD Player and Sylwester. Top Trumps lost to CD Player, Kool Kat and Tweetie Pie. CD
Player beat Top Trumps and Fizzy Pop. Tweetie pie lost to Zebra Wings
and Sylvester. Kool Kat lost to Tweetie Pie and Frogmans Flippers. Frogmans Flippers beat Fizzy Pop, Minty Mouse and CD Player. CD Player
lost to Frogmans Flippers, Kool Kat and Tweetie Pie. Top Trumps beat
Fizzy Pop and Windy Miller. Minty Mouse lost to Windy Miller and Sylwester. Windy Miller lost to Tweetie Pie and CD Player. Write a program
to work out who nished where.
154
Spring fete
At the recent spring fete, four keen gardeners were displaying their ne
roses. In total there were four colors and each rose appeared in two colors.
Mr Green had a yellow rose. Mr Yellow did not have a red one. Mr Red
had a blue rose but not a green one, whilst Mr Blue did not have a yellow
one. One person with a red rose also had a green one. One person with
a yellow rose also had a blue one. One of the persons with a green rose
had no red. Neither of the persons with a yellow rose had a green one. No
person has two roses of the same color and no two persons had the same
two color roses and their names provide no clues. Write a program which
settles who had which color roses.
Cake theft
During a recent police investigation, Chief Inspector Stone was interviewing ve local villains to try and identify who stole Mrs Archers cake from
the mid-summers fair. Below is a summary of their statements:
1)Arnold: it wasnt Edward it was Brian
2)Brian: it wasnt Charlie it wasnt Edward
3)Charlie: it was Edward it wasnt Arnold
4)Derek: it was Charlie it was Brian
5)Edward:it was Derek it wasnt Arnold
It was well known that each suspect told exactly one lie. Write a program
to determine who stole the cake.
Horse race
A gambler bet on a horse race, but the bookie wouldnt tell him the results
of the race. The bookie gave clues as to how the ve horses nished which
may have included some ties and wouldnt pay the gambler o unless
the gambler could determine how the ve horses nished based on the
following clues:
1. Penuche Fudge nished before Near Miss and after Whispered Promises.
2. Whispered Promises tied with Penuche Fudge if and only if Happy Go
Lucky did not tie with Skippers Gal.
3. Penuche Fudge nished as many places after Skippers Gal as Skippers
Gal nished after Whispered Promises if and only if Whispered Promises
nished before Near Miss.
The gambler thought for a moment, then answered correctly. Write a
program to determine how did the ve horses nish the race.
3.8 Exercises
155
Grades
Five friends in the sixth form took the same combination of A-level subjects. Each obtained a dierent grade in each subject taken, and no two
students had the same grade in the same subject. Write a program to determine grades obtained for each subject by each student, provided that:
- Andrew outscored Bridget in Physics, and Neil in Math.
- Wendy was the only girl to get a C grade, but she managed no A
grades
- The pupil with an E in Math gained a B in Chemistry, but was not
awarded a C in Physics.
- Pauls Physics grade was a D and his highest grade was a C.
- The B in Math did not go to the same student as the E in Physics.
- Bridgets best result was in Chemistry, but her Math grade was lower
than Pauls.
The Autumn Leaves Trail
Thousands of tourists drive the Autumn Leaves Trail each fall to enjoy the
multicolored vista of changing seasons18. The Trail starts in Summerset
and goes north 10.0 miles to Fallbrook. Five scenic spots highlight the
drive, each providing parking along the narrow road with a spectacular
view of a dierent Trail attraction; each scenic spot is at a dierent milepost designating its distance from Summerset in tenths of a mile. Given
the road map data below, write a program to determine at what milepost
along the Autumn Leaves Trail each viewpoint is located:
1. No two consecutive scenic spots are the same distance apart; the longest
drive between any two consecutive locations (including end points) on the
Trail is 3.6 miles, while the shortest is .4 miles.
2. The distance along the Autumn Leaves Trail from Summerset to Cucumber Creek equals the distance going north from Old Man Mountain
to the White Oak Inn.
3. The Amish Covered Bridge, which isnt the last scenic spot along the
route, is 1.0 miles south of Fallbrook.
4. The Cucumber Creek spot is twice as far from the Sugar Maple Farm
stop as it is from the Old Man Mountain viewpoint.
5. The White Oak Inn and Cucumber Creek photographic opportunities
lie more than 5.0 miles apart.
6. The rst scenic spot on the Trail is at milepost 1.8 north of Summerset.
18 This
156
Gardens
Five friends have their gardens next to one another, where they grow three
kinds of crops: fruits (apple, pear, nut, cherry), vegetables (carrot, parsley,
gourd, onion) and owers (aster, rose, tulip, lily)19 .
1. They grow 12 dierent varieties.
2. Everybody grows exactly 4 dierent varieties.
3. Each variety is at least in one garden.
4. Only one variety is in 4 gardens.
5. Only in one garden are all 3 kinds of crops.
6. Only in one garden are all 4 varieties of one kind of crops.
7. Pears are only in the two border gardens.
8. Pauls garden is in the middle with no lily.
9. Aster grower doesnt grow vegetables.
10. Rose grower doesnt grow parsley.
11. Nuts grower has also gourd and parsley.
12. In the rst garden are apples and cherries.
13. Only in two gardens are cherries.
14. Sam has onions and cherries.
15. Luke grows exactly two kinds of fruit.
16. Tulips are only in two gardens.
17. Apples are in a single garden.
18. Only in one garden next to the Zicks is parsley.
19. Sams garden is not on the border.
20. Hank grows neither vegetables nor asters.
21. Paul has exactly three kinds of vegetable.
Write a program to determine who has which garden and what is grown
where.
Open House 20
Five students in the local gifted and talented program (three girls named
Brittany, Natalie, and Olive, and two boys named Emile and Moises) organized their schools open house this year. Each of these students is
majoring in a dierent area of study (geography, language, math, philosophy, or sculpture). Some of these students enlisted one or more relatives
to assist with the production of the open house (mother, father, or grandmother), though no one enlisted more than one of any kind of relative.
Write a program to discover each students full name (surnames are Brad19 This
20 This
3.8 Exercises
157
shaw, Henderson, Smith, Wu, and Zacher), area of study, and the relative
or relatives, if any, of each child who assisted, provided that:
1. Smith (who isnt Moises or Olive) isnt the philosophy major.
2. Two of Wus relatives assisted with the program.
3. Zacher enlisted fewer of his or her relatives to assist than at least one
other student.
4. The sculpture major is the only one who enlisted no relatives to assist.
5. Brittany and Henderson each enlisted one parent; neither of them enlisted a grandmother, and neither of them is the math major.
6. Moises and the geography major either both enlisted their fathers assistance, or neither of them did.
7. No two students of the same gender enlisted their mothers.
8. Bradshaws father didnt assist.
9. Olive enlisted one more relative than the math major.
10. Natalie is the language major, and her father didnt assist.
Swimming race
Five competitors - A, B, C, D and E - enter a swimming race that awards
gold, silver and bronze medals to the rst three to complete it. Each of
the following compound statements about the race is false, although one
of two clauses in each may be true:
- A didnt win the gold, B didnt win the silver.
- D didnt win the silver and E didnt win the bronze.
- C won a medal, D didnt.
- A won a medal, C didnt.
- D and E both won medals.
Write a program to determine who won each of the medals.
Queue for plane tickets 21
Five people are standing in a queue for plane tickets in Germany; each
one has a name, an age, a favorite Internet website, a place they live, a
hairstyle and a destination from the sets:
Their names are: Bob, Keeley, Rachael, Eilish and Amy, their ages: 14, 21,
46, 52 and 81, their favorite Internet websites: Rush Limbaugh Show,
Conservapedia, Chronicles: A Magazine of American Culture, Je
Rense Program and American Thinker, they live at a town, a city, a
village, a farm and a youth hostel, their hairstyle is: afro, long, straight,
curly and bald, their destinations are: France, Australia, England, Africa
21 This
158
Chapter 4
Introductory remarks
The concepts introduced in this chapter and Chapter 6 are basic for modeling
and solving complicated combinatorial problems. In order to create ecient
platforms for modeling and solving CSP and COP, a set of fundamental concepts and predicates corresponding to these concepts is needed. For continuous
dynamic systems, dealt with e.g. in mechanics and control engineering, the
concepts needed had been developed and had matured over ages, starting with
pioneering work by Newton and Leibnitz on dierential equations. For combinatorial problems the concepts started to be developed with the advent of
Prolog and CLP, and culminated in dening and programming a series of basic, extremely useful high-level abstracts implemented as global constraints, see
[Baldiceanu-94] and [Baldiceanu-10]. Global constraints are constraints dening
complex relations over a number of input lists of variables. They are supported by libraries ic_global, lib(ic_cumulative), lib(ic_edge_finder),
lib(ic_edge_finder3). lib(branch_and_bound) They are contrasted with
already discussed elementary constraints with at most one input list, supported
by ic and branch_and_bound libraries. The use of global predicates enhances
program readability, declarativity and eectiveness while substantially decreasing the time needed to model the problem. The ECLi P S e CP S user may
nd elementary as well as global constraints in the Alphabetical Predicate Index
159
160
4.2
The built-in:
alldifferent(?List)
is fullled if all elements of the List=[X1,...,Xn] are pairwise dierent.
This is one of the most useful and often used global constraints. Theoretically
speaking it corresponds to the following set of disequations:
X1#\=X2,
X1#\=X3,
.......
X1#\=Xn,
X2#\=X3,
.......
X2#\=Xn,
.......
X(n-1)#\=Xn,
However, the search and propagation methods for alldifferent([X1,...,Xn])
are much more ecient than those for the above denition.
1 The ic library provides as well support for alldierent/1 and element/3, but in a less
eective way.
161
:- lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
top :[X,Y,Z]::1..4,
alldifferent([X,Y,Z]),
indomain(X),
indomain(Y),
indomain(Z),
writeln("X":X),
writeln("Y":Y),
writeln("Z":Z),
fail.
/*12*/
top:-
/*13*/
write("Thats it."),nl.
is an FS-type problem.
162
X =3 Y =4 Z =2
X =4 Y =1 Z =2
X =4 Y =1 Z =3
X =4 Y =2 Z =1
X =4 Y =2 Z =3
X =4 Y =3 Z =1
X =4 Y =3 Z =2
Thats it.
:- lib(ic).
/*2*/
top :-
/*3*/
[V,W,X,Y,Z]::1..4,
/*4*/
/*5*/
alldifferent([V,W,X,Y,Z]),
indomain(V),
/*6*/
indomain(W),
/*7*/
/*8*/
indomain(X),
indomain(Y),
/*9*/
/*10*/
indomain(Z),
writeln(V:V),
/*11*/
writeln(W:W),
/*12*/
/*13*/
writeln(X:X),
writeln(Y:Y),
/*14*/
writeln(Z:Z).,
4.3
The built-in:
element(?Index, ++List, ?Value)
constraints Value to be at the position Index in the grounded integer list List.
163
:- lib(ic).
/*2*/
top:-
/*3*/
element(Index,[20,10,41,32],41),
/*4*/
/*5*/
writeln("Index ":Index),
element(2,[](20,10,41,32),Indexed_Value),
/*6*/
/*7*/
writeln("Indexed_Value ":Indexed_Value),
element(I,[20,10,41,32],I_V),
/*8*/
writeln("I ":I),
/*9*/
writeln("I_V":I_V).
The examples presented below are classied into the following two problem
classes:
1. Feasible assignment problems, aiming at joining elements of some sets so
as to fulll constraints of belongness.
2. Feasible sequencing problems, aiming at ordering elements of some set so
as to fulll constraints of precedence.
The adjective feasible is used to distinguish the problems from optimum once
discussed in Chapter 5.
3 This
is an FS-type problem.
164
4.4
Their essence is to nd - for any element of some set - elements from some
other sets so as to fulll some constraints of belongness. Tie constraints dene
constraints among elements of various sets.
4.4.1
:- lib(ic).
top:sendmore(_).
/*4*/
sendmore(L) :-
/*5*/
/*6*/
L = [S,E,N,D,M,O,R,Y],
L :: [0..9],
/*7*/
alldifferent(L),
/*8*/
/*9*/
S #\= 0,
M #\= 0,
/*10*/
/*11*/
labeling(L),
4 It is attributed to Henry Dudeney who published it in the July 1924 issue of Strand
Magazine
5 This is an FS-type problem.
/*12*/
write("
/*13*/
/*14*/
write("
S E N D"),nl,
write(" "),write(M),write(0),write(R),write(E),
/*15*/
write("
/*16*/
/*17*/
write(" ----------------"),nl,
write(" "),write(M),write(0),write(N),write(E),write(Y),
/*18*/
write("
165
"),write(S),write(E),write(N),write(D),
M O R E"),nl,
M O N E Y"),nl,nl.
S E N D
1085
------
M O R E
----------
10652
M O N E Y
4.4.2
FIFTEEN
166
:- lib(ic).
top:assert(counter(0)),
P = [F,I,V,E,T,N,L,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10],
P :: [0..9],
alldifferent([F,I,V,T,N,L,E]),
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
F #\= 0,
E#\=0,
E #= 5,
A1#\=0,
A4#\=0,
A7#\=0,
A10#\=0,
my_modulo_5(F,I,V,E),
my_modulo_11(E,L,E,V,E,N),
/*16*/
/*17*/
/*18*/
/*19*/
/*19*/
A1 +
E + 10*V + 100*I + 1000*F + 10000*A2 + 100000*A3
A5 + 10*E + 100*V + 1000*I + 10000*F + 100000*A6
A8 + 10*A9 + 100*E + 1000*V + 10000*I + 100000*F
1000000*F + 100000*I+ 10000*F + 1000*T + 100*E +
/*20*/
/*21*/
/*22*/
/*23*/
labeling(P),
count,
counter(Solution_number),
write("Solution "), write(Solution_number),write(":"),nl,
/*24*/
/*25*/
write("
write("
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
+ 1000000*A4 +
+ 1000000*A7 +
+ 1000000*A10 #=
10*E + N,
/*36*/ top:-nl,nl,
/*37*/
write("Thats everything!").
167
/*38*/ my_modulo_5(F,I,V,E):/*39*/
integers(X),
/*40*/
E+10*V+100*I+1000*F #= X*5.
/*41*/ my_modulo_11(E,L,E,V,E,N):/*42*/
integers(X),
/*43*/
N+10*E+100*V+1000*E+10000*L+100000*E #= X*11.
/*44*/ count:/*45*/
retract(counter(Old)),
/*46*/
New is Old + 1,
/*47*/
assert(counter(New)).
The problem has 18 solution, all with the same FIFTEEN. The rst and the
last one are as follows:
Solution 1:
8
A1
1094085 A4 A3 A2 F I V E
1540859 A7 A6 F I V E A5
1408599 A10 F I V E A9 A8
------- -------------------4043551
F I F T E E N
.........................
Solution 18:
9
A1
1594085 A4 A3 A2 F I V E
1040859 A7 A6 F I V E A5
1408598 A10 F I V E A9 A8
------- -------------------4043551
F I F T E E N
4.4.3
Both global constraints discussed so far enable to simplify the program solving
the who with whom puzzle from Section 3.6.2 while at the same time enabling the
generation of a readable message. The modied program 4_6_who_with_whom_
again.ecl6 is as follows:
6 This
is an FS-type problem.
168
/*1*/
:- lib(ic).
/*2*/
top :/*3*/
[Andy, Ben, Carl, Dusty]::[1..4],
/*4*/
[Olive, Eva, Paula, Sabina]::[1..4],
% concert=1, cinema=2, theater=3, exhibition=4
% It means:
if e. g.
Ben=Olive=4, then
% Ben and Olive went to an exhibition
% Andy enjoyed a concert:
/*5*/
Andy#=1,
% Ben accompanied Olive:
/*6*/
Ben#=Olive,
% Carl has not seen Eva:
/*7*/
Carl#\=Eva,
% Paula went to a cinema:
/*8*/
Paula#=2,
% Eva went to a theater:
/*9*/
Eva#=3,
/*10*/
/*11*/
alldifferent([Andy,Ben,Carl,Dusty]),
alldifferent([Olive,Eva,Paula,Sabina]),
/*12*/
write(Andy),write(" "),write(Ben),write(" "),
/*13*/
write(Carl),write(" "),write(Dusty),nl,
/*14*/
write(Olive),write(" "),write(Eva),write(" "),
/*15*/
write(Paula),write(" "),write(Sabina),nl,nl,
% End of solution part.
% Beginning of message part:
% Determining the numbers for boys on the boy list:
/*16*/
element(Number_of_First_Boy,[Andy,Ben,Carl,Dusty],1),
/*17*/
element(Number_of_Second_Boy,[Andy,Ben,Carl,Dusty],2),
/*18*/
element(Number_of_Third_Boy,[Andy,Ben,Carl,Dusty],3),
/*19*/
element(Number_of_Fourth_Boy,[Andy,Ben,Carl,Dusty],4),
% Determining the numbers for girls on the girl list:
/*20*/
element(Number_of_First_Girl,[Olive, Eva,Paula,Sabina],1),
/*21*/
element(Number_of_Second_Girl,[Olive, Eva,Paula,Sabina],2),
/*22*/
element(Number_of_Third_Girl,[Olive, Eva,Paula,Sabina],3),
/*23*/
element(Number_of_Fourth_Girl,[Olive, Eva,Paula,Sabina],4),
% Translating numbers for boys to names:
/*24*/
name_of_boy(Number_of_First_Boy,Name_of_1_boy),
/*25*/
name_of_boy(Number_of_Second_Boy,Name_of_2_boy),
/*26*/
name_of_boy(Number_of_Third_Boy,Name_of_3_boy),
/*27*/
169
name_of_boy(Number_of_Fourth_Boy,Name_of_4_boy),
a concert."),nl,
a cinema."),nl,
a theater."),nl,
an exhibition."),nl.
/*40*/ name_of_boy(1,"Andy").
/*41*/ name_of_boy(2,"Ben").
/*42*/ name_of_boy(3,"Carl").
/*43*/ name_of_boy(4,"Dusty").
/*44*/ name_of_girl(1,"Olive").
/*45*/ name_of_girl(2,"Eva").
/*46*/ name_of_girl(3,"Paula").
/*47*/ name_of_girl(4,"Sabina").
4.4.4
Golfers again
Both global constraints discussed so far may also be used to simplify the program
solving the golfers puzzle from Section 3.7.2 while at the same time enabling the
170
:- lib(ic).
top :[Fred,Joe,Tom,Bob]::1..4,
% Tom - variable denoting Toms position in line.
alldifferent([Fred,Joe,Tom,Bob]),
[Red,Orange,Blue,Plaid]::1..4,
% Blue - variable denoting the position of blue pants in line.
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
7 This
labeling([Fred,Joe,Tom,Bob,Orange,Blue,Red,Plaid]),
write("Fred,Joe,Tom,Bob"),nl,
write([Fred,Joe,Tom,Bob]),nl,
write("Red,Orange,Blue,Plaid"),nl,
write([Red,Orange,Blue,Plaid]),nl,
% End of problem solving part
% Beginning of message generating part:
% The point at issue: finding pairs (Name_of_golfer, color_of_pants)
% Number of golfer at position n, n=1,..4:
element(Golfer_with_number_1,[Fred,Joe,Tom,Bob],1),
element(Golfer_with_number_2,[Fred,Joe,Tom,Bob],2),
element(Golfer_with_number_3,[Fred,Joe,Tom,Bob],3),
element(Golfer_with_number_4,[Fred,Joe,Tom,Bob],4),
is an FS-type problem.
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
171
name_of_golfer(1,"Fred").
name_of_golfer(2,"Joe").
name_of_golfer(3,"Tom").
name_of_golfer(4,"Bob").
/*41*/
/*42*/
color(1,"red").
color(2,"orange").
/*43*/
color(3,"blue").
/*44*/
color(4,"plaid").
172
From this program and from the previous one it can be seen that ECLi P S e CLP
is decidedly more powerful for problem solving than for generating messages
displaying solutions. For both the 4_6_who_with_whom_again.ecl and the
4_7_golfers_again.ecl program, the message generating part was more voluminous and verbose than the problem solving part.
4.4.5
The three cubes program from Section 2.4.2 could also be simplied with the help
of the two global constraints discussed so far. The constraints are also useful for
generating a readable message. The new program 4_8_three_cubes_again.ecl8
is as follows:
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
:-lib(ic).
top:color=[Black,Grey, White],
Size=[Small, Large, Medium],
[Black,Grey, White] :: [1..3],
[Small, Large, Medium] :: [1..3],
alldifferent([Black,Grey, White]),
alldifferent([Small, Large, Medium]),
Cubes = [ cube(1,_,_), cube(2,_,_), cube(3,_,_)],
% cube(Cube_number,Cube_size,Cube_color)
/*10*/
Constraints = [ cube(Black,_,black),
cube(Grey,Size_of_grey_cube,grey),
cube(White,_,white),
%(2) The small cube has number 2:
cube(2,Small,_),
% Nothing is known about the medium cube:
cube(Medium,medium,color_of_medium_cube),
% Nothing is known about the large cube:
cube(Large,large,color_of_large_cube),
cube(3,Size_3,_) ],
/*11*/
/*12*/
%(3) The number of the black cube is greater than the one on the white cube
Black#>White,
%(4) The size of cube with number 3
% is smaller than the size of the grey cube:
8 This
is an FS-type problem.
/*13*/
smaller_size(Size_3,Size_of_grey_cube),
% The elements
of
173
grounding(Constraints, Cubes),
writeln(Color), writeln(Size),
for variables:
[Black, Grey, White]
[Small, Large, Medium]*/
% Beginning of message generating part. The problem: find triples
% (Number,Color,Size) with same value of elements.
% Number of color on position n, n=1,2,3:
/*16*/
element(Number_of_color_1,[Black,Grey, White],1),
/*17*/
element(Number_of_color_2,[Black,Grey, White],2),
/*18*/
element(Number_of_color_3,[Black,Grey, White],3),
% Translating number of color into name of color:
/*19*/
color(Number_of_color_1,Name_of_color_1),
/*20*/
color(Number_of_color_2,Name_of_color_2),
/*21*/
color(Number_of_color_3,Name_of_color_3),
% Number of size on position n, n=1,2,3:
/*22*/
element(Number_of_size_1,[Small,Large,Medium],1),
/*23*/
element(Number_of_size_2,[Small,Large,Medium],2),
/*24*/
element(Number_of_size_3,[Small,Large,Medium],3),
% Translating number of size into name of size:
/*25*/
size(Number_of_size_1,Name_of_size_1),
/*26*/
size(Number_of_size_2,Name_of_size_2),
/*27*/
size(Number_of_size_3,Name_of_size_3),
% Joining
/*28*/
/*29*/
/*30*/
elements of
write("The
write(" is
write("The
write(" is
write("The
write(" is
174
/*31*/
/*32*/
/*33*/
color(1,black).
color(2,grey).
color(3,white).
/*34*/
/*36*/
/*36*/
size(1,small).
size(2,large).
size(3,medium).
/*37*/
/*38*/
/*39*/
smaller_size(small,large).
smaller_size(small,medium).
smaller_size(medium,large).
/*40*/
/*41*/
/*42*/
brighter(white,grey).
brighter(white,black).
brighter(grey,black).
/*43*/
/*44*/
grounding([],_).
grounding([H|T],List):-
/*45*/
member(H,List),
/*46*/
grounding(T,List).
4.4.6
Queens again
The alldierent/1 build-in may be used for a rather original solution to the
8 queens problem. The corresponding program 4_9_queens_again.ecl9 is as
follows:
/*1*/
:-lib(ic).
/*2*/
/*3*/
top:queens(_).
9 This
is an FS-type problem.
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
queens([X1,X2,X3,X4,X5,X6,X7,X8]):[X1,X2,X3,X4,X5,X6,X7,X8]::1..8,
[X11,X22,X33,X44,X55,X66,X77,X88]::1..16,
[X18,X27,X36,X45,X54,X63,X72,X81]::1..16,
alldifferent([X1,X2,X3,X4,X5,X6,X7,X8]),
X11 #= X1+1,
X22 #= X2+2,
X33 #= X3+3,
X44 #= X4+4,
X55 #= X5+5,
X66 #= X6+6,
X77 #= X7+7,
X88 #= X8+8,
alldifferent([X11,X22,X33,X44,X55,X66,X77,X88]),
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
X18 #= X1+8,
X27 #= X2+7,
X36 #= X3+6,
X45 #= X4+5,
X54 #= X5+4,
X63 #= X6+3,
X72 #= X7+2,
X81 #= X8+1,
alldifferent([X18,X27,X36,X45,X54,X63,X72,X81]),
/*27*/
/*28*/
labeling([X1,X2,X3,X4,X5,X6,X7,X8]),
write([X1,X2,X3,X4,X5,X6,X7,X8]),nl,fail.
/*29*/
queens(_):-
/*30*/
write("Thats it!").
175
4.4.7
Allocating resources between tasks is a typical combinatorial application, successfully solved by CLP languages. This is illustrated by the following example:
Any one of seven machines may perform any of seven dierent tasks, but at
dierent cost, as shown by Table 4.1. The tasks should be allocated between
machines so as to keep the overall cost below the threshold equal to 185.
The solution is given by program 4_10_7_machines_7_tasks.ecl10:
10 This
is an FS-type problem.
176
Machine
1
2
3
4
5
6
7
1
15
45
56
13
45
23
76
2
23
76
45
45
49
25
98
3
43
32
87
34
18
29
86
Task
4
27
39
75
51
48
39
41
5
76
72
34
52
58
52
34
6
43
37
76
21
98
41
76
7
91
48
29
76
23
12
77
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
:- lib(ic).
top :[O1,O2,O3,O4,O5,O6,O7]::1..7,
[K1,K2,K3,K4,K5,K6,K7]::0..100,
alldifferent([O1,O2,O3,O4,O5,O6,O7]),
element(O1,[15,23,43,27,76,43,91],K1),
element(O2,[45,76,32,39,72,37,48],K2),
element(O3,[56,45,87,75,34,76,29],K3),
element(O4,[13,45,34,51,52,21,76],K4),
element(O5,[45,49,18,48,58,98,23],K5),
element(O6,[23,25,29,39,52,41,12],K6),
element(O7,[76,98,86,41,34,76,77],K7),
K1+K2+K3+K4+K5+K6+K7 #< 185,
labeling([K1,K2,K3,K4,K5,K6,K7]),
display_results([O1,K1,O2,K2,O3,K3,O4,K4,
O5,K5,O6,K6,O7,K7],1),
K is K1+K2+K3+K4+K5+K6+K7,
write("Cost = "),write(K),
L=[O1,K1,O2,K2,O3,K3,O4,K4,O5,K5,O6,K6,O7,K7],
write(L).
display_results([],_):!.
display_results([A,B|R],N):write("Machine "),write(N),write(" is performing task "),write(A),
write(" costing "),write(B),write("."),nl,
/*24*/
M is N+1,
/*25*/
display_results(R,M).
177
Now we asked to be shown all solutions using the option more form ECLi P S e ,
Main Menu. This results in:
Machine 1 is performing task 1 costing 15.
Machine 2 is performing task 4 costing 39.
Machine 3 is performing task 7 costing 29.
Machine 4 is performing task 6 costing 21.
Machine 5 is performing task 3 costing 18.
Machine 6 is performing task 2 costing 25.
Machine 7 is performing task 5 costing 34.
Overall cost = 81
[O1,K1,O2,K2,O3,K3,O4,K4,O5,K5,O6,K6,O7,K7] =
[1, 15, 4, 39, 7, 29, 6, 21, 3, 18, 2, 25, 5, 34]
Machine 1 is performing task 1 costing 15.
Machine 2 is performing task 4 costing 39.
Machine 3 is performing task 2 costing 45.
Machine 4 is performing task 6 costing 21.
Machine 5 is performing task 3 costing 18.
Machine 6 is performing task 7 costing 12.
Machine 7 is performing task 5 costing 34.
Overall cost = 184
[O1,K1,O2,K2,O3,K3,O4,K4,O5,K5,O6,K6,O7,K7] =
[1, 15, 4, 39, 2, 45, 6, 21, 3, 18, 7, 12, 5, 34]
Machine 1 is performing task 2 costing 23.
Machine 2 is performing task 6 costing 37.
Machine 3 is performing task 5 costing 34.
Machine 4 is performing task 1 costing 13.
Machine 5 is performing task 3 costing 18.
Machine 6 is performing task 7 costing 12.
Machine 7 is performing task 4 costing 41.
Overall cost = 178
[O1,K1,O2,K2,O3,K3,O4,K4,O5,K5,O6,K6,O7,K7] =
[2, 23, 6, 37, 5, 34, 1, 13, 3, 18, 7, 12, 4, 41]
Machine 1 is performing task 4 costing 27.
Machine 2 is performing task 6 costing 37.
Machine 3 is performing task 7 costing 29.
Machine 4 is performing task 1 costing 13.
Machine 5 is performing task 3 costing 18.
Machine 6 is performing task 2 costing 25.
Machine 7 is performing task 5 costing 34.
Overall cost = 183
178
[O1,K1,O2,K2,O3,K3,O4,K4,O5,K5,O6,K6,O7,K7]
4.4.8
1
1
4
6
2
11
6
3
Task
3 4
5 7
2 8
9 12
5
13
10
15
alldifferent([O1,O2,O3]),
is an FS-type problem.
179
/*12*/
display_results([A,B|R],N):-
/*13*/
/*14*/
/*15*/
M is N+1,
display_results(R,M).
/*16*/
display_results([],_).
4.4.9
1
1
1
4
4
6
6
2
11
11
6
6
3
3
Task
3 4
5 7
5 7
2 8
2 8
9 12
9 12
5
13
13
10
10
15
15
6
0
0
0
0
0
0
180
:- lib(ic).
top :[M1,M2,M3,M12,M22,M32] :: 1..6,
M12 = 4 means that machine 1 is performing task 4.
[K1,K2,K3,K12,K22,K32] :: 0..16,
K12 = 7 means that machine 1 is performing task 4 with cost 7.
alldifferent([M1,M2,M3,M12,M22,M32]),
/*6*/
element(M1,[1,11,5,7,13,0],K1),
% E.g. M12 = 4 means that machine 1 is performing task 4 with cost 7:
/*7*/
element(M12,[1,11,5,7,13,0],K12),
/*8*/
element(M2,[4,6,2,8,10,0],K2),
/*9*/
element(M22,[4,6,2,8,10,0],K22),
/*10*/
element(M3,[6,3,9,12,15,0],K3),
/*11*/
element(M32,[6,3,9,12,15,0],K32),
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*33*/
/*34*/
display_results([],_).
display_results([A,B|R],N):not(B = 0),
N =< 3,
write("Machine "),write(N),write(" is performing task "),write(A),
write(" costing "),write(B),write("."),nl,
M is N+1,
display_results(R,M).
display_results([A,B|R],N):not(B = 0),
N > 3,
M is N - 3,
write("Machine "),write(M),write(" is performing task "),write(A),
write(" costing "),write(B),write("."),nl,
Q is N+1,
display_results(R,Q).
/*35*/
display_results([_,_|R],N):-
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
12 This
is an FS-type problem.
/*36*/
M is N+1,
/*37*/
display_results(R,M).
181
4.5
4.5.1
Feasible timetabling
Five rooms
182
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
(13)
(14)
:-lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
top:Days = [Monday,Tuesday,Wednesday,Thursday,Friday],
Colors = [Red,Green,Blue,White,Yellow],
Subjects = [Physics,Mathematics,Informatics,Economics,English],
Marks = [Dull,Difficult,Interesting,Most_Interesting,Nothing_Special],
Technology = [Computer,Internet,Video,ChalkBlackboard,Projector],
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
14 This
Days :: 1..5,
colors :: 1..5,
Subjects :: 1..5,
Marks :: 1..5,
Technology :: 1..5,
is an FS-type problem.
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
183
alldifferent(Days),
alldifferent(colors),
alldifferent(Subjects),
alldifferent(Marks),
alldifferent(Technology),
write("Days = "),write(Days),nl,
write("Colors = "), write(colors),nl,
write("Subjects = "),write(Subjects),nl,
write("Marks = "),write(Marks),nl,
write("Technology = "),write(Technology),nl,nl,
/*40*/write("Partial assignment:"),nl,
/*41*/
SubjectsNames = [Physics-"Physics",Mathematics-"Mathematics",
Informatics-"Informatics", Economics-"Economics",English-"English"],
/*42*/
memberchk(Monday-MondayDays, SubjectsNames),
184
/*43*/
/*44*/
/*45*/
memberchk(Projector-ProjectorTechnology,SubjectsNames),
printf("%w is taught on Monday.", [MondayDays]),nl,
printf("%w is taught using the projector.",[ProjectorTechnology]).
/*46*/
next_to(X,Y,Z):-
/*47*/
/*48*/
X+Z#=Y.
next_to(X,Y,Z):-
/*49*/
X#=Y+Z.
The calculated timetable including graphics and lists are shown by Figure 4.1.
4.5.2
Ten rooms
Let us extend the size of the ve rooms problem from Section 4.5.1 by considering ten rooms, to which ten colors, ten time slots, ten classes, ten marks and
ten technologies had to be attributed. The:
room colors (red, green, blue, white, yellow, pink, violet,
orange, brown, grey),
days a_m and p_m (Monday_a_m,Tuesday_a_m,Wednesady_a_m,
Thursday_a_m,Friday_a_m,Monday_p_m,
185
Tuesday_p_m,Wednesady_p_m,Thursday_p_m,
Friday_p_m),
subjects (physics,mathematics,informatics,economics,English,
chemistry,German,history,music,electronics),
subject marks (dull,difficult,interesting,most_interesting,
nothing_special,exhausting,funny,popular,
singing,absorbing),
technology (computer,internet,video,chalk_blackboard,projector,
reagents,dictionaries,maps,piano,oscilloscope))
are subject to following constraints:
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
(13)
(14)
(15)
(16)
(17)
(18)
(19)
(20)
(21)
(22)
(23)
(24)
(25)
186
popular
On Wednesday p_m a class is run in the orange room
For the history class maps are needed
Piano is in room number 9
There is much singing in the music class
The piano is in the brown room
A class in the brown room is run Thursday p_m
Electronics is taught in the room next to the room were
music is taught
(33) For teaching electronics an oscilloscope is needed
(34) The class that makes use of the oscilloscope is absorbing
(35) On Friday p_m the class is in the grey room.
(26)
(27)
(28)
(29)
(30)
(31)
(32)
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
15 This
:-lib(ic).
top:Days = [Monday_a_m,Tuesday_a_m,Wednesady_a_m,Thursday_a_m,Friday_a_m,
Monday_p_m,Tuesday_p_m,Wednesady_p_m,Thursday_p_m,Friday_p_m],
Colors = [Red,Green,Blue,White,Yellow,Pink,Violet,Orange,Brown,Grey],
Subjects = [Physics,Mathematics,Informatics,Economics,English,
Chemistry,German,History,Music,Electronics],
Marks = [Dull,Difficult,Interesting,Most_Interesting,Nothing_Special,
Exhausting,Funny,Popular,Singing,Absorbing],
Technology = [Computer,Internet,Video,ChalkBlackboard,Projector,
Reagents,Dictionaries,Maps,Piano,Oscilloscope],
Days :: 1..10,
Colors :: 1..10,
Subjects :: 1..10,
Marks :: 1..10,
Technology :: 1..10,
alldifferent(Days),
is an FS-type problem.
/*14*/
/*15*/
/*16*/
/*17*/
187
alldifferent(colors),
alldifferent(Subjects),
alldifferent(Marks),
alldifferent(Technology),
188
189
%(32) Electronics is taught in the room next to the room were music is taught:
/*49*/
adjacent(Electronics,Music,1),
%(33) For teaching electronics an oscilloscope is needed:
/*50*/
Elektronika#=Oscilloscope,
%(34) The class that makes use of the oscilloscope is absorbing:
/*51*/
Oscilloscope#=Absorbing,
%(35) On Friday p_m the class is in the grey room:
/*52*/
Friday_p_m#=Grey,
/*53*/
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
/*59*/
/*60*/
% Complete assignment:
write("Complete assignment:"),nl,
write("Days =
"),write(Days),nl,
write("colors =
"), write(colors),nl,
write("Subjects = "),write(Subjects),nl,
write("Marks =
"),write(Marks),nl,
write("Technology =
"),write(Technology),nl,nl,
/*61*/
/*62*/
/*63*/
/*64*/
/*65*/
/*66*/
/*67*/
/*68*/
/*69*/
/*70*/
% Partial assignment:
write("Partial assignment:"),nl,
SubjectsNames = [Physics-"Physics", Mathematics-"Mathematics",
Informatics-"Informatics", Economics-"Economics",
English-"English",Chemistry-"Chemistry",
German-"German",History-"History",Music-"Music",
Electronics-"Electronics"]
memberchk(Monday_a_m-MondayDays,SubjectsNames),
memberchk(Projector-ProjectorTechnology,SubjectsNames),
printf("%w is taught on Monday.", [MondayDays]),nl,
printf("%w is taught using the projector.",[ProjectorTechnology]).
adjacent(X,Y,Z):X+Z#=Y.
adjacent(X,Y,Z):X#=Y+Z.
The timetables including graphics and lists are shown in Figures 4.2 and 4.3.
190
191
192
4.5.3
The element/3 built-in is almost always used with the alldifferent/1 builtin. This is illustrated by the following example:
The Absurdolands party All Things to All People is a popular political force
to be reckoned with. At its Headquarters each Friday a meeting takes place with
the agenda devoted solely to next week dispatching of party activists to local
communities to meet with local activists, voters and supporters, and persuade
people to vote for the party candidates in the forthcoming elections. Last Friday
the discussion concentrated upon visiting three important local communities,
Lower Hole, Upper Hole and Middle Hole, by three trusted and experienced
party activists, Mr Blather, Mr Jabber and Ms Fable. The visits were supposed
to take place only on Monday, Tuesday or Wednesday, by one party activist each
day, because they were also badly needed at the Headquarters. The problem
to be settled is who should go where. Each of the party activists has special
wishes and hindrances to be taken into account:
1)Activist Blather decided never to travel again to Lower Hole, because at his
last stay there he was invited for lunch to a shabby roadside eatery pot, where
the local activists and supporters presented him with a complete set of Chinese
ball-pens; well, he did not boast about this to his party colleagues.
2)Activist Jabber has no objections for going to Lower Hole or to Upper Hole,
but not on Tuesdays, because his sponsoring benefactor, the Famous Businessman, whom he used to meet at some randomly selected grave at the Loweror Upper Hole cemetery, traditionally devotes each Tuesday to one of his girlfriends. Mr Jabber does not intend to give up those meetings because at each
of them he is presented by the Famous Businessman with a plastic bag lled
with cash and some memos about things he should take care of.
3)To Upper Hole Mr Jabber does not want to go on Monday as well, because
on Mondays all Escort Service Agencies in Upper Hole have a day o.
4)To Lower Hole nobody wants travel on Mondays because then all bars and
restaurants try to sell their Sunday left-overs.
5)Mr Blather should not be dispatched to Upper Hole because at his last stay
there he had considerable problems in explaining this item of the Party Political Program that promises state guarantees for loans taken by any unemployed
who wishes - for a planned future business activity - to buy a new SUV of the
well-known make Luxus.
6)Mr Blather may be dispatched to Lower Hole, but not on Monday, because
Mondays are traditional extensions of his customary weekends.
193
7)Ms Fable should not be dispatched to Middle Hole, because last time there
she refused to support the request of the Middle Hole Party Chairman to be
distinguished by the widely aspired Pour le Fraude golden medal that she
herself has not got yet.
Is it possible to nd a dispatch solution that gives justice to all the presented
wishes and hindrances?
This problem is solved by program 4_15_delegations.ecl16:
/*1*/
/*2*/
/*3*/
:-lib(ic).
top:Towns=[Destination_of_Blather, Destination_of_Jabber,
Destination_of_Fable],
/*4*/
Towns::1..3,
% Visited towns:
1 - Lower Hole, 2 - Upper Hole, 3 - Middle Hole.
% If e.g Destination_of_Blather=3, then Blather is dispatched to Middle Hole.
/*5*/
alldifferent(Towns),
/*6*/
/*7*/
% Visited
% If e.g.
/*8*/
% 1) Mr
/*9*/
Days=[Monday,Tuesday,_],
Days::1..3,
Towns: 1 - Lower Hole, 2 - Upper Hole, 3 - Middle Hole.
Tuesday=3, then on Tuesday someone is dispatched to Middle Hole.
alldifferent(Days),
Blather is not going to Lower Hole:
Destination_of_Blather #\= 1,
is an FS-type problem.
194
constraint_2(Destination_of_Jabber,Tuesday):Destination_of_Jabber #= 1,
/*35*/
/*36*/
/*37*/
/*38*/
195
Tuesday #\= 1;
Destination_of_Jabber #= 2,
Tuesday #\= 2.
constraint_2(_,_).
/*39*/
/*40*/
/*41*/
/*42*/
constraint_3(Destination_of_Jabber,Monday):Destination_of_Jabber #= 2,
Monday #\= 2.
constraint_3(_,_).
/*43*/
/*44*/
/*45*/
/*46*/
constraint_6(Destination_of_Blather,Monday):Destination_of_Blather #= 3,
Monday #\= 3.
constraint_6(_,_).
day(1," on Monday.").
day(2," on Tuesday.").
/*52*/
day(3," on Wednesday.").
4.6
Data handling
The solution of complicated and large problems may require some additional
knowledge about data structures and their handling.
196
4.6.1
Structures, abbreviated by struct, are handy for presenting and processing data
from nested relational data bases. Their use is declared by local struct()
templates, like e.g.:
:- local struct(person(name, address, age)).
:- local struct(employee(p:person, salary)).
where the structure person is nested in structure employee using eld p. The
following example illustrates the use of the structures. It is given by commands
in command mode, see Section 0.3, for which a response is generated:
This is a command:
[eclipse 1]:
:- local struct(person(name, address, age)).
:- local struct(employee(p:person, salary)).
Employee = employee with [name: "Jan Kowalski"", age: 26,
salary: 4000, address: "Gliwice, Kormoranow 5"],
arg(name of employee, Employee, Name),
arg(age of employee, Employee, Age),
arg(salary of employee, Employee, Salary).
197
4)The built-in dim/2 may also serve to determine the elements of an array:
This is a command:
[eclipse 5]: Array = [](a, b, c, d), dim(Array,D).
5)A 1-dimensional array may have lists as its elements. The number of elements
of such array is equal to the number of lists, e.g.:
This is a command:
[eclipse 6]: Array=[]([5 ,7 ,1 ,20 ],[14 ,8 ,100,300],
[2 ,20 ,50 ,12 ] ),
dim(Array,[M]).
198
The length/2 built-in may also be used for list construction, e.g.:
This is a command:
[eclipse 8]: length(List, 4).
199
4.6.2
:- lib(ic).
array_matrix(ArrayMatrix):ArrayMatrix=[](
[](1,2,3,4,5),
[](6,7,8,9,10),
[](11,12,13,14,15)
).
/*8*/
top:-
/*9*/
array_matrix(ArrayMatrix),
/*10*/
/*11*/
arg(2,ArrayMatrix,ArrayMatrixRow),
writeln("ArrayMatrixRow":ArrayMatrixRow),
/*12*/
ArrayMatrixRow=..[[]|ListMatrixRow],
/*13*/
/*14*/
writeln("ListMatrixRow":ListMatrixRow),
element(3,ListMatrixRow,Element_2_3),
/*15*/
writeln("Element_2_3":Element_2_3).
While being interested only in a specic element of the matrix, a simpler approach is recommended: the element is available by calling the predicate
17 This
is an FS-type problem.
200
4.6.3
For ECLi P S e P rolog - as for any other Prolog - data is processed chiey using
recursions. Prolog people just love recursions. E.g. consecutive elements of a
list may be obtained by the simple private predicate write_list/1 dened by
the recursion from program 4_17_write_list.ecl18:
/*1*/
/*2*/
top :-
/*3*/
/*4*/
write_list([X|Xs]):writeln(X),
/*5*/
/*6*/
write_list(Xs).
write_list([]).
write_list([1,2,3]).
is an FS-type problem.
201
same predicate, in a loop, for changing data. Such iterations are not used in
Prolog programs; their presence in ECLi P S e CP S seems to be a concession
to programmers accustomed to procedural programming. As a result some of
Prolog programs declarativity as well as readability has been lost.
The basic iterative built-in is do/2 used as:
+iteration_definition(X) do +goal(X)
for calling goal(X) according to iteration_definition(X).
Following iteration_definitions may be used:
1) foreach(X,List) do goal(X) is iterating goal(X) for all X from the list
List. X is a local variable for goal(X). E.g.:
This is a command:
[eclipse 1]: (foreach(X, [1,2,3]) do writeln(X)).
The response is the same as that obtained by the private write_list/1 predicate. However, foreach(X,List) may also be used for constructing lists:
This is a command:
[eclipse 2]: (foreach(X, [1,2,3]), foreach(Y,List) do Y is X+5).
The possibility to construct data structures is common to the majority of iteration denitions. It lessens somehow the burden of procedurality from those
denitions. It has been used in program 4_18_scalar_product.ecl (see 4.6.5),
202
calculating the scalar products of two vectors presented as lists. This scalar
product has been in turn used in the 5_14_knapsack_1.ecl program, see 5.6.3.
2) foreacharg(X,Predicate) do goal(X) is iterating goal(X) for all X given
by arguments (free or grounded) of the predicate Predicate. E.g.:
This is a command:
[eclipse 3]: (foreacharg(X, s(p,q,R,5)) do writeln(X)).
The built-in foreacharg(X,Predicate) cannot be used for constructing predicates because of the ambiguity of this concept.
3) foreacharg(X,Predicate,I) do goal(X) is iterating goal(X) for all X given
by arguments (free or grounded) of the predicate Predicate, while delivering
the numbers I of positions X in the predicate. E.g.:
This is a command:
[eclipse 3]: (foreacharg(X, s(p,q,R,5),I) do writeln(X),writeln(I)).
203
1
1
2
3
2
2
1
2
3
3
1
2
List = [1, 2, 3]
X = X
Y = Y
204
7) for(I,MinExpr,MaxExpr,Delta)do goal(I) is iterating goal(I) for integer variables I from the range [MinExpr...MaxExpr] incremented with Delta.
I is (obviously) a local variable for goal(I), and MinExpr as well as MaxExpr
may be arithmetic expressions. This construct may be used only for controlling
iterations, i.e. MaxExpr must be grounded. This is illustrated by constructing
a list of integers:
This is a command:
[eclipse 7]: (for(I,1,5,2), foreach(I,List) do true).
This is the response:
I = I
List = [1, 3, 5]
205
206
J = J
K = K
10) fromto(First,In,Out,Last)do goal(In,Out) is the most general iterator. It iterates goal(In,Out) by starting with In = First, thus computing a
rst value for Out. This value is swapped at the second iteration for In, and so
on: at each iteration the value of OUT computed from previous In is swapped
for the next In, until Out = Last and the iteration stops. In and Out are local
variables for goal. The fromto/4 performance is illustrated by computing the
sum of a list of integers:
This is a command:
[eclipse 10]: (foreach(X,[10,20,30]),
fromto(0,In,Out,Sum) do Out is InX).+
This is the response:
X = X
In = In
Out = Out
Sum = 60
207
The 4_21_queens_for_the_last_time.ecl program (see Section 4.7.2) illustrates another situation, for which First is not grounded till the end of iterations.
4.6.4
Iterations allow to express the queens placement problem from Section 4.4.6 in
a more compact way, as shown in program 4_19_queens_one_more_time.ecl19:
/*1*/
/*2*/
/*3*/
:- lib(ic).
top:queens(_,_).
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
(for(I,1,N), param(Chessboard,N) do
(for(J,I+1,N), param(Chessboard,I) do
Chessboard[I] #\= Chessboard[J],
Chessboard[I] #\= Chessboard[J]+J-I,
Chessboard[I] #\= Chessboard[J]+I-J
)
),
/*16*/
/*17*/
labeling(Chessboard),
writeln(Chessboard).
/*18*/
size_of_chessboard(4).
is an FS-type problem.
208
4.6.5
Scalar product
The scalar product (or dot product) of two vectors presented as lists:
[a1,a2,...,an]
[b1,b2,...,bn]
is given by:
a1*b1 + a2*b2 + ... an*bn.
This can be computed by program 4_18_scalar_product.ecl20:
/*1*/
/*2*/
/*3*/
:- lib(ic).
top:scalar_product([1,2,3,4],[10,20,30,40],_).
/*4*/
scalar_product(List_1,List_2,Scalar_product):-
/*5*/
(foreach(V1, List_1),
/*6*/
/*7*/
foreach(V2, List_2),
foreach(Product,Product_list)
/*8*/
do
/*9*/
/*10*/
Product is V1 * V2
),
/*11*/
/*12*/
Scalar_product #= sum(Product_list),nl,
write("Scalar product = "),writeln(Scalar_product),nl.
4.7
4.7.1
is an FS-type problem.
209
boxes) contains all of the digits from 1 to 9. Initially the table is partially
completed in a way that assures a unique solution.
The program 4_20_sudoku.ecl21 is solving sudoku puzzles using the builtin multifor/3. It is a slightly modied version of the program available at the
website [Schimpf-10]:
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
:- lib(ic).
top:write("Declare puzzle number (1,2 or 3):"),nl,
read_token(Number, integer),
solve(Number).
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
solve(Number):problem(Number, Board),
write_board(Board),
sudoku(Board),
write_board(Board).
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
sudoku(Board):Board[1..9,1..9] :: 1..9,
(for(I,1,9), param(Board)
do
Row is Board[I,1..9],
alldifferent(Row),
Col is Board[1..9,I],
alldifferent(Col)
),
(multifor([I,J],1,9,3), param(Board)
do
(multifor([K,L],0,2),
param(Board,I,J),
foreach(X,Square)
do
X is Board[I+K,J+L]
),
alldifferent(Square)
),
term_variables(Board, Variables),
labeling(Variables).
/*31*/
/*32*/
/*33*/
/*34*/
/*34*/
write_board(Board):(for(I,1,9), param(Board)
do
(for(J,1,9), param(Board,I)
do
21 This
is an FS-type problem.
210
/*35*/
/*36*/
/*37*/
/*38*/
X is Board[I,J],
(var(X) -> write("
), nl
), nl.
problem(1, [](
[](_, _, 2, _,
[](_, _, _, 5,
[](_, 6, _, _,
[](_, _, _, _,
[](_, 9, 7, _,
[](4, 1, _, 7,
[](_, _, _, 8,
[](_, 2, _, _,
[](6, _, _, _,
6,
9,
_,
_,
_,
_,
_,
7,
4,
_,
_,
4,
1,
_,
_,
_,
5,
_,
_,
_,
_,
_,
8,
_,
_,
_,
3,
_,
7,
_,
3,
1,
_,
9,
_,
_,
3),
_),
_),
7),
_),
_),
_),
_),
_))).
problem(2, [](
[](_, _, 5, _,
[](9, _, _, _,
[](_, _, 1, _,
[](_, _, _, 9,
[](_, _, _, _,
[](4, _, _, _,
[](8, 6, _, _,
[](_, _, _, 1,
[](_, 2, _, 8,
7,
_,
_,
_,
_,
_,
_,
_,
6,
4,
3,
_,
_,
_,
6,
_,
_,
_,
_,
_,
_,
_,
_,
_,
7,
_,
5,
6,
_,
3,
_,
_,
_,
_,
_,
_,
_),
_),
2),
5),
_),
_),
_),
8),
_))).
problem(3, [](
[](_, _, _, _, _, 1, 2, _, _),
[](_, _, _, _, _, _, 9, 6, _),
[](_, _, _, 7, 4, 6, _, _, 8),
[](_, 9, 3, _, 2, _, _, 1, _),
[](_, 8, _, _, _, _, _, 9, _),
[](_, 6, _, _, 5, _, 8, 2, _),
[](1, _, _, 5, 6, 7, _, _, _),
[](_, 3, 4, _, _, _, _, _, _),
[](_, _, 6, 3, _, _, _, _, _))).
_
_
_
9
8
_
_
_
3
_
_
_
7
_
_
_
_
4
2
_
1
_
6
_
_
2
9
_
_
_
_
6
_
1
9
_
_
8
_
_
_
1
_
_
6
_
3
_
_
_
4
6
_
5
_
3
5
6
_
_
_
7
_
_
8
_
_
_
2
_
_
_
_
_
_
_
3
9
4
1
7
2
2
7
8
4
5
6
9
5
6
3
1
8
2
7
8
6
5
1
1
4
7
5
3
9
4
8
9
2
6
3
1
5
2
3
9
4
5
8
6
1
7
2
3
6
8
7
4
9
4.7.2
211
The program 4_21_queens_for_the_last_time.ecl22 illustrates the application of fromto/4 to the queen placement problem:
/*1*/
/*2*/
/*3*/
:- lib(ic).
top:four_queens(4,_).
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
22 This
(fromto(Chessboard,[Position_1|Next_positions],
Next_positions,[])
do
(foreach(Position_2, Next_positions),
param(Position_1),
count(Distance,1,_)
do
Position_2 #\= Position_1,
Position_2 - Position_1 #\= Distance,
Position_1 - Position_2 #\= Distance
)
),
is an FS-type problem.
212
/*18*/
labeling(Chessboard),
/*19*/
write("Chessboard = "),writeln(Chessboard).
4.7.3
Consider again the lecture example from Section 2.4.10. It may be solved by an
CLP program 4_22_lectures.ecl with implicit domain declaration:
/*1*/
/*2*/
/*3*/
:- lib(ic).
top :Lectures =
[
lecture(1, _, _, _, _, _, _),
lecture(2, _, _, _, _, _, _),
lecture(3, _, _, _, _, _, _)
],
Constraints =
[
lecture(Andrew, "Andrew", _, _, _, _, _),
lecture(Barbara, "Barbara",_,_, _, _, _),
lecture(Christopher, "Christopher",_, _, _, _, _),
213
214
grounding(Constraints, Lectures),
(foreach(Lecture, Lectures) do writeln(Lecture)),!.
/*16*/
/*17*/
/*18*/
/*19*/
grounding([],_).
grounding([H|T],Lectures) :member(H,Lectures),
grounding(T,Lectures).
4.7.4
Stable marriages
215
As can be seen, the marriage (m-p, w-a) is unstable because m-p prefers w-b
more than his wife w-a, and w-b prefers m-p more than her husband m-q.
A set of marriages is stable if it does not contain unstable pairs.
Let us consider the following example with three women (woman_1, woman_2
and woman_3) and three men (man_1, man_2
216
Women
woman_1
woman_2
woman_3
High
woman_2
woman_3
woman_1
pref...Low
woman_1
woman_2
woman_3
pref
woman_3
woman_1
woman_2
217
% rankByWomen:
% women are ranking men: woman_1 likes
% most man_2, next-man_1, and least-man_3
[]([](2, 1, 3),
[](3, 2, 1),
[](1, 3, 2))).
% rankByMen:
% men are ranking women: man_1 likes most
% woman_2, next-woman_1, and least-woman_3
:-lib(ic).
:-lib(ic_global).
:-lib(ic_search).
:-lib(propia).
top :all_solutions(0),
all_solutions(1),
all_solutions(2),
all_solutions(3),
all_solutions(4),
all_solutions(5).
(foreach([H,W], L) do
write("Husband: "),write(H),nl,
218
/*17*/
/*18*/
write("Wife
).
: "),write(W),nl,nl
dim(RankByWomen,[NumWomen,NumMen]),
dim(RankByMen,[NumMen,NumWomen]),
/*23*/
/*24*/
dim(Wife,[NumMen]),
Wife #:: 1..NumWomen,
/*25*/
/*26*/
dim(Husband,[NumWomen]),
Husband #:: 1..NumMen,
/*27*/
/*28*/
ic_global:alldifferent(Wife),
ic_global:alldifferent(Husband),
% Rankings are tested on all possible pairings for men and for women:
% if the fact that any man M who ranks an outsider woman O higher
% than his wife implies that the outsider woman O prefers her husband to M:
/*29*/
( for(M,1,NumMen) * for(O,1,NumWomen),
/*30*/
param(RankByMen,RankByWomen,Wife,Husband) do
/*31*/
(RankByMen[M,O] #< RankByMen[M, Wife[M]]) =>
/*32*/
(RankByWomen[O,Husband[O]] #< RankByWomen[O,M])
/*33*/
),
% and if the fact that any woman W who ranks an outsider male O higher
% than her husband implies that the outsider male O prefers his wife to W:
/*34*/
( for(W,1,NumWomen) * for(O,1,NumMen),
/*35*/
param(RankByMen,RankByWomen,Wife,Husband) do
/*36*/
(RankByWomen[W,O] #< RankByWomen[W,Husband[W]]) =>
/*37*/
(RankByMen[O,Wife[O]] #< RankByMen[O,W])
/*38*/
),
% then the marriages are stable.
% Husbands are paired with wifes for the same lists positions:
/*39*/
( for(W,1,NumWomen), param(Husband, Wife) do
/*40*/
Wife[Husband[W]] #= W
/*41*/
),
% Wifes are paired with husbands for the same lists positions:
/*42*/
( for(M,1,NumMen), param(Husband, Wife) do
/*43*/
Husband[Wife[M]] #= M
/*44*/
),
% flatten the list of lists [Wife,Husband] for labeling purposes:
/*45*/
term_variables([Wife,Husband],Vars),
/*46*/
problem(0,
[]([](1, 2),
[](1, 2)),
[]([](2, 1),
[](2, 1))).
labeling(Vars).
% rankByWomen
% rankByMen
From [Wikipedia-13]:
problem(1,
[]([](2, 1, 3),% rankByWomen
[](3, 2, 1),
[](1, 3, 2)),
[]([](2, 1, 3), %
[](3, 2, 1),
[](1, 3, 2))).
rankByMen
219
220
[](6,
[](2,
[](9,
[](6,
[](8,
9,
4,
3,
3,
2,
2,
5,
8,
2,
6,
5,
1,
2,
1,
4,
1,
6,
7,
8,
9,
4,
8,
5,
4,
1,
7,
3,
4,
5,
3,
From [Hunt-13]:
problem(4,
[]([](1,2,3,4),% rankWomen
[](4,3,2,1),
[](1,2,3,4),
[](3,4,1,2)),
[]([](1,2,3,4),% rankByMen
[](2,1,3,4),
[](1,4,3,2),
[](4,3,1,2))).
From [Ahriz-13]:
problem(5,
[]([](1,5,4,6,2,3),
[](4,1,5,2,6,3),
[](6,4,2,1,5,3),
[](1,5,2,4,3,6),
[](4,2,1,5,6,3),
[](2,6,3,5,1,4)),
[]([](1,4,2,5,6,3),
[](3,4,6,1,5,2),
[](1,6,4,2,3,5),
[](6,5,3,4,2,1),
[](3,1,2,4,5,6),
[](2,3,1,6,5,4))).
The
solutions are:
Problem 0:
Husband: [](2, 1)
Wife
: [](2, 1)
Problem 1:
Husband: [](2, 3, 1)
Wife
: [](3, 1, 2)
Husband: [](3, 1, 2)
Wife
: [](2, 3, 1)
3,
9,
6,
9,
7,
8),
7),
1),
7),
5))).
Husband: [](1, 2, 3)
Wife
: [](1, 2, 3)
Problem 2:
Husband: [](4, 1, 2, 5, 3)
Wife
: [](2, 3, 5, 1, 4)
Husband: [](2, 1, 4, 5, 3)
Wife
: [](2, 1, 5, 3, 4)
Husband: [](2, 3, 4, 1, 5)
Wife
: [](4, 1, 2, 3, 5)
Problem 3:
Husband: [](7, 5, 9, 8, 3, 6, 1, 4, 2)
Wife
: [](7, 9, 5, 8, 2, 6, 1, 4, 3)
Husband: [](6, 5, 9, 8, 3, 7, 1, 4, 2)
Wife
: [](7, 9, 5, 8, 2, 1, 6, 4, 3)
Husband: [](6, 4, 9, 8, 3, 7, 1, 5, 2)
Wife
: [](7, 9, 5, 2, 8, 1, 6, 4, 3)
Husband: [](6, 1, 4, 8, 5, 9, 3, 2, 7)
Wife
: [](2, 8, 7, 3, 5, 1, 9, 4, 6)
Husband: [](6, 4, 1, 8, 5, 7, 3, 2, 9)
Wife
: [](3, 8, 7, 2, 5, 1, 6, 4, 9)
Husband: [](6, 1, 4, 8, 5, 7, 3, 2, 9)
Wife
: [](2, 8, 7, 3, 5, 1, 6, 4, 9)
Problem 4:
Husband: [](1, 4, 2, 3)
Wife
: [](1, 3, 4, 2)
Husband: [](1, 2, 4, 3)
Wife
: [](1, 2, 4, 3)
Problem 5:
Husband: [](1, 2, 6, 3, 5, 4)
Wife
: [](1, 2, 4, 6, 5, 3)
Husband: [](1, 2, 6, 3, 4, 5)
Wife
: [](1, 2, 4, 5, 6, 3)
Husband: [](1, 2, 4, 3, 6, 5)
Wife
: [](1, 2, 4, 3, 6, 5)
221
222
4.8
Feasible sequencing
Feasible sequencing aims at determining the order of elements from some set so
as to fulll neighbourhood constraints, i.e. constraints determining the position
of each element with respect to the elements.
4.8.1
223
station moves with the car while performing their jobs. The speed of the assembly line is such as to allow the crews to nish their jobs while the car bodies are
in their stations. E.g. if the installation of power seats takes 16 minutes and
a new car body enters the assembly line every 4 minutes, then (assuming that
each car needs a power seats), the station for power seats installation needs a
capacity to handle 16/4 = 4 car bodies, i.e. it has to be staed by 4 power seats
handling crews. However, because not each car requires a power seat, in order
to save instrumentation and labour, the capacity of the power seats station may
be smaller, e.g. the station may have only 3 crews to handle power seats. That
means the station can cope with no more than 3 cars requiring power seats out
of any sequence of 4 cars. In shorthand - the power seats station has a capacity
constraint 3/4. Now its up to the assembly line scheduler to assure that the
entire sequence of car bodies feed into the assembly line has no 4-bodies subsequences with more than 3 bodies requiring power seats. Consider the capacity
requirements for four car models to be produced with ve options as shown in
Table 4.6:
Option
Capacity
constraints
Sunroof
3/5
CD changer
4/5
Automatic transmission
4/5
Power seats
3/4
Parking assistant
1/2
Number of cars required
Models produced
1
2
3
4
30 30 30 30
Table 4.6: Capacity constraints for car assembly line: x - option required, - option not required
The notion of capacity constraint is illustrated for the case of power seat
workstation in Figure 4.5.
A solution (one of a large multitude of possible solutions) for the sequence
of 120 car bodies feed into the assembly line so that the capacity constraints of all
work stations are satised is determined by program 4_24_car_assembling.ecl
using two powerful global constraints: occurrences/3 and sequence_total/7:
/*1*/
/*2*/
:- lib(ic).
:- lib(ic_global).
224
/*3*/ top:/*4*/
length(L,120),
/*5*/
L::1..4,
%
1 - Model 1, 2 - Model 2,
3 - Model 3, 4 - Model 4
/*6*/
/*7*/
/*8*/
/*9*/
225
%
CD changer - at least none and at most 4 of any consecutive 5 integers in L
%
are from list [1,3,4]; at least 90 and at most 90 integers in L are
%
from list [1,3,4]:
/*11*/
sequence_total(90, 90, 0, 4, 5, L, [1,3,4]),
%
Automatic transmission - at least none and at most 4 of any consecutive
% 5 integers in L are from list [1,2,4]; at least 90 and at most 90 integers
% in L are from list [1,2,4]:
/*12*/
sequence_total(90, 90,0, 4, 5, L, [1,2,4]),
%
Power seats - at least none and at most 3 of any consecutive 4 integers
% in L are from list [1,2,3]; at least 90 and at most 90 integers in L are
%
from list [1,2,3]:
/*13*/
sequence_total( 90, 90, 0, 3,4, L, [1,2,3]),
%
Parking assistant - at least none and at most 1 of any consecutive 2 integers
% in L are from list [1,3]; at least 60 and at most 60 integers in L are from
% list [1,3]:
/*14*/
sequence_total( 60, 60, 0, 1, 2, L, [1,3]),
/*15*/
/*16*/
labeling(L),
write_list(L).
/*17*/ write_list([H|T]):/*18*/
write(H),write(", "),
/*19*/
/*20*/
write_list(T).
write_list([_]).
To check that it satises the power seats capacity constraint, one has to look
at every subsequence of 4 cars, i.e.:
1, 2, 1, 4, Its O.K
2, 1, 4, 3, Its O.K
1, 4, 3, 2, Its O.K
and so on, for each capacity constraint. Quite a job! So its worthwhile to
226
present the solution as the sequencing diagrams from Figure 4.6, where capacity
constraints correspond to colour patterns.
4.8.2
227
mushrooms, onions, peppers, and tomatoes that were put onto skewers. The
skewer that each person made had three beef cubes and one piece of three kinds
of vegetables each person disliked a dierent vegetable and omitted it from
his or her skewer. The six pieces can be numbered 1 to 6 from the handle to the
point of the skewer. Can you tell what item each person had in each position,
provided that:
1. No kebab had two beef cubes right next to each other.
2. No ones beef cubes were in the same three positions as anyone elses.
3. One shish kebabs rst three items (numbers 1, 2, and 3 respectively) were
beef, pepper, and mushroom; this wasnt Javiers.
4. One skewer had beef cubes in positions 1, 3, and 5, and a tomato wedge in
position 6.
5. Bob, who loves onions and included a chunk on his skewer, had other vegetables in both positions 4 and 5.
6. On the four kebabs, the items in position 5 were beef, mushroom, onion, and
tomato.
7. Each onion chunk was immediately between two beef cubes.
8. No pepper was immediately between two beef cubes.
9. Marie cant stand mushroom and left them o her skewer.
10. At least two kebabs had the same vegetable in the same position at least
once.
It contains a lot of negative conditions (i.e. conditions stating that something is not true) that may cause diculties. A systematic way to handle them
(its essence is to use predicates dening negated conditions) is presented by
program 4_25_kebab.ecl23:
/*1*/ :- lib(ic).
/*2*/ :-lib(ic_global).
/*3*/ top:%
%
%
%
%
Bi- element
Pi- item on
Ji- element
Mi- element
1-mushroom,
/*4*/
/*5*/
23 This
Bob=[B1,B2,B3,B4,B5,B6,B7],
Bob::1..5,
is an FS-type problem.
228
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
%
Patty=[P1,P2,P3,P4,P5,P6,P7],
Patty::1..5,
Javier=[J1,J2,J3,J4,J5,J6,J7],
Javier::1..5,
Marie=[M1,M2,M3,M4,M5,M6,M7],
Marie::1..5,
Example: J3 = 5 means Javier had beef at the third position.
%
Positions 7 on each skewers denote vegetables disliked
%
by the corresponding person: each person disliked a
%
different vegetable and omitted it from his or her skewer:
/*12*/
[B7,P7,J7,M7]::1..4,
/*13*/
ic_global: alldifferent([B7,P7,J7,M7]),
%
Constraint 1 - No kebab had two beef cubes right next to each other:
/*14*/
constraint_1([Bob,Patty,Javier,Marie]),
%
Constraint 2 - No ones beef cubes were in the same three positions
%
as anyone elses:
/*15*/
constraint_2([Bob,Patty,Javier,Marie]),
%
Constraint 3 - One shish kebabs first three items (numbers 1, 2,
%
and 3 respectively) were beef, pepper, and mushroom; this wasnt Javiers.
/*16*/
constraint_3(Bob,Patty,Marie),
%
Constraint 4 - One skewer had beef cubes in positions 1, 3, and 5, and
%
a tomato wedge in position 6.
/*17*/
constraint_4(Bob,Patty,Javier,Marie),
%
Constraint 5 - Bob, who loves onions and included a chunk
%
on his skewer,had other vegetables in both positions 4 and 5:
/*18*/
constraint_5([_,_,_,B4,B5,_,_]),
%
Constraint 6 - On the four kebabs, the items in position 5 were beef,
%
mushroom, onion, and tomato:
/*19*/
constraint_6(Bob,Patty,Javier,Marie),
%
Constraint 7 - Each onion chunk was immediately between two beef cubes
/*20*/
constraint_7([Bob,Patty,Javier,Marie]),
%
Constraint 8 - No pepper was immediately between two beef cubes:
/*21*/
constraint_8([Bob,Patty,Javier,Marie]),
%
Constraint 9 - Marie cant stand mushroom and left them off her skewer:
/*22*/
constraint_9(Marie),
%
%
/*23*/
%
/*24*/
/*25*/
/*26*/
/*27*/
229
constraint_10([Bob,Patty,Javier,Marie]),
Each skewer has 3 beef cubes:
occurrences(5, [B1,B2,B3,B4,B5,B6],
occurrences(5, [P1,P2,P3,P4,P5,P6],
occurrences(5, [J1,J2,J3,J4,J5,J6],
occurrences(5, [M1,M2,M3,M4,M5,M6],
3),
3),
3),
3),
%
Each skewer has one piece of three kinds of vegetables,
%
the fourth vegetable rejected:
/*28*/
occurrences(1, [B1,B2,B3,B4,B5,B6,B7], 1),
/*29*/
occurrences(1, [P1,P2,P3,P4,P5,P6,P7], 1),
/*30*/
occurrences(1, [J1,J2,J3,J4,J5,J6,J7], 1),
/*31*/
occurrences(1, [M1,M2,M3,M4,M5,M6,M7], 1),
/*32*/
/*33*/
/*34*/
/*35*/
occurrences(2,
occurrences(2,
occurrences(2,
occurrences(2,
[B1,B2,B3,B4,B5,B6,B7],
[P1,P2,P3,P4,P5,P6,P7],
[J1,J2,J3,J4,J5,J6,J7],
[M1,M2,M3,M4,M5,M6,M7],
1),
1),
1),
1),
/*36*/
/*37*/
/*38*/
/*39*/
occurrences(3,
occurrences(3,
occurrences(3,
occurrences(3,
[B1,B2,B3,B4,B5,B6,B7],
[P1,P2,P3,P4,P5,P6,P7],
[J1,J2,J3,J4,J5,J6,J7],
[M1,M2,M3,M4,M5,M6,M7],
1),
1),
1),
1),
/*40*/
/*41*/
/*42*/
/*43*/
occurrences(4,
occurrences(4,
occurrences(4,
occurrences(4,
[B1,B2,B3,B4,B5,B6,B7],
[P1,P2,P3,P4,P5,P6,P7],
[J1,J2,J3,J4,J5,J6,J7],
[M1,M2,M3,M4,M5,M6,M7],
1),
1),
1),
1),
/*44*/
labeling([B1,B2,B3,B4,B5,B6,B7,P1,P2,P3,P4,P5,P6,P7,
J1,J2,J3,J4,J5,J6,J7,M1,M2,M3,M4,M5,M6,M7]),
/*45*/
write("Bobs skewer:
"),translate(B1),write(" "),translate(B2),
write(" "), translate(B3),write(" "), translate(B4),
write(" "),translate(B5),write(" "), translate(B6),nl,
/*46*/
/*47*/
/*48*/
230
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
translate(1):-write("mushroom").
translate(2):-write("pepper ").
translate(3):-write("onion
").
translate(4):-write("tomato ").
translate(5):-write("beef
").
%
Constraint 1 - No kebab had two beef cubes right next to each other:24
/*54*/ constraint_1([H|T]):/*55*/
check_1(H),
/*56*/
constraint_1(T).
/*57*/ constraint_1([]).
/*58*/
/*59*/
/*60*/
/*61*/
/*62*/
/*63*/
check_1([A,B,C,D,E,F,_]):~two_beef_cubes_next_to_each_other(A,B),
~two_beef_cubes_next_to_each_other(B,C),
~two_beef_cubes_next_to_each_other(C,D),
~two_beef_cubes_next_to_each_other(D,E),
~two_beef_cubes_next_to_each_other(E,F).
/*64*/
/*65*/
two_beef_cubes_next_to_each_other(X,Y):X#=5,Y#=5.
%
Constraint 2 - No ones beef cubes were in the same three positions
%
as anyone elses:
/*66*/ constraint_2([Bob,Patty,Javier,Marie]):/*67*/
check_2(Bob,Patty),check_2(Bob,Javier),check_2(Bob,Marie),
/*68*/
check_2(Patty,Javier),check_2(Patty,Marie),check_2(Javier,Marie).
/*69*/
/*70*/
/*71*/
/*72*/
/*73*/
check_2([B1,B2,B3,B4,B5,B6,_],[P1,P2,P3,P4,P5,P6,_]):~in_the_same_positions(B1,B3,B5,P1,P3,P5),
~in_the_same_positions(B1,B3,B6,P1,P3,P6),
~in_the_same_positions(B1,B4,B6,P1,P4,P6),
~in_the_same_positions(B2,B4,B6,P2,P4,P6).
/*74*/
/*75*/
/*76*/
/*77*/
/*78*/
/*79*/
/*80*/
in_the_same_positions(X1,X2,X3,Y1,Y2,Y3):X1#=5,
X2#=5,
X3#=5,
Y1#=X1,
Y2#=X2,
Y3#=X3.
%
Constraint 3 - One shish kebabs first three items (numbers 1, 2,
%
and 3 respectively) were beef, pepper, and mushroom; this wasnt Javiers:
/*81*/ constraint_3([B1,B2,B3,_,_,_,_],[P1,P2,P3,_,_,_,_],[M1,M2,M3,_,_,_,_]):/*82*/
(
24 The Reader will excuse the Author for repeating the constraint statements, but this nonredundancy makes for easier grasping the programs essence.
/*83*/
/*84*/
/*85*/
/*86*/
231
%
Constraint 4 - One skewer had beef cubes in positions
%
1, 3, and 5, and a tomato wedge in position 6.
/*87*/ constraint_4(Bob,Patty,Javier,Marie):/*88*/
(had_beef_cubes_in_positions_1_3_5_6(Bob);
/*89*/
had_beef_cubes_in_positions_1_3_5_6(Patty);
/*90*/
had_beef_cubes_in_positions_1_3_5_6(Javier);
/*91*/
had_beef_cubes_in_positions_1_3_5_6(Marie)).
/*92*/
/*93*/
%
Constraint 5 - Bob, who loves onions and included a chunk
%
on his skewer, had other vegetables in both positions 4 and 5:
/*94*/ constraint_5([_,_,_,B4,B5,_,_]):/*95*/
B4#\=5, B5#\=5, B4#\=B5, B4#\=3, B5#\=3.
%
Constraint 6 - On the four kebabs, the items in position 5 were
%
beef, mushroom, onion, and tomato:
/*96*/ constraint_6([_,_,_,_,B5,_,_],[_,_,_,_,P5,_,_],[_,_,_,_,J5,_,_],
[_,_,_,_,M5,_,_]):/*97*/
(
/*98*/
(B5#=5; P5#=5; J5#=5; M5#=5),
/*99*/
(B5#=1; P5#=1; J5#=1; M5#=1),
/*100*/
(B5#=3; P5#=3; J5#=3; M5#=3),
/*101*/
(B5#=4; P5#=4; J5#=4; M5#=4)
/*102*/
).
%
Constraint 7 - Each onion chunk was immediately between two beef cubes:
/*103*/ constraint_7([Bob,Patty,Javier,Marie]):/*104*/
check_7(Bob),check_7(Patty),
/*105*/
check_7(Javier),check_7(Marie).
/*106*/
/*107*/
/*108*/
/*109*/
/*110*/
/*111*/
/*112*/
/*113*/
/*114*/
/*115*/
%
check_7([A,B,C,_,_,_,_]):A#=5,B#=3,C#=5.
check_7([_,B,C,D,_,_,_]):B#=5,C#=3,D#=5.
check_7([_,_,C,D,E,_,_]):C#=5,D#=3,E#=5.
check_7([_,_,_,D,E,F,_]):D#=5,E#=3,F#=5.
check_7([_,_,_,_,_,_,G]):G#=3.
Constraint 8 - No pepper was immediately between two beef cubes:
232
/*116*/ constraint_8([Bob,Patty,Javier,Marie]):/*117*/
check_8(Bob),check_8(Patty),
/*118*/
check_8(Javier),check_8(Marie).
/*119*/ check_8([A,B,C,D,E,F,_]):/*120*/
~pepper_was_between_two_beef_cubes(A,B,C),
/*121*/
~pepper_was_between_two_beef_cubes(B,C,D),
/*122*/
~pepper_was_between_two_beef_cubes(C,D,E),
/*123*/
~pepper_was_between_two_beef_cubes(D,E,F).
/*124*/ pepper_was_between_two_beef_cubes(X,Y,Z):/*125*/
X#=5,Y#=2,Z#=5.
%
Constraint 9 - Marie cant stand mushroom and left them off her skewer:
/*126*/ constraint_9([M1,M2,M3,M4,M5,M6,M7]):/*127*/
M7#=1,
/*128*/
M1#\=1, M2#\=1, M3#\=1,
/*129*/
M4#\=1, M5#\=1, M6#\=1.
%
Constraint 10 - At least two kebabs had the same
%
vegetable in the same position at least once:
/*130*/ constraint_10([Bob,Patty,Javier,Marie]):/*131*/
(
/*132*/
check_10(Bob,Patty);
/*133*/
check_10(Bob,Javier);
/*134*/
check_10(Bob,Marie);
/*135*/
check_10(Patty,Javier);
/*136*/
check_10(Patty,Marie);
/*137*/
check_10(Javier,Marie)
/*138*/
).
/*139*/ check_10([X1,X2,X3,X4,X5,X6,_],[Y1,Y2,Y3,Y4,Y5,Y6,_]):/*140*/
(
/*141*/
(X1#\=5,X1#=Y1);
/*142*/
(X2#\=5,X2#=Y2);
/*143*/
(X3#\=5,X3#=Y3);
/*144*/
(X4#\=5,X4#=Y4);
/*145*/
(X5#\=5,X5#=Y5);
/*146*/
(X6#\=5,X6#=Y6)
/*147*/
).
beef
onion
beef
pepper
mushroom
beef
Pattys skewer:
Javier skewer:
beef
beef
pepper
onion
mushroom
beef
beef
mushroom
tomato
beef
beef
tomato
Maries skewer:
pepper
beef
tomato
beef
onion
beef
4.8.3
233
Dinner calamity
:- lib(ic).
top :Places = [MrsAstor, MrAstor, MrBlake, MrsBlake,
MrsCrane, MrCrane, MrsDavis, MrDavis],
/*4*/
Places :: 1..8,
% The places are numbered as shown in Figure \ref{Fig.4.11}.
% Meaning of variables: if e.g. Mr Astor = 7, then Mr Astor is sitting on place 7
% The occupant of one place may be fixed:
/*5*/
MrsAstor = 1,
% Any person is occupying only one place:
/*6*/
alldifferent(Places),
% 1) Mrs Astor was insulted by Mr Blake,
%
who sat next to her on her left:
25 This
is an FS-type problem.
234
/*7*/
MrBlake = 2,
/*21*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*22*/
/*23*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
next_to(A,B):B #= A + 1;
A #= B + 1.
/*39*/
/*40*/
next_to(8,1).
next_to(1,8).
/*41*/
/*42*/
/*43*/
/*44*/
/*45*/
in_between(A,X,B):X #= A + 1,
X #= B - 1;
X #= A - 1,
X #= B + 1.
/*46*/
/*47*/
/*48*/
/*49*/
in_between(7,8,1).
in_between(1,8,7).
in_between(8,1,2).
in_between(2,1,8).
/*50*/
/*51*/
/*52*/
opposite(A,B):B #= A + 4;
A #= B + 4.
/*53*/
get_insulter([_|T_names],[H_position|T_position],X,Insulter):-
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
235
not(X = H_position),
get_insulter(T_names,T_position,X,Insulter).
get_insulter([H_names|_],[H_position|_],X,Insulter):X = H_position,
Insulter = H_names.
236
4.9
Exercises
Stones of Heaven 26
Wan Li, a dealer in Chinese antiques and artifacts, had an excellent month
recently when he made sales to four customers from around the world
Finland, Italy, Japan and United States who were willing and able to pay
very good prices. The four items were rare jade gurines (a belt buckle,
dragon, grasshopper and horse), each carved from a dierent color of jade
(dark green, light green, red and white). Each piece dates from a dierent
Chinese dynasty (Ching, Ming, Sung and Tang). Write a program to
26 This
4.9 Exercises
237
match each gurine with its color and dynasty, and give the home country
of each buyer, if: 1. The rare white dragon (which the American didnt
buy) didnt come from the Sung dynasty. 2. The exquisite belt buckle
(which wasnt any shade of green) was created in 618 A.D. for an emperor
of the Tang dynasty. 3. Three of the gurines were: the one bought by the
Finn (which wasnt the dragon), the one from the Ching dynasty (which
didnt go to the buyer from Japan) and the light green object (which wasnt
the horse). 4. The American decided against both the grasshopper and
the piece from the Sung dynasty, neither of which she felt would match
her home decor. Determine: Item Color Dynasty Country of buyer.
Lectures 27
Last week at school was made varied by a series of lectures, one each day
(Monday through Friday), in the auditorium. None of the lectures was
particularly interesting (on choosing a college, physical hygiene, modern
art, nutrition, and study habits), but the students gured that anything
that got them out of fourth period was okay. The lecturers were two
women named Alice and Bernadette, and three men named Charles, Duane, and Eddie; last names were Felicidad, Garber, Haller, Itakura, and
Jereys. Write a program to nd each days lecturer and subject, provided: 1. Alice lectured on Monday. 2. Charless lecture on physical
hygiene wasnt given on Friday. 3. Dietician Jereys gave the lecture on
nutrition. 4. A man gave the lecture on modern art. 5. Ms. Itakura
and the lecturer on proper study habits spoke on consecutive days, in one
order or the other. 6. Haller gave a lecture sometime after Eddie did. 7.
Duane Felicidad gave his lecture sometime before the modern art lecture.
City council meeting
At the last meeting of the local city council, each member (Mr. Akerman,
Ms. Baird, Mr. Chatham, Ms. Duval, and Mr. Etting) had to vote on ve
motions, number 1 to 5 in the clues below. Write a program to determine
how each one voted on each motion, provided that:
1. Each motion got a dierent number of yes votes.
2. In all, the ve motions got three more yes votes than no votes.
3. No two council members voted the same way on all ve motions.
4. The two women disagreed in their voting more often than they agreed.
5. Mr. Chatham never made two yes votes on consecutive motions.
6. Mr. Akerman and Ms. Baird both voted in favor of motion 4.
27 This
238
4.9 Exercises
239
Write a program for the following pattern of non-zero digits to be instantiated to add up to the same sum along each row, column and diagonal.
Books
Eight married couples meet to land one another some books29 . Couples
have the same surname, employment and a car. Eight couple has a favorite
color. Furthermore we know the following facts:
(1) Danielle Black and her husband work as Shop-Assistants. (2) The book
The Death of the West was brought by a couple who drive a Fiat and
love the color red. (3) Owen and his wife Victoria like the color brown. (4)
Stan Horricks and his wife Hannah like the color white. (5) Jenny Smith
and her husband work as Warehouse Managers and they drive a Ford. (6)
Monica and her husband Alexander borrowed the book Economy in One
Lesson. (7) Mathew and his wife like the color pink and brought the book
Archipelag Gulag. (8) Irene and her husband Oto work as Accountants.
(9) The book The Fatal Conceit was borrowed by a couple driving a
Chrysler. (10) The Cermaks are both Ticket-Collectors who brought the
book The Art of Worldly Wisdom. (11) Mr and Mrs Kuril are both
Doctors who borrowed the book Atlas Shrugged. (12) Paul and his
wife like the color green. (13) Veronica Dvorak and her husband like the
color blue. (14) Rick and his wife brought the book Atlas Shrugged
and they drive a Volkswagen. (15) One couple brought the book The
Oxford Book of Humorouse Prose and borrowed the book Archipelag
Gulag. (16) The couple who drive a Toyota, love the color violet. (17)
The couple who work as Teachers borrowed the book The Oxford Book
of Humorouse Prose. (18) The couple who work as Agriculturalists drive
a Moskvic. (19) Pamela and her husband drive a Renault and brought the
book Economy in One Lesson. (20) Pamela and her husband borrowed
the book that Mr and Mrs Zajac brought. (21) Robert and his wife like the
color yellow and borrowed the book The Enlarged Devils Dictionary.
(22) Mr and Mrs Swain work as Shoppers. (23) The Enlarged Devils
Dictionary was brought by a couple driving a Audi.
Write a program to determine who likes violet and to nd out everything
about everyone from this.
Dinner 30
Last weekend, ve friends gathered for dinner at their favorite steak and
29 This
30 This
240
seafood restaurant. Each friend (two men named George and Oliver, and
three women named Colleen, Patti, and Theresa) ordered a dierent main
courses (crab, let mignon, ribs, shrimp, or sirloin steak), and a dierent
type of potatoes (baked, French-fried, lyonnaise, mashed or scalloped). To
wash down his or her meal, each friend selected a dierent beverage (ginger
ale, iced tea, lemonade, root beer, or water). From the following clues,
can you match each friend with his or her surname (two of which are Gold
and Orlando), main course, side dish, and beverage? 1) The only person
with the same rst-name and last-name initials ordered the ribs. 2) The
one surnamed Petroski and the person who had the shrimp are the person
who had the lyonnaise potatoes and the one who ordered the root beer,
in some order. 3) The one who selected the let mignon didnt have the
lemonade. 4) The one who had the scalloped potatoes (which didnt come
with the sirloin steak) didnt drink the water. 5) The rst-name initial of
the one who had root beer is the same as Georges last-name initial. 6)
Theresa didnt order the water. 7) The ones who chose the shrimp and
the baked potato are of opposite gender. 8) The rst-name initial of the
woman who ordered the crab is the same as the last-name initial of the
person who chose the mashed potatoes. 9) The rst-name initial of the
person who ordered the lemonade is the same as the last-name initial of
the one who ordered lyonnaise potatoes. 10) The one surnamed Chiasson
(who isnt Patti) didnt order French-fried or lyonnaise potatoes. 11) The
one surnames Truang (who didnt order French-fried or mashed potatoes)
didnt choose the ginger ale. 12) Colleen ordered either the let mignon
or the sirloin steak.
Write a program to determine: First name - Last name - Main course Side dish - Beverage.
Soup Selections
Each of six friends who met in cooking school is now an established chef
at a dierent, notable restaurant in the area. Every few weeks, the friends
like to get together to trade secrets of their eld and share some of their favorite creations. This past Tuesday night, each chef arrived at the groups
favorite gathering spot with a dierent kind of soup that he or she had prepared for the evenings taste-test. From the following information, write a
program to match the full name of each chef (one surname is Earle) with
his or her seat (labeled one through six in the illustration) at the table at
which the group gathered and determine the restaurant where each works
and the type of soup that he or she prepared?
4.9 Exercises
241
1. Gloria (who works for either the Apple Orchard Inn or Hennigans
Place) prepared either the French onion or split pea soup. 2. The one
who made the minestrone sat in a lower-numbered seat than Marvin. 3.
The one surnamed Anderson sat directly across from the chef who works
at Michels Cafe. 4. Marvin and the one who prepared the asparagus
soup are the one who sat in seat ve and the person who sat directly
across from the chef who made the chicken noodle soup, in some order. 5.
Norville sat next to the one who cooks for the Country Kitchen. 6. Quincy
and the chef who works for the Village Smorgasbord are the one surnamed
Dugan and a person who didnt sit directly across from the chef who made
the asparagus soup, in some order. 7. The chef who works at the Pine
Cove Restaurant and the chef who sat in seat four are the one surnamed
Anderson and someone who didnt prepare the minestrone, in some order.
8. The one surnamed Burns (who works for the Apple Orchard Inn) didnt
prepare the split pea soup. 9. The six chefs are Jenna, the chef surnamed
Dugan, the person who works for the Pine Cove Restaurant, the person
who prepared the clam chowder, the chef who sat in seat three, and the
chef who sat directly across from the one surnamed Dugan. 10. Isabel and
the one surnamed Friedman are the chef who works at Michels Cafe and
the one who made the chicken noodle soup, in some order. 11. Marvin
didnt prepare the clam chowder. 12. Jenna (who sat in an odd-numbered
seat) sat next to the one surnamed Caruso. 13. The chef who works for
the Pine Cove Restaurant didnt occupy chair number six.
Killer Sudoku 31
Write a program to solve the Killer Sudoku from Figure 4.8a: The objective is to ll the grid with numbers from 1 to 9 in a way that the following
conditions are met:
- Each row, column, and nonet32 contains each number exactly once.
- The sum of all numbers in a cage must match the small number printed
in its corner.
- No number appears more than once in a cage. The solution of Killer
Sudoku is given by Figure 4.8b).
31 This
32 A
242
4.9 Exercises
243
Pi-Day Sudoku 33
Write a program to solve the Pi-Day Sudoku from Figure 4.9a). Each row,
column, and jigsaw region must contain exactly the rst twelve digits of
pi, including repeats: 3.14159265358. Notice that each region will contain
two 1s, two 3s, three 5s, and no 7s. The solution of Pi-Day Sudoku is
given by Figure 4.9b).
33 This
Chapter 5
246
5.2
Branch-and-bound
The basic optimization method used here and in the next section is branchand-bound. A standard version of this method has already been used in Section
2.3.1. However, it would be worthwhile to have a closer look at that method.
To begin with, let us stress that there is a close correspondence between
standard1 Depth-First Backtracking Search and standard Branch-and-Bound :
what for CSP is standard Depth-First Backtracking Search, for COP is standard
Branch-and-Bound, see Figure 5.1.
247
5.3
Upgrading Branch-and-Bound
5.3.1
In order to better understand what should be done to upgrade Branch-andBound, lets consider its standard version for the simple problem of optimally
placing four queens on a 4 4 chessboard. The objective function (quite articial) is:
J = 1*X1+0*X2+1*X3+1*X4 ,
where - as previously - Xi is the row number occupied by the queen in column i.
Figure 5.2 shows two feasible placement of four queens, one of which is optimum.
Branch-and-Bound may be characterized by naming states, for which backtracking is initiated. For the standard Branch-and-Bound this happens:
when a worse objective function value has been computed (Branch-andBound backtracking);
when some constraint is violated (constraint violation backtracking).
This is shown by the search tree from Figure 5.3.
248
249
5.3.2
5.3.3
250
Figure 5.5: Search tree for Branch-and-Bound+Looking Ahead+Forward Checking for 4 queens
5.4
251
Basic built-ins
5.4.1
252
5.4.2
This is a more general version of the already discussed labeling/1 built-in, see
Section 3.2. The version supported by the ic library is:
search(+List, ++Arg, ++Select, +Choice, ++Method, +Option)
where:
List is a list of domain variables (for Arg = 0) or of terms (for Arg > 0);
Arg is an integer, which is 0 if the list is a list of domain variables, or
greater than 0. If the list consists of terms of arity greater than Arg, the
value Arg indicates the selected argument of the term;
Select is a predened variable choice heuristic:
input_order - the rst entry in the list is selected;
first_fail - the entry with the smallest domain size is selected;
anti_first_fail - the entry with the largest domain size is selected;
smallest - the entry with the smallest value in the domain is selected;
largest - the entry with the largest value in the domain is selected;
occurrence - the entry with the largest number of associated constraints is selected;
most_constrained - the entry with the smallest domain size is selected. If several entries have the same domain size, the entry with
the largest number of attached constraints is selected;
max_regret - the entry with the largest dierence between the smallest and second smallest value in the domain is selected.
253
254
5.5
A simple example
:- lib(ic).
/*2*/
/*3*/
:- lib(branch_and_bound).
top :-
/*4*/
Boards=[A,B],
/*5*/
/*6*/
Boards :: 1..60,
Profit :: 30000..40000,
/*7*/
/*8*/
A #=< 60,
B #=< 50,
/*9*/
/*10*/
/*11*/
/*12*/
Negative_profit #= - Profit,
minimize(labeling([A,B]),Negative_profit),
/*13*/
writeln("Maximum profit":Profit),nl,
/*14*/
/*15*/
255
The program displays all intermediate solutions from the search tree:
Found a solution with cost -30100 Found a solution with cost -30400
Found a solution with cost -30700 Found a solution with cost -31000
Found a solution with cost -31100 Found a solution with cost -31200
Found a solution with cost -31300 Found a solution with cost -31400
Found a solution with cost -31500 Found a solution with cost -31600
Found a solution with cost -31700 Found a solution with cost -31800
Found a solution with cost -31900 Found a solution with cost -32000
Found a solution with cost -32100 Found a solution with cost -32200
Found a solution with cost -32300 Found a solution with cost -32400
Found a solution with cost -32500 Found a solution with cost -32600
Found a solution with cost -32700 Found a solution with cost -32800
Found a solution with cost -32900 Found a solution with cost -33000
256
The problems discussed and solved below conform to the classication presented in Section 1.7.
5.6
5.6.1
Next - lets solve the optimum system conguration problem from Section 2.3.1
using an OR approach. This is done by program 5_2_configuration_OR.ecl2:
/*1*/
/*2*/
/*3*/
/*4*/
% A_1
% A_1
/*5*/
/*6*/
:- lib(ic).
:- lib(branch_and_bound).
top :Components=[A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2],
= 1 means element A_1 belongs to the configuration
= 0 means element A_1 does not belong to the configuration
Components :: 0..1,
Price:: 1..3000,
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
C_1
B_2
C_2
B_4
B_3
A_3
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
2 This
+
+
+
+
+
+
A_2
C_2
B_3
A_2
A_1
B_3
#=<
#=<
#=<
#=<
#=<
#=<
1,
1,
1,
1,
1,
1,
is an OS-type problem.
/*21*/
/*22*/
257
write(["A_1","A_2","A_3","B_1","B_2","B_3","B_4","C_1","C_2"]),nl,
write_configuration([A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2],
["A_1","A_2","A_3","B_1","B_2","B_3","B_4","C_1","C_2"]),nl,nl,
fail.
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
write_configuration([H1|T1],[_|T2]):-
/*30*/
H1 is 0,
/*31*/
/*32*/
write_configuration(T1,T2).
write_configuration([],[]).
It can be seen that fail in line /*26*/ did not initiate backtracking to determine the second optimum solution, which is known to exist as demonstrated
by program 2_9_conf_opt.pl. This is a serious limitation that however may be
bypassed as follows: in order to get all optimum solutions, a single one has to be
determined rst. Next, the optimum solution data is used to constrict the domains of variables (see line /*5*/ below) for a program that just determines all
feasible solutions. This program is given by 5_3_configuration_all_OR.ecl:
258
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
:- lib(ic).
top :Components=[A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2],
Components :: 0..1,
Price is 1900,
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
A_1
B_1
C_1
C_1
B_2
C_2
B_4
B_3
A_3
/*15*/
/*16*/
labeling(Components),
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
+
+
+
+
+
+
+
+
+
A_2
B_2
C_2
A_2
C_2
B_3
A_2
A_1
B_3
+ A_3 #= 1,
+ B_3 + B_4 #= 1,
#= 1,
#=< 1,
#=< 1,
#=< 1,
#=< 1,
#=< 1,
#=< 1,
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
write_configuration([H1|T1],[_|T2]):H1 is 0,
/*31*/
/*32*/
write_configuration(T1,T2).
write_configuration([],[]).
259
[0, 0, 1, 1, 0, 0, 0, 1, 0]
[A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2]
Optimum configuration:
A_3 B_1 C_1
Minimum configuration price:1900
Search result:
[0, 1, 0, 1, 0, 0, 0, 0, 1]
[A_1,A_2,A_3,B_1,B_2,B_3,B_4,C_1,C_2]
Optimum configuration:
A_2 B_1 C_2
Those are all optimum configurations.
5.6.2
Next the optimum conguration problem from Section 2.3.1 will be solved using
the CLP approach. The program 5_4_configuration_CLP.ecl3 is as follows:
/*1*/
/*2*/
/*4*/
:- lib(ic).
:- lib(branch_and_bound).
top:% CA - cost of element A
% NA - number of element A
/*4*/
NA :: 1..3,
/*5*/
NB :: 1..4,
/*6*/
NC :: 1..2,
/*7*/
[CA,CB,CC] :: 300..1900,
/*8*/
Cost :: 1800..2600,
/*9*/
element(NA,[1900,750,900],CA),
/*10*/
element(NB,[300,500,450,600],CB),
/*11*/
element(NC,[700,850],CC),
/*12*/
~incompatible_NB_NC(NB,NC),
/*13*/
~incompatible_NA_NB(NA,NB),
/*14*/
~incompatible_NA_NC(NA,NC),
% ~Goal is the sound negation operator, which delays if Goal is not grounded.+
/*15*/
/*16*/
Cost #= CA + CB + CC,
bb_min(labeling([NA,NB,NC]),Cost,bb_options with [strategy:step]),
/*17*/
/*18*/
/*19*/
writeln("Optimum configuration:"),
write("("),write("A"),write(NA),write(","),
write("B"),write(NB),write(","),write("C"),write(NC),writeln(")"),
3 This
is an OS-type problem.
260
/*20*/
/*21*/
/*22*/
top:-
/*23*/
/*24*/
/*25*/
incompatible_NA_NB(2,4).
incompatible_NA_NB(1,3).
incompatible_NA_NB(3,3).
/*26*/
incompatible_NA_NC(2,1).
/*27*/
/*28*/
incompatible_NB_NC(2,2).
incompatible_NB_NC(3,2).
writeln("Thats all!").
In order to generate all optimum solution the same trick as for example
5_3_configuration_all_OR.ecl has to be used. This is done in example
5_5_configuration_all_CLP.ecl4 :
/*1*/
/*2*/
:- lib(ic).
:- lib(branch_and_bound).
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
top:-
4 This
NA :: 1..3,
NB :: 1..4,
NC :: 1..2,
[CA,CB,CC] :: 300..1900,
Cost is 1900,
element(NA,[1900,750,900],CA),
element(NB,[300,500,450,600],CB),
element(NC,[700,850],CC),
~incompatible_NB_NC(NB,NC),
~incompatible_NA_NB(NA,NB),
~incompatible_NA_NC(NA,NC),
is an OS-type problem.
261
/*15*/
/*16*/
Cost #= CA + CB + CC,
labeling([NA,NB,NC]),
/*17*/
/*18*/
/*19*/
/*20*/
writeln("Optimum configuration:"),
write("("),write("A"),write(NA),write(","),
write("B"),write(NB),write(","),write("C"),write(NC),writeln(")"),
write("priced at "),write(Cost), writeln("."),nl,fail.
/*21*/
/*22*/
top:-
/*23*/
/*24*/
/*25*/
incompatible_NA_NB(2,4).
incompatible_NA_NB(1,3).
incompatible_NA_NB(3,3).
/*26*/
incompatible_NA_NC(2,1).
/*27*/
/*28*/
incompatible_NB_NC(2,2).
incompatible_NB_NC(3,2).
writeln("Thats all!").
5.6.3
Knapsack problem 1
The knapsack problem is a classical optimization problem that derives its name
from a xed-size smuggler knapsack, which must be lled with the most valuable
items. It may be formulated as follows: given a set of items, each with a
dimension (length, area, volume or weight) and a value, determine the items to
include in a collection so that the total dimension is less than a given limit and
the total value is maximized. The problem is known to exhibit combinatorial
explosion.
The most simple knapsack problem - a length-constrained knapsack problem
- can be solved using the scalar_product/3 predicate as shown in program
262
5_6_knapsack_1.ecl5:
/*1*/
/*2*/
/*3*/
/*4*/
:- lib(ic).
:- lib(branch_and_bound).
top:knapsack([52,23,35,15,7],[100,60,70,15,15],60,[_,_,_,_,_]).
/*5*/ knapsack(Sizes,Values,Knapsack_size,[X1,X2,X3,X4,X5]):/*6*/
X = [X1,X2,X3,X4,X5],
/*7*/
X :: 0..1,
/*8*/
scalar_product(Sizes,X,Size),
/*9*/
Size #=< Knapsack_size,
/*10*/
scalar_product(Values,X,Value),
/*11*/
Cost #= -Value,
/*12*/
minimize(labeling(X),Cost),nl,
/*13*/
Value is -Cost,
/*14*/
write("Value = "),writeln(Value),
/*15*/
write("Knapsack = "), writeln(X),
/*16*/
write("Size ="),writeln(Size).
/*17*/ scalar_product(List_1,List_2,Scalar_product):/*18*/
/*19*/
(
foreach(V1, List_1),
/*20*/
foreach(V2, List_2),
/*21*/
/*22*/
foreach(Product,List_of_products)
do
/*232*/
/*24*/
/*25*/
Product = V1 * V2
),
Scalar_product #= sum(List_of_products).
Value = 130
Knapsack = [0, 1, 1, 0, 0]
5 This
is an OS-type problem.
263
Size = 58,
So the optimum knapsack loading comprises items 2 and 3 from the list, of
corresponding sizes 23 and 35 amounting to 58, and of corresponding values 60
and 70 amounting to 130.
5.6.4
Reied constraints
264
The implication may be true for any value from the domain, e.g.:
This is a command:
[eclipse 6]: X is 12, Y::14..18,=>(X#=5,Y+2#>15,Index).
265
This is a command:
[eclipse 7]: X is 12, Y::12..17,=>(X#=12,Y+2#>15,Index).
5.6.5
This is a command:
[eclipse 3]::-lib(ic_sets). Set_variable :: []..[1,2,3,4,5,6],
Set_variable = [1,4,6].
266
This is a command:
[eclipse 5]::-lib(ic_sets). Set_variable :: []..[1,2,3,4,5,6],
Set_variable = [].
For ECLi P S e CP S the empty set [] does not belong to the set domain if it
has not been explicitly declared:
This is a command:
[eclipse 7]::-lib(ic_sets). Set_variable :: [4]..[5,6,7],
Set_variable = [].
where the _358 is the range of cardinal numbers for the X set.
The lower bound does not belong to any set containing also elements of the
upper bound as illustrated below:
This is a command:
[eclipse 9]::-lib(ic_sets). Set_variable :: [4]..[5,6,7],
267
Set_variable = [4,5].
In order for the lower bound to belong to some set containing (beside the lower
bound) also elements from the upper bound, it has to be included in the upper
bound:
This is a command:
[eclipse 10]: :-lib(ic_sets). Set_variable :: [4]..[4,5,6,7],
Set_variable=[4,7].
:- lib(ic_sets).
top:-
/*3*/
/*4*/
Set = [1,3],
weight(Set,[](10,20,30,40,50),Weight_of_set),
/*5*/
is an FS-type problem.
268
The built-in weight/3 may be used to determine sets with constraint weights
as shown in the program 5_8_weight_of_set_2.ecl:
/*1*/
/*2*/
:- lib(ic).
:- lib(ic_sets).
/*3*/
top:-
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
insetdomain(Set,_,_,_),
/*9*/
/*10*/
Set = [1, 3]
Weight of set = 50
Set = [1, 4]
Weight of set = 50
Weight of set = 40
Set = [2, 3]
Set = [4]
Weight of set = 50
Set = [5]
5.6.6
Knapsack problem 2
The length-constrained knapsack problem may also be solved using the weight/3
built-in, as shown in 5_9_knapsack_2.ecl7:
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
:- lib(ic).
:- lib(ic_sets).
:- lib(branch_and_bound).
top:array_of_sizes(Sizes),
array_of_values(Values),
knapsack_size(Knapsack_size),
ic_sets:(Set :: [].. [1, 2, 3, 4, 5]),
weight(Set,Sizes,Knapsack_load),
7 This
is an OS-type problem.
/*10*/
/*11*/
/*12*/
/*13*/
minimize(insetdomain(Set,decreasing,_,_),Cost),
/*14*/
/*15*/
/*16*/
write("Value = "),writeln(Value),
write("Knapsack = "), writeln(Set),
write("Knapsack load = "),writeln(Knapsack_load).
/*17*/
array_of_sizes([](52,23,35,15,7)).
/*18*/
/*19*/
array_of_values([](100,60,70,15,15)).
knapsack_size(60).
269
The optimum knapsack load is thus 58, given by items z 2 and 3, with overall
value 130.
5.6.7
is an OS-type problem.
270
:-lib(ic).
:-lib(branch_and_bound).
top :Variables = [Strategy_1,Strategy_2,Strategy_3],
Variables :: 0..60,
/*5*/
/*6*/
/*7*/
/*8*/
minimize(search(Variables,0,first_fail,indomain,complete,[]),Cost),
/*9*/ writeln("Variables":Variables ),
/*10*/ writeln("Cost":Cost).
271
It means that 12 rods should be cut using strategy 1 and 12 rods using strategy
3.
5.6.8
is an OS-type problem.
272
Parliamentarians
1, 2, 3, 4, 5
6, 7, 8, 9, 10
3, 8, 9
1, 6, 7
3, 4
2, 6
7, 10
3, 6
7
2
5, 10
Coalition parties
Spreading Wealth
Paradise on Earth
Main streams of political and social thought
Agents of Inuence 1
Agents of Inuence 2
Maa 1 Supporters
Maa 2 Supporters
Gambling Business Advocates
Anthropogenic Global Warming Believers
Big Bank Advocates
LGBT Supporters
Useful Idiots
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
273
param(X,WhoWhere,I)
do
Out #= In + X[J]*WhoWhere[I,J]
),
Sum #>= 1
),
data([](
[](1, 1, 1, 1, 1, 0, 0, 0, 0, 0),
[](0, 0, 0, 0, 0, 1, 1, 1, 1, 1),
% Spreading Wealth
% Paradise on Earth
[](0, 0, 1, 0, 0, 0, 0, 1, 1, 0),
% Agents of Influence 1
[](1, 0, 0, 0, 0, 1, 1, 0, 0, 0),
[](0, 0, 1, 1, 0, 0, 0, 0, 0, 0),
% Agents of Influence 2
% Mafia 1 Supporters
[](0, 1, 0, 0, 0, 1, 0, 0, 0, 0),
% Mafia 2 Supporters
[](0, 0, 0, 0, 0, 0, 1, 0, 0, 1),
[](0, 0, 1, 0, 0, 1, 0, 0, 0, 0),
[](0, 0, 0, 0, 0, 0, 1, 0, 0, 0),
[](0, 1, 0, 0, 0, 0, 0, 0, 0, 0),
274
The meaning of this results is obvious: only if the i-th element of the onedimensional array Selected parliamentarians is equal 1, then the i-th parliamentarian may be chosen to be a committee member.
The result is both good and bad news. The good news is that there are four
parliamentarians representing all main streams of political and social thought
cultivated in both parties. The bad news is that there are two teams of such
parliamentarians, which means that there will be much arguing in the coalition.
5.6.9
A Town Council is analyzing possible locations for the newly established large
and modern Ambulance Service Stations (ASS). The Town consists of 11 districts as shown in Figure 5.8.
275
its services to its native and all adjacent districts. The conservative majority in
the Town Council successfully defended a motion about minimizing the number
of ASS while providing all districts with their services. It also put forward
some additional suggestions about avoiding the establishment of ASS in adjacent
districts and favoured a location plan for which any district having no ASS is
adjacent to only one district with ASS.
The program 5_12_ambulance_service.ecl explains how was it done:
/*1*/
/*2*/
:- lib(ic).
:- lib(branch_and_bound).
/*3*/
top :-
276
277
Lets check if there are other optimum solutions. This is done by program
278
5_13_ambulance_service_all.ecl:
/*1*/
/*2*/
:- lib(ic).
:- lib(ic_global).
/*3*/
top :-
279
280
5.7
5.7.1
Tasks allocation (as any allocation) may sometimes be also optimized, as shown
by the following example:
Any one of seven machines may perform any one of seven dierent tasks,
but at dierent costs, as shown in Table 5.2.
Machine
1
2
3
4
5
6
7
1
15
45
56
13
45
23
76
2
23
76
45
45
49
25
98
3
43
32
87
34
18
29
86
Task
4
27
39
75
51
48
39
41
5
76
72
34
52
58
52
34
6
43
37
76
21
98
41
76
7
91
48
29
76
23
12
77
:- lib(ic).
:- lib(branch_and_bound).
% Uij - Usage of machine i for operation j:
% Uij = 1 - machine i is used for operation j.
% Uij = 0 - machine i is not used for operation j.
/*3*/
top :/*4*/
Machine_usage =
10 This
is an OS-type problem.
281
/*5*/
/*6*/
[U11,U12,U13,U14,U15,U16,U17,
U21,U22,U23,U24,U25,U26,U27,
U31,U32,U33,U34,U35,U36,U37,
U41,U42,U43,U44,U45,U46,U47,
U51,U52,U53,U54,U55,U56,U57,
U61,U62,U63,U64,U65,U66,U67,
U71,U72,U73,U74,U75,U76,U77],
Machine_usage :: 0..1,
Cost :: 1..700,
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
U11+U21+U31+U41+U51+U61+U71
U12+U22+U32+U42+U52+U62+U72
U13+U23+U33+U43+U53+U63+U73
U14+U24+U34+U44+U54+U64+U74
U15+U25+U35+U45+U55+U65+U75
U16+U26+U36+U46+U56+U66+U76
U17+U27+U37+U47+U57+U67+U77
#=
#=
#=
#=
#=
#=
#=
1,
1,
1,
1,
1,
1,
1,
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
U11+U12+U13+U14+U15+U16+U17
U21+U22+U23+U24+U25+U26+U27
U31+U32+U33+U24+U35+U36+U37
U41+U42+U43+U44+U45+U46+U47
U51+U52+U53+U54+U55+U56+U57
U61+U62+U63+U64+U65+U66+U67
U71+U72+U73+U74+U75+U76+U77
#=
#=
#=
#=
#=
#=
#=
1,
1,
1,
1,
1,
1,
1,
/*21*/
Cost #= U11*15+U12*23+U13*43+U14*27+U15*76+U16*43+U17*91
U21*45 + U22*76 + U23*32 + U24*39 + U25*72 + U26*37 +
U31*56 + U32*45 + U33*87 + U34*75 + U35*34 + U36*76 +
U41*13 + U42*45 + U43*34 + U44*51 + U45*52 + U46*21 +
U51*45 + U52*49 + U53*18 + U54*48 + U55*58 + U56*98 +
U61*23 + U62*25 + U63*29 + U64*39 + U65*52 + U66*41 +
U71*76 + U72*98 + U73*86 + U74*41 + U75*34 + U76*76 +
/*22*/
bb_min(labeling(
[U11,U12,U13,U14,U15,U16,U17,
U21,U22,U23,U24,U25,U26,U27,
U31,U32,U33,U34,U35,U36,U37,
U41,U42,U43,U44,U45,U46,U47,
U51,U52,U53,U54,U55,U56,U57,
U61,U62,U63,U64,U65,U66,U67,
U71,U72,U73,U74,U75,U76,U77]),
Cost,bb_options with [strategy:step]),
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
+
U27*48 +
U37*29 +
U47*76 +
U57*23 +
U67*12 +
U77*77,
282
/*28*/
/*29*/
/*30*/
/*31*/
display_results(5,[U51,U52,U53,U54,U55,U56,U57],[45,49,18,48,58,98,23]),
display_results(6,[U61,U62,U63,U64,U65,U66,U67],[23,25,29,39,52,41,12]),
display_results(7,[U71,U72,U73,U74,U75,U76,U77],[76,98,86,41,34,76,77]),
fail.
/*32*/
/*33*/
top:writeln("Thats all!").
/*34*/
display_results(M,U,C):-
/*35*/
/*36*/
element(N, U, 1),
element(N, C, Op_Cost),
/*37*/
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
283
:- lib(ic).
:- lib(branch_and_bound).
% Uij - Usage of machine i for operation j:
% Uij = 1 - machine i is used for operation j.
% Uij = 0 - machine i is not used for operation j.
top :Machine_usage =
[U11,U12,U13,U14,U15,U16,U17,
U21,U22,U23,U24,U25,U26,U27,
U31,U32,U33,U34,U35,U36,U37,
U41,U42,U43,U44,U45,U46,U47,
U51,U52,U53,U54,U55,U56,U57,
U61,U62,U63,U64,U65,U66,U67,
U71,U72,U73,U74,U75,U76,U77],
Machine_usage :: 0..1,
Cost is 178,
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
U11+U21+U31+U41+U51+U61+U71
U12+U22+U32+U42+U52+U62+U72
U13+U23+U33+U43+U53+U63+U73
U14+U24+U34+U44+U54+U64+U74
U15+U25+U35+U45+U55+U65+U75
U16+U26+U36+U46+U56+U66+U76
U17+U27+U37+U47+U57+U67+U77
#=
#=
#=
#=
#=
#=
#=
1,
1,
1,
1,
1,
1,
1,
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
U11+U12+U13+U14+U15+U16+U17
U21+U22+U23+U24+U25+U26+U27
U31+U32+U33+U24+U35+U36+U37
U41+U42+U43+U44+U45+U46+U47
U51+U52+U53+U54+U55+U56+U57
U61+U62+U63+U64+U65+U66+U67
U71+U72+U73+U74+U75+U76+U77
#=
#=
#=
#=
#=
#=
#=
1,
1,
1,
1,
1,
1,
1,
/*21*/
Cost #= U11*15+U12*23+U13*43+U14*27+U15*76+U16*43+U17*91
U21*45 + U22*76 + U23*32 + U24*39 + U25*72 + U26*37 +
U31*56 + U32*45 + U33*87 + U34*75 + U35*34 + U36*76 +
U41*13 + U42*45 + U43*34 + U44*51 + U45*52 + U46*21 +
U51*45 + U52*49 + U53*18 + U54*48 + U55*58 + U56*98 +
U61*23 + U62*25 + U63*29 + U64*39 + U65*52 + U66*41 +
U71*76 + U72*98 + U73*86 + U74*41 + U75*34 + U76*76 +
/*22*/
labeling(
[U11,U12,U13,U14,U15,U16,U17,
U21,U22,U23,U24,U25,U26,U27,
U31,U32,U33,U34,U35,U36,U37,
U41,U42,U43,U44,U45,U46,U47,
U51,U52,U53,U54,U55,U56,U57,
+
U27*48 +
U37*29 +
U47*76 +
U57*23 +
U67*12 +
U77*77,
284
U61,U62,U63,U64,U65,U66,U67,
U71,U72,U73,U74,U75,U76,U77]),
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
top:writeln("Thats all!").
/*33*/
display_results(M,U,C):-
/*34*/
/*35*/
element(N, U, 1),
element(N, C, Op_Cost),
/*36*/
5.7.2
As before, the CLP approach is more parsimonious than the OR approach with
respect to the number of variables needed to solve the problem. This is well
demonstrated by program 5_16_opty77_CLP.ecl11:
11 This
is an OS-type problem.
/*1*/
/*2*/
:- lib(ic).
:- lib(branch_and_bound).
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
element(O1,[15,23,43,27,76,43,91],C1),
element(O2,[45,76,32,39,72,37,48],C2),
element(O3,[56,45,87,75,34,76,29],C3),
element(O4,[13,45,34,51,52,21,76],C4),
element(O5,[45,49,18,48,58,98,23],C5),
element(O6,[23,25,29,39,52,41,12],C6),
element(O7,[76,98,86,41,34,76,77],C7),
/*15*/
/*16*/
Cost #= C1+C2+C3+C4+C5+C6+C7,
bb_min(labeling([O1,O2,O3,O4,O5,O6,O7]),Cost,
bb_options with [strategy:step]),
display_results([O1,C1,O2,C2,O3,C3,O4,C4,O5,C5,O6,C6,O7,C7],1),
write("Overall cost: "),write(Cost).
/*17*/
/*18*/
/*19*/
/*20*/
285
display_results([],_).
display_results([A,B|R],N):-
/*21*/
/*22*/
/*23*/
/*24*/
display_results(R,M).
:- lib(ic).
:- lib(branch_and_bound).
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
286
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
element(O1,[15,23,43,27,76,43,91],C1),
element(O2,[45,76,32,39,72,37,48],C2),
element(O3,[56,45,87,75,34,76,29],C3),
element(O4,[13,45,34,51,52,21,76],C4),
element(O5,[45,49,18,48,58,98,23],C5),
element(O6,[23,25,29,39,52,41,12],C6),
element(O7,[76,98,86,41,34,76,77],C7),
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
Cost #= C1+C2+C3+C4+C5+C6+C7,
labeling([O1,O2,O3,O4,O5,O6,O7]),
display_results([O1,C1,O2,C2,O3,C3,O4,C4,O5,C5,O6,C6,O7,C7],1),
write("Overall cost: "),write(Cost),
fail.
/*20*/
/*21*/
top:writeln("Thats all!").
/*22*/
/*23*/
display_results([],_).
display_results([A,B|R],N):-
/*24*/
/*25*/
/*26*/
/*27*/
display_results(R,M).
Obviously, the message generated is exactly the same as for the already discussed
program 5_14_opty77_all_OR.ecl.
5.7.3
Transport- and production problems, which have been from the beginning of
OR successfully solved by OR techniques, are also rewarding problems for CLP
techniques. Consider the following example:
Three mines m1, m2 and m3 deliver their output to ve stockyards s1, s2, s3,
s4 i s5 at dierent locations. The capacity of each stockyard equals 400 ton
of output per month, while the monthly outputs equals 600 ton for mine m1
and 700 ton for mines m2 and m3. The production cost for one ton of output
are respectively 108, 96 i 102 MU. The delivery costs for one ton of output are
shown in Table 5.3.
How large should the output of mines be and how much output should the
mines deliver to the stockyard in order to minimize the overall cost of production
and transportation? This problem is solved by program 5_18_mines_1.ecl12:
12 This
is an OS-type problem.
287
Mine
m1
m2
m3
Stockyard
s2 s3 s4
5
9 24
24 11 8
22 15 7
s1
14
30
9
s5
15
19
18
/*1*/
:- lib(ic).
/*2*/
:- lib(branch_and_bound).
/*3*/
top :-
Cost :: 0..300000,
/*8*/
/*9*/
/*10*/
A1+A2+A3+A4+A5 #=600,
B1+B2+B3+B4+B5 #=700,
C1+C2+C3+C4+C5 #=700,
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
A1+B1+C1
A2+B2+C2
A3+B3+C3
A4+B4+C4
A5+B5+C5
#=400,
#=400,
#=400,
#=400,
#=400,
% Output of mine m1
% Output of mine m2
% Output of mine m3
%
%
%
%
%
Capacity
Capacity
Capacity
Capacity
Capacity
of
of
of
of
of
stockyard
stockyard
stockyard
stockyard
stockyard
s1
s2
s3
s4
s5
bb_min(search([A1,A2,A3,A4,A5,B1,B2,B3,B4,B5,
C1,C2,C3,C4,C5],0,first_fail,indomain,complete,[]),
288
tons
tons
tons
tons
tons
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
tons
tons
tons
tons
tons
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
tons
tons
tons
tons
tons
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
stockyard s3 000
stockyard s4 000
stockyard s5 200
289
tons of output.
tons of output.
tons of output.
to:
of output.
of output.
of output.
of output.
of output.
to:
of output.
of output.
of output.
of output.
of output.
5.7.4
Cost :: 0..2500,
/*8*/
/*9*/
/*10*/
A1+A2+A3+A4+A5 #=6,
B1+B2+B3+B4+B5 #=7,
C1+C2+C3+C4+C5 #=7,
/*11*/
A1+B1+C1 #=4,
% Capacity of stockyard s1
/*12*/
A2+B2+C2 #=4,
% Capacity of stockyard s2
% Output of mine m1
% Output of mine m2
% Output of mine m3
290
/*13*/
A3+B3+C3 #=4,
% Capacity of stockyard s3
/*14*/
/*15*/
A4+B4+C4 #=4,
A5+B5+C5 #=4,
% Capacity of stockyard s4
% Capacity of stockyard s5
The cost domain is also expressed for hundreds of tons and decreased in
view of the results obtained by program 5_18_mines_1.ecl. Introducing obvious changes to lines /*18*/,...,/*36*/, the program 5_19_mines_2.ecl13 is
obtained, which solves the problem in a jiy generating the message:
Found
Found
Found
...
Found
Found
Found
Found
13 This
is an OS-type problem.
5.7.5
291
Examples discussed in Sections 5.7.3 and 5.7.4 are integer programming examples: the objective function is linear in integer decision variables, and the
constraints are equations or inequalities linear in integer decision variables as
well. For such problems ECLi P S e CP S makes available an ecient solver
named eplex. In eplex symbols of arithmetic operations and relations have to
be prexed by $. Its application will be illustrated by the already discussed mine
production and transportation problem using program 5_20_mines_3.ecl14:
/*1*/
:- lib(eplex).
/*2*/
top :/*3*/
solve(_,_).
/*4*/
solve(Cost,Variables):/*5*/
Variables = [A1,A2,A3,A4,A5,B1,B2,B3,B4,B5,C1,C2,C3,C4,C5],
/*6*/
Variables $:: 0.0..1.0Inf,
% A default domain for all variables of problems
% solved with the \emph{eplex} solver is -1.0Inf..1.0Inf.
%
An integer solution is to be determined:
/*7*/
integers(Variables),
% Output of mine m1:
/*8*/
A1+A2+A3+A4+A5 $=600,
% Output of mine m2:
/*9*/
B1+B2+B3+B4+B5 $=700,
% Output of mine m3:
/*10*/
C1+C2+C3+C4+C5 $=700,
% Stockyard capacities:
/*11*/
A1+B1+C1 $=400,
/*12*/
A2+B2+C2 $=400,
/*13*/
A3+B3+C3 $=400,
/*14*/
A4+B4+C4 $=400,
/*15*/
A5+B5+C5 $=400,
/*16*/
Cost $= 14*A1+5*A2+9*A3+24*A4+15*A5+
30*B1+24*B2+11*B3+8*B4+19*B5+9*C1+22*C2+15*C3+7*C4+18*C5+
108*A1+108*A2+108*A3+108*A4+108*A5+96*B1+96*B2+96*B3+96*B4+
96*B5+102*C1+102*C2+102*C3+102*C4+102*C5,
/*17*/
/*18*/
/*19*/
/*29*/
14 This
eplex_solver_setup(min(Cost),
eplex_solve(Cost),
write("Mine m1 has to deliver to:"),nl,
write("stockyard s1 = "),write(A1),write(" tons of output."),nl,
is an OS-type problem.
292
/*21*/
/*22*/
/*23*/
/*24*/
write("stockyard
write("stockyard
write("stockyard
write("stockyard
s2
s3
s4
s5
=
=
=
=
"),write(A2),write("
"),write(A3),write("
"),write(A4),write("
"),write(A5),write("
tons
tons
tons
tons
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
write("Mine m2 has to
write("stockyard s1 =
write("stockyard s2 =
write("stockyard s3 =
write("stockyard s4 =
write("stockyard s5 =
deliver to:"),nl,
"),write(B1),write("
"),write(B2),write("
"),write(B3),write("
"),write(B4),write("
"),write(B5),write("
tons
tons
tons
tons
tons
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
deliver to:
_6066{0.0 ..
_6050{0.0 ..
_6034{0.0 ..
_6018{0.0 ..
_6002{0.0 ..
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
@
@
@
@
@
Mine m2 has to
stockyard s1 =
stockyard s2 =
stockyard s3 =
stockyard s4 =
stockyard s5 =
deliver to:
_5986{0.0 ..
_5970{0.0 ..
_5954{0.0 ..
_5938{0.0 ..
_5922{0.0 ..
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
@
@
@
@
@
Mine m3 has to
stockyard s1 =
stockyard s2 =
stockyard s3 =
stockyard s4 =
stockyard s5 =
deliver to:
_5906{0.0 ..
_5890{0.0 ..
_5874{0.0 ..
_5858{0.0 ..
_5842{0.0 ..
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
1.79769313486232e+308
@
@
@
@
@
293
5.7.6
A1+B1+C1
A2+B2+C2
A3+B3+C3
A4+B4+C4
A5+B5+C5
/*14*/
Cost $=
14*A1+5*A2+9*A3+24*A4+15*A5+
30*B1+24*B2+11*B3+8*B4+19*B5+
9*C1+22*C2+15*C3+7*C4+18*C5+
108*A1+108*A2+108*A3+108*A4+108*A5+
96*B1+96*B2+96*B3+96*B4+96*B5+
102*C1+102*C2+102*C3+102*C4+102*C5,
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
eplex_solver_setup(min(Cost)),
eplex_solve(Cost),
eplex_get(vars,Vars),
eplex_get(typed_solution,Vals),
Vars = Vals,nl,
/*20*/
$=400,
$=400,
$=400,
$=400,
$=400,
294
/*22*/
/*23*/
write("Mine
write("stockyard
write("stockyard
write("stockyard
write("stockyard
write("stockyard
m2
s1
s2
s3
s4
s5
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
write("Mine
write("stockyard
write("stockyard
write("stockyard
write("stockyard
write("stockyard
m3
s1
s2
s3
s4
s5
of
of
of
of
of
output."),nl,
output."),nl,
output."),nl,
output."),nl,
output."),nl,nl,
295
5.7.7
Map coloring
Lets try to test the Graph Coloring Theorem (see Sections 2.4.7 and 3.7.4) for
coloring a map.
This has to be done for the administrative map of Absurdoland showing
the countrys division into districts, see Figure 5.10 where districts are denoted
by alphanumeric Di symbols, so that a minimum number of colors is used and
adjacent districts have dierent colors.
This is done by program 5_22_map_coloring.ecl15:
/*1*/
:- lib(ic).
/*2*/
:- lib(ic_edge_finder3).
/*3*/
:- lib(branch_and_bound).
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
15 This
top:Districts = [D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16],
Districts :: 1..16,
L :: 1..16,
color([D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16]),
maxlist([D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16],L),
minimize(labeling([D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,
D15,D16]),L),nl,nl,
write("Minimum number of colors = "),write(L),nl,
is an OS-type problem.
296
/*12*/
/*13*/
/*14*/
/*15*/
write("Districts = "),write("D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,
D11,D12,D13,D14,D15,D16"),nl,
write("Colors
= "), write(Districts).
color([D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16]):D1 #\= D4,
/*16*/
D1 #\= D5,
/*17*/
D1 #\= D2,
/*18*/
D2 #\= D5,
/*19*/
/*21*/
D2 #\= D6,
D3 #\= D6,
/*20*/
/*22*/
D2 #\= D3,
D3 #\= D7,
/*23*/
D3 #\= D8,
/*24*/
D4 #\= D10,
/*25*/
/*27*/
D4 #\= D5,
D5 #\= D11,
/*26*/
/*28*/
D5 #\= D10,
D5 #\= D9,
/*29*/
/*31*/
D5 #\= D6,
D6 #\= D7,
/*30*/
/*32*/
D6 #\= D9,
D7 #\= D9,
/*33*/
D7 #\= D13,
/*34*/
D7 #\= D14,
/*35*/
/*37*/
D7 #\= D8,
D9 #\= D11,
/*36*/
/*38*/
D8 #\= D14,
D9 #\= D12,
/*39*/
D9 #\= D13,
/*40*/
/*41*/
/*43*/
/*42*/
/*44*/
/*45*/
/*47*/
/*46*/
/*48*/
/*49*/
D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16
= [1, 2, 1, 2, 3, 4, 2, 3, 1, 1,
2,
3,
4,
1,
1,
2]
297
5.7.8
298
Education Agency, to coordinate rain education at all levels, starting with junior classes on Rainfall Justice, through senior classes on Rain Management,
up to chains of Educational and Correctional Institutions (to convince and win
over the most ardent opponents of rainfall justice), 6)Rain Lobbying Agency to
encourage the leaders of nations to contribute additionally to rain funds as well
as supporting groups of Rainpeace activists, 7)World Rain Institute, to manage
and nance rain research, to provide Young Researcher Rain Grants and to
organize Scientic Rain Summits on selected football stadiums.
Obviously, to successfully implement such broad range of complicated actions, highly qualied experts are needed. Luckily, three world-reputable rain
activists, Professor Hoaxman, Professor Luftmensch and Colonel Baron Fraud
of Blubury - have been blessed with a progeny that from their earliest days,
while listening to discussions at the Family Tables, had acquired such deep
knowledge and understanding of rainfall theory and practice, which would be
impossible to get at the best universities. Luckily as well, this progeny is - for
dierent reasons - busily looking for new jobs:
So the two daughters of the Colonel Baron had to vacate the posts of vicechairwoman of the Silly Initiative Monetary Fund. The elderly - it turned out
- did not quite understood the meaning of percentages, thereby causing huge
nancial losses16 , the younger one had problems with grasping the dierence
between European and Anglo-American billions, causing a number of quite embarrassing and costly blunders17 .
Professors Hoaxman son, after being dismissed from a Sport Academy, was
employed as caddy by an exclusive Golf Club. There, listening for some time to
the palaver of playing bank ocials, it occurred to him rightly that he would
surely be successful in this profession. Hence he started dreaming about asserting himself in some banking business.
The young Luftmensch in his wildest dreams envisaged himself in uniforms,
of course some elegant ones, dark blue or white, with golden braids and multicolored ribbons, and of course with the inseparable personal power and adoring
girls all around. In such uniforms he could well manage the Rain Flotilla, e.g.
using the white uniform to command the Rainfall Stopping Planes, and the
blue uniform to command the Rainfall Causing Planes. Strongly believing that
16 The dear one should not be blamed: she could not take - because of acute drug-and-booze
poisoning - Home Math classes on percentages at her beloved Quick Results College.
17 This should really be excused because the poor girl - while studying at the renowned
Quick Results College - could not attend Home Math classes on large numbers; this was due
to the urgent need to get rid of the fruit of some exciting night spend with somebody she
cant remember.
299
Agenda
Int. Rain Fund
Rain Flotilla
Satellite Monitoring
Air Ionizers
Education
Lobbing
Rain Research
Salaries
(MM MU)
Hoaxman
Jr
Applicants
Luftmensch Older Ms
Jr
Blubury
Younger Ms
Blubury
12
is an OS-type problem.
300
/*1*/ :-lib(ic).
/*2*/ :-lib(branch_and_bound).
/*3*/ top :% Xj = 1 - the application of candidate j has been accepted.
% Xj = 0 - the application of candidate j has been rejected.
/*4*/ Variables=[X1,X2,X3,X4],
/*5*/ Variables :: 0..1,
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
X1
X2
X3
X2
X3
X1
X1
+
+
+
+
+
+
+
X4
X3
X4
X4
X4
X4
X2
#>=
#>=
#>=
#>=
#>=
#>=
#>=
1,
1,
1,
1,
1,
1,
1,
Luckily only one application (of younger Ms Blubury) has been rejected.
Notice the discrepancy between the length of the story and the shortness
of the program. Well, there is no iunctim between the length of a story (i.e.
between the complex circumstances giving raise to the problem) and the length
of its program: sometimes to explain the background knowledge of some simple
integer programming programs, a lot of things needs to be presented.
5.7.9
For the popular puzzle Send More Money (see Section 4.4.1) an optimization
version known as Send Most Money may be found, see Kjellerstrands website
[Kjellerstrand-13], which aims at maximizing the value of Money. It is given by
301
program 5_24_smm.ecl19 :
/*1*/ :-lib(ic).
/*2*/ :-lib(branch_and_bound).
/*3*/ top :% 1) Finding a single solution that maximizes MONEY:
%
a)A list LD with 8 variables is created. The variables
%
correspond to the eight letters in "Send Most Money":
/*4*/
length(LD, 8),
%
b)The domain of LD must include all single-position digits,
%
because it is not known, which of them will be finally needed:
/*5*/
LD :: 0..9,
% c)This is the main constraint:
/*6*/
send_most_money(LD, MONEY),
%
Maximization is needed, but only the built-in minimize/2
%
is available, so negative MONEY is to be minimized:
/*7*/
MONEY_NEGATIVE #= -MONEY,
/*8*/
/*9*/
/*10*/
member(L,Everything),
writeln(L),
/*27*/
fail.
/*28*/ write_list([]).
19 This
is an OS-type problem.
302
The nesting of labeling(LD2) into the findall built-in in line /*13*/ for the
purpose of nding all optimum solutions is worth noticing. It may also be
applied to other optimum-seeking problems.
5.8
5.8.1
CLP approach to this problem has been rst presented in [van Hentenryck-89].
is an OS-type problem.
21 This
Customer
303
Warehouse
1
2
3
5
7 20
4 20 1
20 2
5
20 20 4
3 20 8
18 20 28
1
2
3
4
5
Building cost
Table 5.5: Delivery and building costs for 3 warehouses and 5 customers
/*1*/
/*2*/
/*3*/
/*4*/
:- lib(ic).
:- lib(branch_and_bound).
top:warehouses(_,_).
T11
T21
T31
T41
T51
+
+
+
+
+
T12
T22
T32
T42
T52
+
+
+
+
+
T13
T23
T33
T43
T53
#=
#=
#=
#=
#=
1,
1,
1,
1,
1,
/*13*/
/*14*/
/*15*/
/*16*/
/*17*/
T11
T21
T31
T41
T51
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
T12
T22
T32
T42
T52
/*23*/
/*24*/
%
%
%
%
%
customer
customer
customer
customer
customer
1
2
3
4
5
is
is
is
is
is
serviced
serviced
serviced
serviced
serviced
just
just
just
just
just
by
by
by
by
by
one
one
one
one
one
warehouse
warehouse
warehouse
warehouse
warehouse
#=<
#=<
#=<
#=<
#=<
W1,
W1,
W1,
W1,
W1,
%
%
%
%
%
if
if
if
if
if
warehouse
warehouse
warehouse
warehouse
warehouse
1
1
1
1
1
is
is
is
is
is
built,
built,
built,
built,
built,
it
it
it
it
it
may
may
may
may
may
service
service
service
service
service
customer
customer
customer
customer
customer
1
2
3
4
5
#=<
#=<
#=<
#=<
#=<
W2,
W2,
W2,
W2,
W2,
%
%
%
%
%
if
if
if
if
if
warehouse
warehouse
warehouse
warehouse
warehouse
2
2
2
2
2
is
is
is
is
is
built,
built,
built,
built,
built,
it
it
it
it
it
may
may
may
may
may
service
service
service
service
service
customer
customer
customer
customer
customer
1
2
3
4
5
304
/*25*/
/*26*/
/*27*/
/*28*/
Cost #= 18*W1+10*W2+28*W3+5*T11+7*T12+100*T13+4*T21+100*T22+1*T23+
100*T31+2*T32+5*T33+100*T41+100*T42 +4*T43+3*T51+100*T52+8*T53 ,
/*29*/
bb_min(labeling([W1,W2,W3,T11,T12,T13,T21,T22,T23,T31,T32,T33,
T41,T42,T43,T51,T52,T53]),Cost, bb_options{strategy:restart}),
nl,
/*30*/
/*31*/
/*32*/
/*32*/
writeln([T11,T12,T13,T21,T22,T23,T31,T32,T33,T41,T42,T43,T51,T52,T53]),
/*33*/
write("Cost: "),writeln(Cost),nl.
5.8.2
5_26_warehouses_CLP_1.ecl22:
/*1*/ :- lib(ic).
/*2*/ :- lib(branch_and_bound).
%op(Precedence, +Associativity, ++Name)+
/*3*/ :- op(960, fx, if).
/*4*/ :- op(950,xfx, then).
/*5*/
/*6*/
top:warehouses(_,_,_).
/*7*/
/*8*/
warehouses(Ws,Cs,Cost):Ws=[W1,W2,W3],
% if Wi=0, warehouse "i" is not build
% if Wi=1, warehouse "i" is build
/*9*/
Ws::0..1,
/*10*/
/*11*/
%
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
Cs=[C1,C2,C3,C4,C5],
Cs::1..3,
Cj - number of warehouse serving the "j"-th customer
element(C1,[5,7,20],Cost_1),
element(C2,[4,20,1],Cost_2),
element(C3,[20,2,5],Cost_3),
element(C4,[20,20,4],Cost_4),
element(C5,[3, 20,8],Cost_5),
/*17*/
/*18*/
/*19*/
/*20*/
Cost #= 18*W1+20*W2+28*W3+Cost_1+Cost_2+Cost_3+Cost_4+Cost_5,
/*21*/
bb_min((labeling(Ws),labeling(Cs)),Cost,
bb_options{strategy:restart}),
/*22*/
write("
List of warehouses: "),
writeln([W1,W2,W3]),
write("
List of customers and warehouses: "),
writeln([C1,C2,C3,C4,C5]),
write("
Cost: "),
writeln(Cost).
/*23*/
/*24*/
/*25*/ outof([],_).
/*26*/ outof([K|Ks],N):22 This
is an OS-type problem.
305
306
/*27*/
/*28*/
K #\= N,
outof(Ks,N).
gives
Term = likes("John",play),
and:
307
gives
List = [s,[1,4,5,6]].
call(+Goal) succeeds if Goal succeeds: it calls the goal Goal. This builtin is used to call goals that are grounded only at the time they are called.
For lines /*35*/,..,/*38*/ wait until Bool is grounded, then call Goal,
or simply succeed.
op(960, fx, if) and op(950,xfx, then) mean that the then part
from lines */17*/, */18*/ and */19*/ is evaluated after the if part
was, see Section 2.1.4.
As before, the number of variables needed to model the warehouse location
problem OR-wise is decisively larger than the number needed to model it CLPwise.
5.8.3
The program 5_26_warehouses_CLP_1.ecl discussed so far has weak propagation properties23 , which is due to multiple callings of the element/3 builtin. The next program 5_27_warehouses_CLP_2.ecl, which is a slightly modied version of the Warehouse location program authored by J. Schimpfa (see
[Schimpf-10]), has better propagation properties . It uses a heuristic which orders - for each client - warehouses according the the rising delivery cost. This
is illustrated for a more complicated problem given by table 5.6:
As before we would like to know, which warehouses should be built, and for
which customers, in order to minimize the overall delivery and building cost.
The program 5_26_warehouses_CLP_1 discussed before has rather poor
propagation properties, mainly due to the multiple use of the element/3 builtin. As result, to solve more complicated problems takes long times. The next
program 5_27_warehouses__CLP_2.ecl24, which is a slightly modied version
of the Warehouse location program by Schimpf (see [Schimpf-10]), is much better. It is based on a following heuristic: for each customer the warehouses have
to be ordered according to rising delivery costs. The program is as follows:
23 This
24 This
308
Customers
1
2
3
4
5
6
7
8
9
10
Building cost
1
5
14
2
110
300
3
30
230
20
30
18
Warehouses
2
3
7
1
8
100
20
50
2
200
300
8
100
8
40
20
50
70
350 70
450 370
10
28
4
20
300
12
5
200
5
80
8
98
250
20
Table 5.6: Delivery and building costs for 4 warehouses and 10 customers
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_sets).
/*3*/ :- lib(branch_and_bound).
/*4*/ top:% declare the data:
/*5*/
building_cost_array(BuildingCostArray),
/*6*/
delivery_cost_array(DeliveryCostArray),
/*7*/
dim(DeliveryCostArray,[NumberOfClients,NumberOfHouses]),
/*8*/
dim(BuildingCostArray,[NumberOfHouses]),
% declare constraints:
intset(ListOfBuildHouses,1,NumberOfHouses),
(
for(ClientsId, 1, NumberOfClients),
foreach(NumberOfHouseForClient,HousesForClients),
foreach(DeliveryCostForClient,ListOfDeliveryCostsForClients),
param(ListOfBuildHouses,DeliveryCostArray,NumberOfHouses)
do
ListOfDeliveryCosts is
DeliveryCostArray[ClientsId,1..NumberOfHouses],
/*17*/
element(NumberOfHouseForClient,ListOfDeliveryCosts,DeliveryCostForClient),
/*18*/
NumberOfHouseForClient in ListOfBuildHouses
/*19*/
),
/*20*/
weight(ListOfBuildHouses,BuildingCostArray,BuildingCost),
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
/*21*/
% objective function:
OverallCost #= BuildingCost + sum(ListOfDeliveryCostsForClients),
309
% heuristics: sort warehouses for all clients in order of increasing delivery cost:
/*37*/ sort_houses(DeliveryCostArray,SortedListsOfHousesForClients) :/*38*/
dim(DeliveryCostArray,[NumberOfClients,NumberOfHouses]),
/*39*/
( for(I,1,NumberOfHouses),
/*40*/
foreach(I,ListOfHouseId)
/*41*/
do
/*42*/
true
/*43*/
),
/*44*/
(
/*45*/
for(ClientsId, 1, NumberOfClients),
/*46*/
foreach(SortedListOfHousesForClient,SortedListsOfHousesForClients),
/*47*/
param(DeliveryCostArray,NumberOfHouses,ListOfHouseId)
/*48*/
do
/*49*/
DeliveryCosts is DeliveryCostArray[ClientsId,1..NumberOfHouses],
/*50*/
sorting(DeliveryCosts,ListOfHouseId,SortedListOfHousesForClient)
/*51*/
).
% bounding variables "HousesForClients"
/*52*/
310
/*53*/
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
/*59*/
/*60*/
/*61*/
/*62*/
/*63*/
/*64*/
/*65*/
/*66*/
/*67*/
/*68*/
/*69*/
(
foreach(NumberOfHouseForClient,HousesForClients),
foreach(SortedListOfHousesForClient,SortedListsOfHousesForClients)
do
member(NumberOfHouseForClient,SortedListOfHousesForClient)
).
% intermediate constraint: sorting heuristic
sorting(Keys, Values, SortedValues):(foreach(K,Keys),
foreach(W,Values),
foreach(K-W,KeyValues)
do
true),
keysort(KeyValues, SortedKeyValues),
(foreach(W,SortedValues),
foreach(_K-W,SortedKeyValues)
do
true).
/*70*/
/*71*/
/*72*/
/*73*/
/*74*/
/*75*/
/*76*/
/*77*/
/*78*/
/*79*/
/*80*/
/*81*/
delivery_cost_array([](
[](5,7,1,20),
[](14,8,100,300),
[](2,20,50,12),
[](110,2,200,5),
[](300,300,8,200),
[](3,100,8,5),
[](30,40,20,80),
[](230,50,70,8),
[](20,350,70,98),
[](30,450,370,250)
)).
/*81*/
building_cost_array([](18,10,28,20)).
311
5.8.4
An ecient program comparable to the one from Section 5.8.3 may also be
designed by not using sets but using the built-in fromto/4. This is demonstrated
by example 5_28_warehouses_CLP_3.ecl25, where the following variables have
been used:
ListOfClientHouses - list of variables corresponding to warehouse numbers associated with consecutive customers, e.g. ListOfClientHouses =
[3, 1, 1, 4, 3, 1, 3, 4, 1, 1] means that customer 5 will be served
by warehouse 3.
ListOfHousesBuild - list of variables denoting warehouses that will be
build. E.g. ListOfHousesBuild = [1,0,1, 1] means that warehouse 2
is not going to be build.
DeliveryCostArray - one-dimensional array of delivery costs for consecutive clients.
25 This
312
/*7*/
/*8*/
:-lib(ic).
:-lib(ic_global).
:-lib(branch_and_bound).
top:declare_data(DeliveryCostArray,BuildingCostList),
constrain(ListOfClientHouses,
ListOfHousesBuild,DeliveryCostArray,
BuildingCostList,OverallCost),
find_optimum_solution(ListOfClientHouses,
OverallCost),
display_results(ListOfClientHouses,
ListOfHousesBuild,OverallCost).
/*9*/ declare_data(DeliveryCostArray,BuildingCostList):/*10*/
DeliveryCostArray=[](
/*
H1 H2 H3 H4 */
/*11*/
/* K1 */ [5 ,7 ,1 ,20 ],
/*12*/
/* K2 */ [14 ,8 ,100,300],
/*13*/
/* K3 */ [2 ,20 ,50 ,12 ],
/*14*/
/* K4 */ [110,2 ,200,5 ],
/*15*/
/* K5 */ [300,300,8 ,200],
/*16*/
/* K6 */ [3 ,100,8 ,5 ],
/*17*/
/* K7 */ [30 ,40 ,20 ,80],
/*18*/
/* K8 */ [230,50 ,70 ,8 ],
/*19*/
/* K9 */ [20 ,350,70 ,98 ],
/*20*/
/* K10*/ [30 ,450,370,250]
/*21*/
),
/*22*/
BuildingCostList=[18,10,28,20].
/*23*/ constrain(ListOfClientHouses,
ListOfHousesBuild,DeliveryCostArray,
BuildingCostList,OverallCost):/*24*/
dim(DeliveryCostArray,[NumberOfClients]),
/*25*/
length(BuildingCostList,MaxNumberOfHouses),
% Knowing "NumberOfClients" the unbounded
% "ListOfClientHouses" is created:
/*26*/
length(ListOfClientHouses,NumberOfClients),
% Its domain includes all warehouses under consideration
/*27*/
ListOfClientHouses#::[1..MaxNumberOfHouses],
26 This
is an OS-type problem.
313
/*50*/
/*51*/
314
5.8.5
For real-valued objective functions, even if the decision variables are integers,
branch-and-bound is not delivering: we have to resort to eplex. This is illustrated by the following example:
In order to promote tolerance and ght discrimination, the Absurdolands Ministry of National Brainwashing, after analyzing a number of public surveys, has
ordered that the enrollment to any High School in Absurdoland must be at least
10% gay or lesbian. As a result of this, the Happy Town School Authorities are
facing a following problem: there are ve High School Districts with numbers of
straight and gay/lesbian students as shown by Table 5.7, and two High Schools
(HS), with mean distances from the districts shown by the same Table.
District
1
2
3
4
5
Straight
80
70
90
50
60
Gay/lesbian
15
13
8
20
15
Distance to HS 1
3
1
2
2.6
3
Distance to HS 2
6
1.5
0.8
1.8
1.2
315
Variables=[D1_HS1,D1_HS2,D2_HS1,D2_HS2,D3_HS1,D3_HS2,
D4_HS1,D4_HS2,D5_HS1,D5_HS2],
Variables $:: 0.0..1.0Inf,
integers(Variables),
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
D1_HS1
D2_HS1
D3_HS1
D4_HS1
D5_HS1
/*11*/
/*12*/
+
+
+
+
+
D1_HS2
D2_HS2
D3_HS2
D4_HS2
D5_HS2
$=
$=
$=
$=
$=
1,
1,
1,
1,
1,
316
/*13*/
/*14*/
/*15*/
Distance $= D1_HS1 * 3
+ D1_HS2 *
D2_HS1
D3_HS1
D4_HS1
D5_HS1
6
*
*
*
*
+
1
2
2.6
3
+
+
+
+
D2_HS2
D3_HS2
D4_HS2
D5_HS2
*
*
*
*
1.5 +
0.8 +
1.8 +
1.2,
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
eplex_solver_setup(min(Distance)),
eplex_solve(Distance),
eplex_get(vars,Vars),
eplex_get(typed_solution,Vals),
Vars = Vals,nl,
write(Variables),nl,
/*22*/
(foreach(A,["D1_HS1","D1_HS2","D2_HS1","D2_HS2","D3_HS1","D3_HS2",
"D4_HS1","D4_HS2","D5_HS1","D5_HS2"]),
/*23*/
foreach(X,[D1_HS1,D1_HS2,D2_HS1,D2_HS2,D3_HS1,D3_HS2,
/*24*/
do
/*25*/
write(A),write(" = "),write(X),nl).
D4_HS1,D4_HS2,D5_HS1,D5_HS2])
5.9
317
Timetabling is the process of deciding who should act (or what should happen)
in a well-dened time span in order to satisfy a number of constraints and
minimize some performance index. In the most elementary case it is the process
of dening on the Cartesian product of two sets (the set of actors or actions and
the set of time intervals) a subset satisfying constraints and minimizing some
objective function, and known as timetable.
5.9.1
A roster is a list showing the order in which people are to perform a set of
duty. A crew roster problem aims at determining an allocation of the duties
into rosters satisfying constraints of job regulations and minimizing the number
of people involved.
A large fast food bar operate seven days each week and faces the problem
of deciding how many employees to use on what day. The bar has a reliable
forecast of the number of employees needed for each day of the week, which
shows that for Monday 20 employees are needed, for Tuesday 16, Wednesday
- 13, for Thursday 16, for Friday - 19, Saturday 14 and for Sunday - 12. The
bar hires employees to work at ve consecutive days with two consecutive days
o. How many employees need to start work each day of the week to minimize
the total number of employees hired? The solution is presented by program
5_30_crew_rostering.ecl27:
/*1*/ :- lib(ic).
/*2*/ :- lib(branch_and_bound).
/*3*/
top:% Demand for employees working on consecutive days starting with Monday:
/*4*/
Demand = [20,16,13,16,19,14,12],
% Domains for variables:
% Mon - number of employees starting work on Monday, etc.
/*5*/
[Mon,Tue,Wed,Thu,Fri,Sat,Sun] :: 0..50,
% On Mondays are working employees who started on Monday,
% or on Thursday, or on Friday, or on Saturday, or on Sunday.
% Monday is a day off for those who started on Tuesday and Wednesday.
/*6*/
Monday #= Mon + Thu + Fri + Sat + Sun,
% The number of employees working on Monday should meet the demand:
/*7*/
element(1,Demand,D1),
/*8*/
Monday #>= D1,
27 This
is an OST-type problem.
318
319
320
5.9.2
Optimality (in the strict sense used in this book) means just that the solution
optimizes some objective function. The practical value of such optimum solution
may (in some cases) be at odds with the theoretical result. To bridge the gap
between both notions of optimality, a reformulation of the problem or a change
of objective function may often be needed. This is illustrated by the following
crew roster problem for toll collectors.
5.9.3
A tollway has a toll plaza with the following stang demands for each 24-hour
period:
from 24 to 6 - 2 collectors
from 6 to 10 - 8 collectors
from 10 to 12 - 4 collectors
from 12 to 16 - 3 collectors
from 16 to 18 - 6 collectors
from 18 to 22 - 5 collectors
from 22 to 24 - 3 collectors28
Each collector works four hours, is o one hour, and then works another four
hours. A collector may start the work at any hour. How many collectors should
start work at each hour in order to minimize the number of collectors hired?
The following variables are needed:
X1 - number of collectors that start work at 1
X2 - number of collectors that start work at 2
X3 - number of collectors that start work at 3
28 Well, the 24-hour clock system, although not popular in English-speaking countries, is
decidedly more CLP-friendly and less error-prone for around the clock time-tabling tasks.
:- lib(eplex).
top:Variables = [X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,
X13,X14,X15,X16,X17,X18,X19,X20,X21,X22,X23,X24],
Variables $:: 0.0..1.0Inf,
integers(Variables),
is an OST-type problem.
321
322
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
NumberOfCollectors $= X1+X2+X3+X4+X5+X6+X7+X8+X9+X10+
X11+X12+X13+X14+X15+X16+X17+X18+X19+X20+X21+X22+X23+X24,
eplex_solver_setup(min(NumberOfCollectors)),
eplex_solve(NumberOfCollectors),
eplex_get(vars,Vars),
eplex_get(typed_solution,Vals),
Vars = Vals,nl,
/*36*/
/*37*/
/*38*/
/*39*/
/*40*/
/*41*/
323
Number is X1+X2+X3+X4+X5+X6+X7+X8+X9+X10+X11+X12+
X13+X14+X15+X16+X17+X18+X19+X20+X21+X22+X23+X24,
write("Overall number of collectors = "),write(Number),nl,nl,
(foreach(A,["1","2","3","4","5","6","7","8","9","10","11","12",
"13","14","15","16","17","18","19","20","21","22","23","24"]),
foreach(X,[X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,
X13,X14,X15,X16,X17,X18,X19,X20,X21,X22,X23,X24])
do
write("Number of collectors starting work at "),
write(A),write(" oclock = "),write(X),nl).
As can be seen, the collector balances (lines /*6*/ - /*29*/) are formulated
so as to fulll the main constraint: each collector works 4 hours, has an hour
break, and works for another 4 hours.
The solution obtained is as follows:
Overall number of collectors = 16
Number of collectors staring to work at 1 oclock
Number of collectors staring to work at 2 oclock
= 2
= 1
= 1
= 1
= 1
= 3
= 0
= 0
= 0
= 0
= 1
= 2
= 2
= 2
= 0
= 0
= 0
= 0
= 0
= 0
324
= 0
= 0
5.9.4
Dog Service
325
How many dogs should start working at any hour throughout day and night in
order to minimize the overall number of dogs working around the clock?
The following variables are needed;
X1 - number of dogs that start working at 1
X2 - number of dogs that start working at 2
...
X24 -number of dogs that start working at 24.
The dog balances for each hour are formulated so as to fulll the main
constraint: each each dog works one hour with an hour long break afterwards.
The program 5_32_dogs.ecl looks like this:
/*1*/ :- lib(eplex).
/*2*/ top:/*3*/ Dogs = [X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,
X13,X14,X15,X16,X17,X18,X19,X20,X21,X22,X23,X24],
/*4*/
/*5*/
326
327
Number_of_dogs $= X1+X2+X3+X4+X5+X6+X7+X8+X9+X10+X11+X12+
X13+X14+X15+X16+X17+X18+X19+X20+X21+X22+X23+X24,
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
eplex_solver_setup(min(Number_of_dogs)),
eplex_solve(Number_of_dogs),
eplex_get(vars,Vars),
eplex_get(typed_solution,Vals),
Vars = Vals,nl,
(foreach(A,["1","2","3","4","5","6","7","8","9","10","11","12",
"13","14","15","16","17","18","19","20","21","22","23","24"]),
/*39*/ foreach(X,[X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,
X13,X14,X15,X16,X17,X18,X19,X20,X21,X22,X23,X24])
/*40*/ do
/*41*/ write("Number of dogs starting work at "),write(A),
write(" oclock is "),write(X),nl).
of
of
of
of
of
of
of
of
of
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
starting
starting
starting
starting
starting
starting
starting
starting
starting
work
work
work
work
work
work
work
work
work
at
at
at
at
at
at
at
at
at
1
2
3
4
5
6
7
8
9
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
is
is
is
is
is
is
is
is
is
0
5
0
2
4
1
4
0
0
328
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
Number
of
of
of
of
of
of
of
of
of
of
of
of
of
of
of
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
dogs
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
starting
work
work
work
work
work
work
work
work
work
work
work
work
work
work
work
at
at
at
at
at
at
at
at
at
at
at
at
at
at
at
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
oclock
is
is
is
is
is
is
is
is
is
is
is
is
is
is
is
0
0
0
0
3
0
0
3
0
0
0
0
0
0
0
5.9.5
Police ocers
The number of optimum solutions with the same value of objective function
could - for some problems - be large indeed. Consider the following example:
The City Police Station30 needs at least, for successive 4-hour intervals aroundthe-clock, the number of police ocers on duty as given by Table 5.8:
Time (hours)
Interval
2-6
6 - 10
10 - 14
14 - 18
18 - 22
22 - 2
1
2
3
4
5
6
Number of ocers
required
22
55
88
110
44
33
:-lib(ic).
:-lib(branch_and_bound).
30 This
/*7*/
/*8*/
/*8*/
329
330
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
Sum
/*17*/
bb_min(labeling([Officers_1,Officers_2,Officers_3,
Officers_4,Officers_5,Officers_6]),
Sum,bb_options with [strategy:step]), nl,
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
#= Officers_1+Officers_2+Officers_3+Officers_4+Officers_5+Officers_6,
/*28*/ top:/*28*/
write("Thats all!"),nl,nl.
331
/*7*/
/*8*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
Officers_1+Officers_2+Officers_3+Officers_4+Officers_5+
Officers_6 #= 198,
/*17*/
labeling([Officers_1,Officers_2,Officers_3,
Officers_4,Officers_5,Officers_6]),
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
count(Number),
write("Number of
write("Number of
write("interval_
write("interval_
write("interval_
write("interval_
solution: ),write(Number),nl,
officers starting service at the beginning of:"),nl,
1: "),write(Officers_1),nl,
2: "),write(Officers_2),nl,
3: "),write(Officers_3),nl,
4: "),write(Officers_4),nl,
332
/*25*/
/*26*/
/*27*/
/*28*/
write("interval_ 5: "),write(Officers_5),nl,
write("interval_ 6: "),write(Officers_6),nl,nl,
write("Minimum number of police officers needed: "),write(Sum),nl,nl,
fail.
/*29*/ top:/*30*/
write("Thats all!"),nl,nl.
/*31*/ count:/*32*/
retract(counter(Old)),
/*33*/
/*34*/
New is Old 1, +
assert(counter(New)).
This time the program generates 32154 solutions; only the rst and last is shown
below:
Number of solution: 1
Number of officers starting their service at the beginning of
interval_ 1: 0
interval_ 2: 55
interval_ 3: 33
interval_ 4: 77
interval_ 5: 0
interval_ 6: 33
Minimum number of police officers needed: 198
......
Number of solution:
32154:
333
5.10
334
5.10.1
335
Activity name
Foundation
Walls
Sanitary installation
Roof
Electrical installation
Painting
Activity duration
5
6
3
5
3
2
End
Precedence
Nothing
Foundation
Foundation
Walls
Walls
Electrical installation
Sanitary installation
Roof
Painting
336
3. To determine the critical path, for the last change additionally lines /*x*/
have to be decommented and lines /*17b, /*18*/, /*19*/,...,/*24*/ have
to be commented.
The program 5_35_house.ecl32 is as follows:
/*1*/
:-lib(ic).
% for a single minimum-time solution:
/*2a*/ :-lib(branch_and_bound).
/*3*/ top:-
/*4a*/
/*7a*/
house(Operations):Operations = [Foundation,Walls,SanitaryInstallation,Roof,
ElectricalInstallation,Painting,End],
% for a single minimum-time solution:
Operations :: 0..25,
%
for a single minimum-time solution:
/*16a*/ End #=< 25,
%
for all minimum-time solutions:
/*16b*/%
End #= 18,
%
for a single minimum-time solution:
/*17a*/
minimize(labeling(Operations),End),nl,
32 This
is an OST-type problem.
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
get_domain(Foundation,DFoundation),
get_domain(Walls,DWalls),
get_domain(SanitaryInstallation,DSanitaryInstallation),
get_domain(Roof,DRoof),
get_domain(ElectricalInstallation,DElectricalInstallation),
get_domain(Painting,DPainting),
get_domain(End,DEnd),
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
/*x*/%
%
/*17b*/%
337
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
write("End: "),write(End),nl.
338
/*?b*/ have to be decommented, lines numbered by /*?a*/ have to be commented, and the shortest duration (End: 18) is used as the upper bound of
the Operations domain in line /*7b*/. The modied program (referred to as
5_36_house_all.ecl) then generates 24 optimum solutions, from which the
following three are presented:
Starting
Starting
Starting
Starting
Starting
Starting
End: 18
time
time
time
time
time
time
for
for
for
for
for
for
foundation: 0
walls: 5
sanitary installation: 5
roof: 11
electrical installation: 11
painting: 16
Starting
Starting
Starting
Starting
Starting
Starting
End: 18
time
time
time
time
time
time
for
for
for
for
for
for
foundation: 0
walls: 5
sanitary installation: 5
roof: 11
electrical installation: 12
painting: 16
Starting
Starting
Starting
Starting
Starting
Starting
End: 18
time
time
time
time
time
time
for
for
for
for
for
for
foundation: 0
walls: 5
sanitary installation: 5
roof: 11
electrical installation: 13
painting: 16
Now, if for the last change the x lines are additionally decommented, and
the lines /*17b*/, /*18*/, /*19*/,...,/*24*/ are commented, then the modied
program (referred to as 5_37_house_crit_path.ecl) generates the following
result:
Domain of foundation: 0
Domain of walls: 5
Domain of sanitary installation: 5 .. 12
Domain of Roof: 11
Domain of electrical installation: 11 .. 13
Domain of painting: 16
Domain of End: 18
Single value domains indicate that the corresponding activities (for founda-
339
tion, walls, roof and painting) determine the critical path: in order to decrease
the projects duration, durations of critical path activities must be decreased.
5.10.2
:-lib(ic).
:-lib(branch_and_bound).
top :schedule(_).
/*5*/ schedule([Z1,Z2,Z3,Z4,End]):/*6*/
[Z1,Z2,Z3,Z4,End] :: 0..15,
/*7*/
Z1 + 3 #=< Z2,
/*8*/
Z1 + 3 #=< Z3,
/*9*/
Z2 + 4 #=< Z4,
/*10*/
Z3 + 2 #=< Z4,
/*11*/
Z4 + 1 #= End,
/*12*/
disjunctive([Z2,4,Z3,2]),
/*13*/
minimize(labeling([Z1,Z2,Z3,Z4,End]),End),
/*14*/
writeln("Z1 ":Z1),
/*15*/
writeln("Z2 ":Z2),
/*16*/
writeln("Z3 ":Z3),
/*17*/
writeln("Z4 ":Z4),
/*18*/
writeln("End ":End).
/*19*/ disjunctive([Z1,D1,Z2,_]):/*20*/
Z1 + D1 #=< Z2.
/*21*/ disjunctive([Z1,_,Z2,D2]):/*22*/
Z2 + D2 #=< Z1.
340
Z2 : 3
Z3 : 7
Z4 : 9
End
: 10
341
: 3
Z4 : 7
End : 8
5.10.3
is an FS-type problem.
342
/*1*/ :-lib(ic).
/*2*/ top :/*3*/
Persons = [Anna, Ben, Charles, Derek, Eva, Fred, Gary],
% The meaning of variables is as follows: Anna is the position number
% (counting from left) occupied by person "Anna", etc.
/*4*/
Persons :: 1..7,
/*5*/
alldifferent(Persons),
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
next_to(Anna,Eva),
next_to(Anna,Fred),
next_to(Ben,Anna),
next_to(Ben,Eva),
next_to(Derek,Fred),
next_to(Derek,Charles),
next_to(Gary,Derek),
next_to(Gary,Charles),
/*14*/
/*15*/
search(Persons,0,first_fail,indomain,complete,[]),
writeln("Persons ":Persons).
/*16*/ next_to(X,Y):/*17*/
X #= Y + 1.
/*18*/ next_to(X,Y):/*19*/
Y #= X + 1.
The message generated is No. However, if lines /*6*/ and /*11*/ are removed
343
(no attention is payed to one preference by Anna and one by Derek), the solution obtained is:
Persons
: [5, 6, 1, 3, 7, 4, 2]
Persons
: [3, 2, 7, 5, 1, 4, 6]
The question may well be asked how many of the declared preferences may
be satised at most, if all of them cannot. The maximum number of satised
344
:-lib(ic).
:-lib(branch_and_bound).
top :preferences(Preferences),
dim(Preferences,[NumberOfPreferences,2]),
dim(Positions, [7]),
Positions :: 1..7,
alldifferent(Positions),
37 This
is an OS-type problem.
345
%
4 next to 6, 4 next to 3
% 4. Gary wishes to stand next to Derek and Charles:
%
7 next to 4, 7 next to 3
/*30*/ preferences([](
[](1,5),
[](1,6),
[](2,1),
[](2,5),
[](4,6),
[](4,3),
[](7,4),
[](7,3))).
Ben,Eva,Anna,Fred,Derek,Charles,Gary
The alignment is shown in Figure 5.20. There are two preferences not fullled.
Obviously, this is not a unique optimum solution: program 5_39_photo_1.ecl,
with lines /*6*/ and /*11*/ removed, generated two solutions with dierent 6
preferences fullled.
346
5.11
Exercises
Five textbooks
Find the optimum solution to the following problem: Bookco Publishers is
considering publishing ve textbooks. The maximum number of copies of
each textbook that can be sold, the variable cost of producing each textbook, the sales price of each textbook, and the xed cost of a production
run for each book are given in Table 5.10. Thus for example, producing
2000 copies of book l brings in a revenue of 2000*50 = 100000 but costs
80000 + 25*2000 = 130000 MU. Bookco can produce at most 10 thousand
books. How can they maximize prot?
Textbooks
Maximum demand
Variable cost (MU)
Sales price (MU)
Fixed cost (thousands MU)
1
5000
25
50
80
2
4000
20
40
50
3
3000
15
38
60
4
4000
18
32
30
5
3000
22
40
40
5.11 Exercises
347
pensions) to look for a mechanism that could make the dogs to generate
some income towards the retiree benets of their masters. A hastily created Think Tank considered a number of proposals, but its Final Scrutiny
Report presented in detail just one recommendation referred to by the
acronym TET, meaning Tail Energy Taps. The idea was to convert the
dogs natural (and pretty useless) tail-wagging into useful energy by means
of a small computer-controlled and tail-driven electrical power generator
loading a small battery. Such TETs would be attached to the dogs behind and interfaced with their tails. All dog masters would be obliged
by law to download the energy stored in the battery once per week at
the local Dog Energy Sink (DES), were it would be used to drive pumps
rising water to a cascade of elevated reservoirs, thus converting dogs energy into stored gravitational potential energy for future uses. For lazy
dogs an enhanced TET model was envisaged, allowing to control the dogs
tail-wagging through Internet, and prompt the dogs declining activity by
a series of gentle randomly changing mechanical and acoustical signals.
The submitted proposal was enthusiastically supported by the overwhelming majority of parliamentarians. The environmentalists could not praise
enough the brilliant idea of tapping a hitherto untouched source of green
energy, its sustainability and renewability. Some of them even envisaged
TETs to tail-wag the way to energy independence. Parliamentarian dogooders of all stripes were just enthralled by the bright prospect of creating
a number of green technical jobs in newly created branches of TET production, TET maintenance, DES building, and DES maintenance, as well as
green management jobs in the newly created District Dog Energy Coordination Outlets (DDECO), the National Department of Dog Energy (NDDE, in
the Ministry of Energy), and the Dog Energy Police Task Force (DEPTF,
in the Ministry of Interior ) for chasing dogs with no TETs attached to
their behinds. The objections raised by a small group of TET-sceptics,
who argued that without massive taxpayer funded subsidies dog-energy
is unsustainable, were brushed aside, and a Dog Energy Bill was passed
quickly. This was welcomed by a number of companies thinking about
downloading on the market some of their outdated mechanical and electronic hardware that still gathered dust on the shelves, and give something
to do to their underemployed and overpaid unionized manpower. The Bill
had plenty of gaps, which could be protably exploited by shrewd companies. The most important gap was the lack of canigraphic 38 data; nobody
38 A
348
in Absurdoland knew how many large dogs and how many small dogs
live there, but the Bill distinguished those groups of dogs, prescribing for
each group a unique TET contraption. The reasonable approach by all
companies engaged was to stop worrying about the dog canilation 39 and
start maximizing prot, pretty sure that their output will be bought by
state-controlled NDDE outlets at state-established prices.
So did the renowned Junk Techno Company, which saw the opportunity to
get rid of two of their dust gathering mechanical appliances, Type_A and
Type_B, rejected by both Army and Navy. Both appliances could practically at small cost be converted into correspondingly small dog TETs
(Type_B appliance only) and large dog TETs (Type_A plus Type_B appliances). Whats more, they constitute the main cost factor of the TETs,
the needed accompanying electronics being practically freely available at
various electronics graveyards. The daily conversion of Type_A appliances
could not be larger than 60 items, the daily conversion of Type_B appliances could not be larger than 50 items. The furnishing of all produced
appliances with electronics could be done at the pace of 120 appliances
daily.
On the basis of NDDE-approved purchasing prices for small and large dog
TETs, the Company estimated its daily prot from getting rid of a single
Type_A appliance as being no less than 300 MU, and from getting rid of
a single Type_B appliance - 500 MU. Write a program that determines
the number of appliances produced to maximize the daily prot of the
company.
Glue
Glueco produces three types of glue on two dierent production lines.
Each line can be utilized by up to seven workers at a time. Workers are
paid 500 MU per week on production line l, and 900 MU per week on
production line 2. For a week of production it costs 1000 MU to set up
production line l and 2000 MU to set up production line 2. During a week
on a production line, each worker produces the number of units of glue
shown in Table 5.11. Each week, at least 120 units of glue l, at least 150
units of glue 2, and at least 200 units of glue 3 must be produced. Write
a program to minimize the total cost of meeting weekly demands.
Allocating machines
A product can be produced on four dierent machines. Each machine
39 A
5.11 Exercises
349
Production lines
Production line l
Production line 2
Glue 1
20
50
Glue 2
30
35
Glue 3
40
45
Capacity
900
1000
1200
1600
Number of
rolls
100
125
80
350
Five projects
Five projects are being evaluated over a 3-year planning horizon. Table
5.1440 gives the expected returns and the associated yearly expenditure
for each project.
Project
1
2
3
4
5
Available
funds
(milion MU)
Expenditure
(million MU per year)
year 1 year 2 year 3
5
1
8
4
7
10
3
9
2
7
4
1
8
6
10
25
25
Returns
(million MU)
20
40
20
15
30
25
5.11 Exercises
351
352
ues for their most wanted benets, and suggested that the Commission
should do its job by maximizing Happines over all entitled beneciaries
by selecting the number of dierent benets granted. Next the Commission established prices for those benets, the Ministry of Medical Technology informed, that - because of technological constraints - no more
than 30 height-matching and 15 face-matching operations could be performed yearly, and the Ministry of Cultural Heritage declared that the
number of small-sized servants-staed manor houses available for manorless Napoleonides is (unfortunately, at least for the time being) limited to
6. It was also considered reasonable that (in view of the sorry state of
economy) Napoleonides equipped with horses for riding should not claim
horse-driven carriages. The basic problem data is presented by Table 5.15.
Number of
beneciaries
N1
N2
N3
N4
N5
N6
Type of
benet
Napoleon-like outt
Horse for riding
Horse-drawn carriage
Face matching
Height matching
Manor house
Happiness
Value
6
25
50
180
200
500
Cost of benet
per beneciary
40
300
1500
2000
6500
13000
5.11 Exercises
Plant
1
2
3
4
353
Fixed cost
7 billion MU
6 billion MU
4 billion MU
2 billion MU
SUV
15000 MU
12000 MU
17000 MU
19000 MU
Variable cost
Electric
19000 MU
18000 MU
16000 MU
22000 MU
Green
15000 MU
11000 MU
12000 MU
9000 MU
District
1
2
3
4
5
6
7
8
Cost of building (MM MU)
10
15 12 8 12
13
354
41 This
42 This
5.11 Exercises
355
Students grievances 43
A University is in the process of forming a committee to handle students
grievances. The administration wants the committee to include at least
one female, one male, one students, one administrator and one faculty
member. Ten individuals a,b,c,...,j have been nominated to serve on the
committee, see Table 5.18.
Category
Females
Males
Students
Administrators
Faculty
Individuals
a,b,c,d,e
f,g,h,i,j
a,b,c,j
e,f
d,g,h,i
43 This
44 This
356
No
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Activity
Design layout
Select contractor
Cleaning area
Plumbing
Install electricity
Install AC
Tile oors
Install walk-in cooler
Make partition
Tile walls and partitions
Ceiling, lighting, AC
Equipment installation
Paste
Design store front
Install store front
Paint 1 and 2
Install counters
Install electricity sockets
Install frames
Paint 3
Final decoration
Prepare sign board
Install sign board
Print new store opening
Final test
Predecessor
1
2
3
3
3
4
7
8
9
5, 6, 7
10, 11
12
3
14
13, 15
16
13
16
17, 19
20
3
22
18, 21, 23
Days
1
5
5
5
12
7
7
1
6
7
4
2
3
5
5
2
4
1
1
1
1
2
2
2
1
Chapter 6
Introduction
Some global predicates were already introduced and applied in Chapter 4 for
nding feasible solutions. Some of them (like cumulative/4, cumulative/5,
disjunctive/2) and some new ones (like disjoint/1 and cycle/3) are indispensable for solving a group of new optimization problems:
1. Optimum scheduling problems. Scheduling is an extension of sequencing:
scheduling is sequencing with the additional constraint on available resources
and the aim of minimizing an objective function, given most often by the time
to complete the schedule, known as makespan. Resource constraints may be
dened as follows:
Demand_A_for_shared_resource + ... +
Demand_Z_for_shared_resource <=
Maximum_amount_of_shared_resource_available.
This constraint is fundamental and universal, almost like the Law of Gravitation (toutes proportion gardee): no rational decision-making is possible while
abstracting from the niteness of resources.
2. Optimum bin packing problems. The aim of those problems is most often to
pack the highest-value number of objects of dierent values into a bin of xed
357
358
6.2
359
360
6.3
Cumulative scheduling 1
Lets apply the cumulative/4 built-in to data from Section 5.10.2. This can be
done as shown in program 6_1_cumu_schedule_1.ecl1:
/*1*/
/*2*/
/*3*/
:-lib(ic).
:- lib(ic_edge_finder3).
:-lib(branch_and_bound).
/*4*/
/*5*/
top :schedule(_).
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
schedule([Z1,Z2,Z3,Z4,End]):[Z1,Z2,Z3,Z4,End] :: 0..15,
Z1 + 3 #=< Z2,
Z1 + 3 #=< Z3,
Z2 + 4 #=< Z4,
Z3 + 2 #=< Z4,
Z4 + 1 #= End,
/*13*/ cumulative([Z2,Z3],[4,2],[1,1],1),
/*14*/ minimize(labeling([Z1,Z2,Z3,Z4,End]),End),
/*15*/ writeln("Z1 ":Z1),
/*16*/ writeln("Z2 ":Z2),
/*17*/ writeln("Z3 ":Z3),
/*18*/ writeln("Z4 ":Z4),
/*19*/ writeln("End ":End).
: 10.
is an OST-type problem.
361
ated is:
Found a solution with cost 8
Z1
Z2
: 0
: 3
Z3
: 3
Z4 : 7
End : 8.
6.4
Cumulative scheduling 2
Task
1
2
3
4
5
6
7
Duration
16
6
13
7
5
18
4
Resource
2
9
3
7
10
1
11
:- lib(ic).
:- lib(ic_edge_finder3).
:- lib(branch_and_bound).
2 This
is an OST-type problem.
362
/*4*/top:/*5*/
LS = [S1,S2,S3,S4,S5,S6,S7],
%list of
/*6*/
LD = [16, 6,13, 7, 5,18, 4],
%list of
/*7*/
LE = [E1,E2,E3,E4,E5,E6,E7],
%list of
/*8*/
LR = [2,9,3,7,10,1,11],
%list of task
/*9*/
LS :: 1..100,
/*10*/
End :: 1..100,
/*11*/
LE :: 1..100,
/*12*/
Limit :: 1..13,
/*13*/
cumulative(LS,LD,LR,Limit),
/*14*/
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
E1
E2
E3
E4
E5
E6
E7
/*21*/
/*22*/
maxlist([E1,E2,E3,E4,E5,E6,E7],End),
minimize(labeling([S1,S2,S3,S4,S5,S6,S7,
E1,E2,E3,E4,E5,E6,E7]),End),
/*23*/
/*24*/
/*25*/
/*26*/
#=
#=
#=
#=
#=
#=
#=
S1
S2
S3
S4
S5
S6
S7
+
+
+
+
+
+
+
16,
6,
13,
7,
5,
18,
4,
A Gantt chart illustrating this schedule is given by Figure 6.2. The numbers
inside rectangles are task numbers. This gure may also be interpreted as a
solution for a bin-packing problem, namely the problem of cutting a rectangle
with dimension 13 23 into smaller rectangles given by the tasks.
363
6.5
Cumulative sequencing
The cumulative/4 predicate may be used also for optimum sequencing problems. This is illustrated by the following assembly line example: a sequence of
tasks should be determined that fullls precedence and time constraints as well
as minimizes the overall assembly time. The following set of tasks and their
duration is given:
jobs:
A
B
C
D
E
F
G
H I
J
K
duration:
45 11
9 50 15 12 12 12 12
8
9 .
The precedence constraints are:
first_next(predecessor, successor)
first_next(A,B).
first_next(B,C).
first_next(C,F).
first_next(C,G).
first_next(F,J).
364
first_next(G,J).
first_next(J,K).
first_next(D,E).
first_next(E,H).
first_next(E,I).
first_next(H,J).
first_next(I,J).
For any pair (predecessor-successor), predecessor cannot start before successor has ended. Program 6_3_sequencing_opti_cum.ecl uses the
cumulative/4 global built-in to determine a sequence of jobs that minimizes
the overall assembly time:
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_edge_finder3).
/*3*/ :- lib(branch_and_bound).
/*4*/
top:% task start times:
/*5*/
LS=[As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
/*6*/
LS :: 0..250,
/*7*/
End :: 0..250,
% precedence
/*8*/
As
/*9*/
Bs
/*10*/
Cs
/*11*/
Cs
/*12*/
Fs
/*13*/
Gs
/*14*/
Js
/*15*/
Ds
/*16*/
Es
/*17*/
Es
/*18*/
Hs
/*19*/
Is
/*20*/
Ks
/*21*/
cumulative([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
[45,15,9,50,15,12,12,12,12,8,9],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],1),
/*22*/
minimize(labeling([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks]),End),
/*23*/
writeln([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks,End]).
365
Our intuition suggest however that there may be more solutions. This is to
be veried using program 6_4_sequencing_opti_cum_all.ecl, with variable
End grounded on optimum value 199:
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_edge_finder3).
/*3*/
top:/*4*/
assert(counter(0)),
% task start times:
/*5*/
LS=[As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
/*6*/
LS :: 0..250,
% precedence and time constraints:
/*7*/
As + 45 #=< Bs,
/*8*/
Bs + 15 #=< Cs,
/*9*/
Cs + 9 #=< Fs,
/*10*/
Cs + 9 #=< Gs,
/*11*/
Fs + 12 #=< Js,
/*12*/
Gs + 12 #=< Js,
/*13*/
Js + 8 #=< Ks,
/*14*/
Ds + 50 #=< Es,
/*15*/
Es + 15 #=< Hs,
/*16*/
Es + 15 #=< Is,
/*17*/
Hs + 12 #=< Js,
/*18*/
Is + 12 #=< Js,
/*19*/
Ks + 9 #= End,
/*20*/
End is 199,
/*21*/
cumulative([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
[45,15,9,50,15,12,12,12,12,8,9],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],1),
/*22*/
labeling([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks]),
/*23*/
/*24*/
my_count,
counter(Number),
/*25*/
/*26*/
366
/*27*/
fail.
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
my_count:retract(counter(Old)),
New is Old 1, +
assert(counter(New)).
Our intuition was well-founded: there are 504 optimum solutions. Only some
of them are shown below:
Optimum solution 1:
[0, 45, 60, 69, 119, 134, 146, 158, 170, 182, 190, 199]
.................................................................
Optimum solution 61:
[0, 45, 110, 60, 119, 134, 146, 158, 170, 182, 190, 199]
.................................................................
Optimum solution 141:
[0, 95, 110, 45, 119, 134, 146, 158, 170, 182, 190, 199]
.................................................................
Optimum solution
504:
[89, 134, 149, 0, 50, 170, 158, 77, 65, 182, 190, 199]
Those are all optimum solutions.
The Gantt chart for those solutions shown in Figure 6.3 presents a proper
interpretation of the above numerical results.
6.6
367
tasks along the time coordinate (on Gantt charts - horizontally). However - as
shown by the following example - disjunctive/2 may sometimes fulll the role
of cumulative/3.
6.7
Disjunctive sequencing
The disjunctive/2 built-in is most often used for sequencing problems. This
is illustrated by example 6_5_opti_dis.ecl dealing with the already solved
problem from Section 6.5:
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_edge_finder3).
/*3*/ :- lib(branch_and_bound).
/*4*/
top:% task start times:
/*5*/
LS=[As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
/*6*/
LS :: 0..250,
368
/*7*/
End :: 0..250,
disjunctive([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
[45,15,9,50,15,12,12,12,12,8,9]),
/*22*/
minimize(labeling([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks]),End),
/*23*/
writeln([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks,End]).
369
/*3*/
top:/*4*/
assert(counter(0)),
% task start times:
/*5*/
LS=[As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
/*6*/
LS :: 0..250,
% precedence and time constraints:
/*7*/
As + 45 #=< Bs,
/*8*/
Bs + 15 #=< Cs,
/*9*/
Cs + 9 #=< Fs,
/*10*/
Cs + 9 #=< Gs,
/*11*/
Fs + 12 #=< Js,
/*12*/
Gs + 12 #=< Js,
/*13*/
Js + 8 #=< Ks,
/*14*/
Ds + 50 #=< Es,
/*15*/
Es + 15 #=< Hs,
/*16*/
Es + 15 #=< Is,
/*17*/
Hs + 12 #=< Js,
/*18*/
Is + 12 #=< Js,
/*19*/
Ks + 9 #= End,
/*20*/
End is 199,
/*21*/
disjunctive([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks],
[45,15,9,50,15,12,12,12,12,8,9]),
/*22*/
labeling([As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is,Js,Ks]),
/*23*/
/*24*/
my_count,
counter(Number),
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
my_count:retract(counter(Old)),
New is Old 1, +
assert(counter(New)).
There are 504 optimum solutions, exactly the same as for program 6_4_sequencing_
opti_cum_all.ecl. See also Figure 6.3
370
6.8
Disjunctive scheduling
Lets solve the example from Section 5.10.2 using disjunctive/2. This is done
by program 6_7_dis_schedule.ecl3 :
/*1*/
/*2*/
/*3*/
:- lib(ic).
:- lib(ic_edge_finder3).
:- lib(branch_and_bound).
/*4*/
/*5*/
top :schedule(_).
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
schedule([Z1,Z2,Z3,Z4,End]):[Z1,Z2,Z3,Z4,End] :: 0..15,
Z1 + 3 #=< Z2,
Z1 + 3 #=< Z3,
Z2 + 4 #=< Z4,
Z3 + 2 #=< Z4,
Z4 + 1 #= End,
/*13*/ disjunctive([Z2,Z3],[4,2]),
/*14*/ minimize(labeling([Z1,Z2,Z3,Z4,End]),End),
/*15*/ writeln("Z1 ":Z1),
/*16*/ writeln("Z2 ":Z2),
/*17*/ writeln("Z3 ":Z3),
/*18*/ writeln("Z4 ":Z4),
/*19*/ writeln("End ":End).
: 10,
is an OST-type problem.
6.9
371
This is a generalization of the disjunctive/2 predicate for the case of two dimensions. It constrains the position (and possibly size) of rectangles in Rectangles
so that none overlaps. The rectangles are dened by structures:
rect{x:X,y:Y,w:W,h:H}
using the following elds:
constant x: The x co-ordinate of the left side of the rectangle, equal to
variable X;
constant y: The y co-ordinate of the bottom side of the rectangle, equal
to variable Y;
constant w: The width of the rectangle equal to variable W;
constant h: The height of the rectangle equal to variable H.
Its basic usage is illustrated by program 6_8_disjoint.ecl:
:- lib(gfd).
top_1:disjoint2([rect{x:1,y:2,w:1,h:1}, rect{x:3,y:1,w:2,h:1},rect{x:4,y:3,w:3,h:1}]).
top_2:disjoint2([rect{x:1,y:2,w:1,h:1},rect{x:3,y:1,w:2,h:1},rect{x:4,y:2,w:3,h:3}]).
top_3:disjoint2([rect{x:1,y:2,w:1,h:1},rect{x:3,y:1,w:2,h:3},rect{x:4,y:2,w:3,h:3}]).
The solution to top_1 and top_2 is yes, the solution to top_3 is no. Figure 6.5
depicts the rectangles involved in this program.
372
6.10
373
declaration
LSZ #:: 0..100,
Lst #:: 1..4,
LE #:: 0..100,
Limit #:: 1..4,
tasks end
(EA #>= A
(EB #>= B
(EC #>= C
(ED #>= D
(EE #>= E
(EF #>= F
times::
+ Ad),
+ Bd),
+ Cd),
+ Dd),
+ Ed),
+ Fd),
374
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
gfd_gac:
gfd_gac:
gfd_gac:
gfd_gac:
gfd_gac:
(EG
(EH
(EI
(EJ
(EK
#>=
#>=
#>=
#>=
#>=
G
H
I
J
K
+
+
+
+
+
Gd),
Hd),
Id),
Jd),
Kd),
append(LSZ,LE,LSZ_E),
append(LSZ_E, Lst,LSZ_E_Lst),
%minimizing
/*30*/
gfd_gac: (max(LE, M)),
/*31*/
bb_min(labeling(LSZ_E_Lst), M, bb_options with
[strategy:continue,from:0,to:100]),
/*32*/
write("End times of tasks = "),write(LE),nl,
/*33*/
write("Minimum cycle time = "),write(M),nl,nl,
/*34*/write("Workstation for A: "),write(Ast),write(", Start A = "),write(A),nl,
/*35*/write("Workstation for B: "),write(Bst),write(", Start B = "),write(B),nl,
/*36*/write("Workstation for C: "),write(Cst),write(", Start C = "),write(C),nl,
/*37*/write("Workstation for D: "),write(Dst),write(", Start D = "),write(D),nl,
/*38*/write("Workstation for E: "),write(Est),write(", Start E = "),write(E),nl,
/*39*/write("Workstation for F: "),write(Fst),write(", Start F = "),write(F),nl,
/*40*/write("Workstation for G: "),write(Gst),write(", Start G = "),write(G),nl,
/*41*/write("Workstation for H: "),write(Hst),write(", Start H = "),write(H),nl,
/*42*/write("Workstation for I: "),write(Ist),write(", Start I = "),write(I),nl,
/*43*/write("Workstation for J: "),write(Jst),write(", Start J = "),write(J),nl,
/*43*/write("Workstation for K: "),write(Kst),write(", Start K = "),write(K),nl.
375
=
1
3
3
2
3
3
4
4
4
4
4
53
Start
Start
Start
Start
Start
Start
Start
Start
Start
Start
Start
A
B
C
D
E
F
G
H
I
J
K
=
=
=
=
=
=
=
=
=
=
=
0
0
15
0
24
39
0
12
24
36
44
Delayed goals:
gfd : gfd_do_propagate(gfd_prob(nvars(35)))
Yes (1258.02s cpu)
376
6.11
Reading newspapers 1
Andy
Ben
Carl
4 The subject has been inspired by the report of [Duncan-90], who quotes French
([French-82]) as the author who originally posed the problem.
5 This is an OST-type problem.
Students
Andy starts
at 8.30 with
reading order:
and duration:
Ben starts
at 8.45 with
reading order:
and duration:
Carl starts
at 8.45 with
reading order:
and duration:
Dusty starts
at 9.30 with
reading order
and duration:
377
Task 1
To
read
MD
60 mins
To
read
DA
75 mins
To
read
MB
5 mins
To
read
GN
90 mins
Task 2
To
read
DA
30 mins
To
read
MB
3 mins
To
read
DA
15 mins
To
read
MD
5 mins
Task 3
To
read
MB
2 mins
To
read
MD
25 mins
To
read
MD
10 mins
To
read
DA
5 mins
Task 4
To
read
GN
5 mins
To
read
GN
10 mins
To
read
GN
30 mins
To
read
MB
5 mins
A :: 30..360,
B :: 45..360,
C :: 45..360,
D :: 105..360,
End :: 90..360,
End_of_Ends :: 90..360,
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
AMD#>=30,
ADA#>=AMD+60,
AMB#>=ADA+30,
AGN#>=AMB+2,
A_end#>=AGN+5,
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
BDA#>=45,
BMB#>=BDA+75,
BMD#>=BMB+3,
BGN#>=BMD+25,
B_end#>=BGN+10,
378
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
CMB#>=45,
CDA#>=CMB+5,
CMD#>=CDA+15,
CGN#>=CMD+10,
C_end#>=CGN+30,
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
DGN#>=105,
DMD#>=DGN+90,
DDA#>=DMD+5,
DMB#>=DDA+5,
D_end#>=DMB+5,
write("A
write("B
write("C
write("D
=
=
=
=
"),write(A),nl,
"),write(B),nl,
"),write(C),nl,
"),write(D),nl,
/*51*/ present_schedule([AMD,ADA,AMB,AGN,BDA,BMB,BMD,BGN,
CMB,CDA,CMD,CGN,DGN,DMD,DDA,DMB],
["Andy","Mainstream Drivel",60,
"Andy","Daily Absurdities",30,
379
"Andy","Morning Brainwasher",2,
"Andy","Gutter News",5,
"Ben","Daily Absurdities",75,
"Ben","Morning Brainwasher",3,
"Ben","Mainstream Drivel",25,
"Ben","Gutter News",10,
"Carl","Morning Brainwasher",5,
"Carl","Daily Absurdities",15,
"Carl","Mainstream Drivel",10,
"Carl","Gutter News",10,
"Dusty","Gutter News",90,
"Dusty","Mainstream Drivel",5,
"Dusty","Daily Absurdities",5,
"Dusty","Morning Brainwasher",5]).
/*52*/ present_schedule([],[]):-nl.
/*53*/ present_schedule([H1|T1],[H21,H22,H23|T2]) :/*54*/
convert_time(H1, FG, FM),
/*55*/
HH is H1+H23,
/*56*/
convert_time(HH, TG, TM),nl,
/*57*/
write(H21),write(" reads "),write(H22),write(" from "),
/*58*/
write(FG),write(":"),write(FM),
/*59*/
write(" to "),write(TG),write(":"),write(TM),
/*60*/ present_schedule(T1,T2).
/*61*/ convert_time(Time,Hours,Minutes) :/*62*/
/*63*/
/*64*/
Hours is G + 8,
mod(Time,60,Minutes).
=
=
=
=
a
a
a
a
a
a
a
a
solution
solution
solution
solution
solution
solution
solution
solution
with
with
with
with
with
with
with
with
cost
cost
cost
cost
cost
cost
cost
cost
338
263
262
257
240
238
235
210
380
As can be seen, the readings nish at 11:25 and then all students may set-o to
the University.
The above message makes for hard reading. It is better presented as Gantt
charts, one for presenting student activities (see Figure 6.8), the other one presenting the reading histories of papers (see Figure 6.9). The color codes for
boxes of the Gantt chart for papers are necessarily dierent from those of the
Gantt chart for students. Sticking to the same color codes would result in all
boxes of the Gantt chart for papers to have the same color for the same paper,
which would be rather uninformative.
It is obvious from those charts that the optimum reading order is not unique:
e.g. reading of MB by Andy, MD by Ben and GN by Carl could start a little
latter with no change to the minimum nal time.
6.12
Reading newspapers 2
The problem could also be solved by a program that uses only the cumulative/4
global constraint, as shown in 6_5_newspapers_2.ecl6:
6 This
is an OST-type problem.
381
382
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_edge_finder3).
/*3*/ :- lib(branch_and_bound).
/*4*/ top:/*5*/ A=[AMD,ADA,AMB,AGN], % reading start times
/*6*/ B=[BDA,BMB,BMD,BGN], % reading start times
/*7*/ C=[CMB,CDA,CMD,CGN], % reading start times
/*8*/ D=[DGN,DMD,DDA,DMB], % reading start times
/*9*/ End=[A_end,B_end,C_end,D_end],
% end of reading times for students
/*10*/
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
for
for
for
for
Andy
Ben
Carl
Dusty
A :: 30..360,
B :: 45..360,
C :: 45..360,
D :: 105..360,
End :: 90..360,
End_of_Ends :: 90..360,
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
AMD#>=30,
ADA#>=AMD+60,
AMB#>=ADA+30,
AGN#>=AMB+2,
A_end#>=AGN+5,
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
BDA#>=45,
BMB#>=BDA+75,
BMD#>=BMB+3,
BGN#>=BMD+25,
B_end#>=BGN+10,
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
CMB#>=45,
CDA#>=CMB+5,
% order constraints for Carl
CMD#>=CDA+15,
CGN#>=CMD+10,
C_end#>=CGN+30,
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
DGN#>=105,
DMD#>=DGN+90,
DDA#>=DMD+5,
DMB#>=DDA+5,
D_end#>=DMB+5,
write("A
write("B
write("C
write("D
=
=
=
=
"),write(A),nl,
"),write(B),nl,
"),write(C),nl,
"),write(D),nl,
/*50*/ present_schedule([AMD,ADA,AMB,AGN,BDA,BMB,BMD,BGN,
CMB,CDA,CMD,CGN,DGN,DMD,DDA,DMB],
["Andy","Mainstream Drivel",60,
"Andy","Daily Absurdities",30,
"Andy","Morning Brainwasher",2,
"Andy","Gutter News",5,
"Ben","Daily Absurdities",75,
"Ben","Morning Brainwasher",3,
"Ben","Mainstream Drivel",25,
"Ben","Gutter News",10,
"Carl","Morning Brainwasher",5,
"Carl","Daily Absurdities",15,
"Carl","Mainstream Drivel",10,
"Carl","Gutter News",10,
"Dusty","Gutter News",90,
"Dusty","Mainstream Drivel",5,
"Dusty","Daily Absurdities",5,
"Dusty","Morning Brainwasher",5]).
/*51*/ present_schedule([],[]):-nl.
/*52*/ present_schedule([H1|T1],[H21,H22,H23|T2]) :/*53*/
convert_time(H1, FG, FM),
/*54*/
HH is H1+H23,
383
384
/*55*/
convert_time(HH, TG, TM),nl,
/*56*/
write(H21),write(" reads "),write(H22),write(" from "),
/*57*/
write(FG),write(":"),write(FM),
/*58*/
write(" to "),write(TG),write(":"),write(TM),
/*59*/ present_schedule(T1,T2).
%% Czasy przedstawiaja minuty po godzinie 08:00
/*60*/ convert_time(Time,Hours,Minutes) :/*61*/
/*62*/
/*63*/
Hours is G + 8,
mod(Time,60,Minutes).
=
=
=
=
a
a
a
a
a
a
a
a
solution
solution
solution
solution
solution
solution
solution
solution
with
with
with
with
with
with
with
with
cost
cost
cost
cost
cost
cost
cost
cost
338
263
262
257
240
238
235
210
385
The reading order is this time slightly dierent from what we got before.
Because of the non-uniqueness of the optimum solution, for the same minimum
nal reading time 11:30 , Andy and Ben swapped their readings of Gutter
News. As can be seen from the Gantt diagrams, this does not violate any
constraint.
6.13
Reading newspapers 3
The way data was introduced in the previous two programs was unwieldy and
and made their change dicult to handle.
Program 6_6_newspapers_3.ecl7 presents a more professional approach to
data declaring; however, the price paid for this is poorer readability. The following important private predicates are used:
data(Data))
Data = [student(Name,Getting_ready_time,Papers)|Rest]
Papers = [Paper,Reading_time|Rest] =
= [Paper_1, Reading_time1,
Paper_2, Reading_time2, etc.]
constrain(Data,Readings,Start_times,End)
Readings = [reading(Name,Paper,Start,Reading_time)|Rest]
constrain_single_paper(Paper,Readings)
constrain_with_accu(Data,Reading_accu,Readings,
Start_times_accu,Start_times,End)
make_reading(Papers,Name,Getting_ready_time,Reading_accu,Readings,
Start_times_accu,Start_times)
collect_papers(Readings,Paper,Start_times_accu,Start_times,
Start_times_accu,Reading_times)
labeling(Start_times,End) - a private labeling predicate
is an OST-type problem.
386
/*1*/ :- lib(ic).
/*2*/ :- lib(ic_edge_finder3).
/*3*/ :- lib(branch_and_bound).
/*4*/ top:/*5*/ data(Data),
/*6*/ constrain(Data,Readings,Start_times,End),
/*7*/ minimize(labeling(Start_times,End),End),
/*8*/ present_schedule(Readings).
%
Getting_ready_time in "Data"
% is given by minutes after 08:00:
/*9*/ data([
student("Andy",30,["MD",60,"DA",30,"MB",2,"GN",5]),
student("Ben",45,["DA",75,"MB",3,"MD",25,"GN",10]),
student("Carl",45,["MB",5,"DA",15,"MD",10,"GN",30]),
student("Dusty",104,["GN",90,"MD",5,"DA",5,"MB",5])]).
/*10*/constrain(Data,Readings,Start_times,End):/*11*/ End :: 0..363,
/*12*/ constrain_with_accu(Data,[],Readings,[],Start_times,End),
/*13*/ constrain_single_paper("MD",Readings),
/*14*/ constrain_single_paper("DA",Readings),
/*15*/ constrain_single_paper("MB",Readings),
/*16*/ constrain_single_paper("GN",Readings).
% Make a series of "readings" for all students:
/*17*/constrain_with_accu([],Readings,Readings,Start_times,
Start_times,_).
/*18*/constrain_with_accu([student(Name,Getting_ready_time,
[Paper,Reading_time|Rest])|Remaining],Reading_accu,
Readings,Start_times_accu,Start_times,End):% Make readings for "Name":
/*19*/ Start :: Getting_ready_time..363,
/*20*/ Next_time is Getting_ready_time + Reading_time,
/*21*/ make_reading(Rest,Name,Next_time,
[reading(Name,Paper,Start,Reading_time)|Reading_accu],
Read1,[Start|Start_times_accu],Start1),
/*22*/ Read1 = [reading(Name,_,S1,D1)|_],
% Make "End" not less than the end_time for the
% last reading of the student. Hence "End" will finally be equal
% to the end of the last reading of the latest student:
/*23*/ End #>= S1+D1,
/*24*/ constrain_with_accu(Remaining,Read1,Readings,Start1,
Start_times,End).
% Make a "reading" for the
student "Name"
387
388
% Present schedule:
/*53*/present_schedule([]).
/*54*/present_schedule([reading(Name,Paper,Start,
Reading_time)|Rest]):/*55*/ convert_time(Start, FH, FM),
/*56*/ HH is Start+Reading_time,
/*57*/ convert_time(HH, TH, TM),
/*58*/ write(Name),write(" reads "),write(Paper),write(" from "),
write(FH),write(":"),write(FM),
/*59*/ write(" to "),write(TH),write(":"),write(TM),nl,
/*60*/ present_schedule(Rest).
% Convert time:
/*61*/convert_time(Time,Hours,Minutes) :/*62*/ div(Time, 60, G),
/*63*/ Hours is G + 8,
/*64*/ mod(Time,60,Minutes).
389
6.14
Assembling bicycles
This is yet another example of scheduling with cumulative and precedence constraints. It was inspired by the distinguished discrete mathematician Ronald
Graham who wrote an enlightened essay on a ctitious bicycle assembly plant
named ACME , see [Graham-78]. This essay will form the basis of an instructive scheduling program; instructive means that it shows the unreliability and
weakness of human intuition even if confronted with a simple scheduling problem. What follows is a large quote from Graham, slightly modied to make the
problem more dicult and interesting:
Things have not been going too well in the assembling section of the ACME
Bicycle Company. For the past six month, the section had consistently failed to
meet its quota and heads were beginning to roll. A newly appointed foreman of
the assembling section has been brought in to remedy this sad state of aairs.
He realizes that this is his big chance the catch the eye of upper management,
so that the rst day on the job he rolls up his sleeves and begins nding out
everything about what goes on in the section.
The rst thing he learns is that the overall job of assembling a bicycle is usually
broken up into a number of specic smaller tasks:
A - Frame preparation which includes installation of the
front fork and fenders.
B - Mounting and aligning front wheel.
C - Mounting and aligning back wheel.
D - Attaching the derailleur to the frame.
E - Installing the gear cluster.
F - Attaching the chain wheel to the crank.
G - Attaching the crank and chain wheel to the frame.
H - Mounting right pedal and toe clip.
I - Mounting left pedal and toe clip.
J - Final attachments which includes mounting and adjusting
390
A
7
B
7
C
7
D
2
E
2
F
2
G
2
H
8
I
8
J
18
must
must
must
must
must
must
be
be
be
be
be
be
done
done
done
done
done
done
before
before
before
before
before
before
J
C
E, F
H, I
G
B
391
also two rules (known locally as busy rules) that management requires to
observe during working hours:
Rule 1: No assembler can be idle if there is some task he or she can be doing.
Rule 2: Once an assembler starts a task, he or she must continue working on
the task until it is completed.
The customary order of assembling bicycles at Acme Bicycles has always
been the following one:
Task
A B C D E F G H I J
Start time
1, 8, 9, 1, 7, 3, 5, 15, 23, 16,
shown in the Gantt chart in Figure 6.10.
The schedule shows the activity of each assembler of the team beginning at
time 1 and progressing to the time of completed assembly, called the overall
assembling time, some 33 minutes latter. Although this schedule obeys all
the required order-of-assembly constraints given above, it allows each team to
complete only 14.5 bicycles per day. Thus the total output of the section is 145
bicycles per day, well under the quota of 152.9.
After wasting numerous pieces of paper trying out various alternative schedules with no success, the foreman decided to ask a well-known CLP specialist for
9 This
392
Unfortunately, the overall assembling time is still over the expected 31.5 minutes. Whats more - Rule 1 has been violated because between job F and job C
an illegal 1-minute long inactivity is found. The foreman wants to eliminate it
by changing the objective function: instead of minimizing the overall assembling
time, the sum of end times for all jobs should be minimized. The CLP specialist
wrote a program called by top2 from 6_7_bicycles.clp. The result is:
Start times = [1, 8,
Durations =
[7, 7,
9,
7,
393
394
8,
7,
1, 3, 3, 5, 7, 15, 15]
2, 2, 2, 2, 8, 8, 18]
395
End times =
[8, 15, 15, 3, 5, 5, 7, 15, 23, 33]
End = 33
Assembling time = 32,
visualized by the Gantt chart from Figure 6.15.
It happens that the minimum assembling time for 3 assemblers is exactly
the same as for two assemblers, see Figure 6.10. The foreman - desperate as
he is - hires another 10 assemblers and decrees that from now on, each of the
10 teams will consists of four assemblers working together. The CLP specialist
warns him again that this will be of no avail and demonstrates that by writing
the top5 part of his program, which generates the schedule:
Start times = [1,
Durations =
[7,
End times =
[8,
End = 33
Assembling time =
8, 8, 1, 3, 3, 5, 7, 7, 15]
7, 7, 2, 2, 2, 2, 8, 8, 18]
15, 15, 3, 5, 5, 7, 15, 15, 33]
32,
396
to the popular All Things to All People political party10 which enthusiastically
commissioned him - because of his industrial expertise - to create a lobbying
service for providing manufacturing industries with nancial bailouts by the
10 A long time ago Alexis de Tocqueville (18051859) remarked in his famous Democracy
in America book that In America there are so many ways of making a living that a man
doesnt usually enter politics until he has failed at everything else. Does it happen only in
America? And only in such remote ages?
397
Absurdoland Government.
The conclusion is that getting more man-power to even such menial job as
bicycle assembling is no guarantee of success. Lets quote [Graham-78] the last
time: One might well ask just where it was that our hypothetical foreman at
ACME Bicycle did go wrong. It will turn out that he was a victim of Rules 1
and 2 (and a little bad luck). The short-sighted greediness resulted, as it often
does, in an overall loss of performance of the system as a whole. In each case,
assemblers were forced (by Rule 1) to start working on jobs that they couldnt
interrupt (by Rule 2) when a more urgent job eventually cam up.
The program 6_7_bicycles.ecl11 is as follows:
/*1*/
/*2*/
/*3*/
:- lib(ic).
:- lib(ic_edge_finder3).
:- lib(branch_and_bound).
/*4*/ top:/*5*/
top1,
/*6*/
top2,
/*7*/
top3,
/*8*/
top4,
/*9*/
top5,
/*10*/
top6.
% Minimizing assembly time for two assemblers:
/*11*/ top1:/*12*/
declare_domains(Start_Times,Resources),
/*13*/
Assembling_Times = [7, 7, 7, 2, 2, 2, 2, 8, 8,18],
/*14*/
End_Times =
[_, _, _, _, _, _, _, _, _, _],
/*15*/
End_Times :: 1..200,
/*16*/
Limit :: 2,
/*17*/
/*18*/
/*19*/
constraints(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*20*/
bb_min(search(Start_Times,0,smallest,indomain_min,
bbs(1),[]),End, bb_options{delta:1,timeout:60}),
/*21*/
/*22*/
/*23*/
Assembling_Time is End - 1,
write("Minimizing assembly time for two assemblers:"),
write_results(Start_Times,Assembling_Times,End_Times,
11 This
is an OST-type problem.
398
End,Assembling_Time).
% Minimizing sum of end times for two assemblers:
/*24*/ top2:/*25*/
declare_domains(Start_Times,Resources),
/*26*/
Assembling_Times = [7, 7, 7, 2, 2, 2, 2, 8, 8, 18],
/*27*/
End_Times =
[K1,K2,K3,K4,K5,K6,K7,K8,K9,K10],
/*28*/
End_Times :: 1..200,
/*29*/
Limit :: 2,
/*30*/
/*31*/
/*32*/
constraints(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*33*/
Sum_of_End_Times #= K1+K2+K3+K4+K5+K6+K7+K8+K9+K10,
/*34*/
bb_min(search(Start_Times,0,smallest,indomain_min,
bbs(1),[]),Sum_of_End_Times, bb_options{delta:1,timeout:60}),
/*35*/
/*36*/
/*37*/
Assembling_Time is End - 1,
write("Minimizing sum of end times for two assemblers:"),
write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time).
% Minimizing sum of end times for two assemblers and power tools:
/*38*/ top3:/*39*/
declare_domains(Start_Times,Resources),
/*40*/
Assembling_Times = [6, 6, 6, 1, 1, 1, 1, 7, 7, 17],
/*41*/
End_Times =
[K1,K2,K3,K4,K5,K6,K7,K8,K9,K10],
/*42*/
End_Times :: 1..200,
/*43*/
Limit :: 2,
/*44*/
/*45*/
/*46*/
constraints_for_power_tools(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*47*/
Sum_of_End_Times #= K1+K2+K3+K4+K5+K6+K7+K8+K9+K10,
/*48*/
bb_min(search(Start_Times,0,smallest,indomain_min,
bbs(1),[]),Sum_of_End_Times, bb_options{delta:1,timeout:60}),
/*49*/
/*50*/
Assembling_Time is End - 1,
write("Minimizing sum of end times for two assemblers
and power tools:"),
write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time).
/*51*/
constraints_for_power_tools(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*61*/
bb_min(search(Start_Times,0,first_fail,indomain,
bbs(1),[]),End, bb_options{delta:1,timeout:60}),
/*62*/
/*63*/
Assembling_Time is End - 1,
write("Minimizing assembly time for two assemblers
and power tools:"),
write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time).
/*64*/
constraints(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*74*/
bb_min(search(Start_Times,0,first_fail,indomain,
bbs(1),[]),End, bb_options{delta:1,timeout:60}),
/*75*/
/*76*/
/*77*/
Assembling_Time is End - 1,
write("Minimizing assembly time for three assemblers:"),
write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time).
399
400
/*83*/
Limit :: 4,
/*84*/
/*85*/
/*86*/
constraints(Start_Times),
cumulative(Start_Times,Assembling_Times,Resources,Limit),
end_times(Start_Times,Assembling_Times,End_Times,
End),
/*87*/
bb_min(search(Start_Times,0,first_fail,indomain,
bbs(1),[]),End, bb_options{delta:1,timeout:60}),
/*88*/
/*89*/
/*90*/
Assembling_Time is End - 1,
write("Minimizing assembly time for four assemblers:"),
write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time).
/*91*/ declare_domains(Start_Times,Resources):/*92*/
Start_Times = [_, _, _, _, _, _, _, _, _, _],
/*93*/
Resources =
[_, _, _, _, _, _, _, _, _, _],
/*94*/
Start_Times :: 1..100,
/*95*/
Resources :: 1.
/*96*/ constraints([A,B,C,D,E,F,G,H,I,J]):/*97*/
A + 7 #=< J,
/*98*/
B + 7 #=< J,
/*99*/
C + 7 #=< J,
/*100*/
D + 2 #=< J,
/*101*/
E + 2 #=< J,
/*102*/
A + 7 #=< C,
/*103*/
D + 2 #=< C,
/*104*/
E + 2 #=< C,
/*105*/
D + 2 #=< E,
/*106*/
D + 2 #=< F,
/*107*/
E + 2 #=< H,
/*108*/
F + 2 #=< H,
/*109*/
G + 2 #=< H,
/*110*/
E + 2 #=< I,
/*111*/
F + 2 #=< I,
/*112*/
G + 2 #=< I,
/*113*/
F + 2 #=< G,
/*114*/
A + 7 #=< B.
/*115*/ constraints_for_power_tools([A,B,C,D,E,F,G,H,I,J]):/*116*/
A + 6 #=< J,
/*117*/
B + 6 #=< J,
/*118*/
C + 6 #=< J,
/*119*/
D + 1 #=< J,
/*120*/
E + 1 #=< J,
/*121*/
A + 6 #=< C,
/*122*/
D + 1 #=< C,
/*123*/
/*124*/
/*125*/
/*126*/
/*127*/
/*128*/
/*129*/
/*130*/
/*131*/
/*132*/
/*133*/
E
D
D
E
F
G
E
F
G
F
A
+
+
+
+
+
+
+
+
+
+
+
1
1
1
1
1
1
1
1
1
1
6
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
401
C,
E,
F,
H,
H,
H,
I,
I,
I,
G,
B.
/*134*/ end_times(Start_Times,Assembling_Times,End_Times,End):/*135*/
( foreach(S,Start_Times),
/*136*/
foreach(D,Assembling_Times),
/*137*/
foreach(K,End_Times)
/*138*/
do
/*139*/
K #= S + D
/*140*/
),
/*141*/
End #= max(End_Times).
/*142*/ write_results(Start_Times,Assembling_Times,End_Times,
End,Assembling_Time):/*143*/
printf("%2n
Start times =
[%d, %d, %d, %d, %d, %d, %d, %d, %d, %d].%n", Start_Times),
/*144*/
printf("
Assembling times =
[%d, %d, %d, %d, %d, %d, %d, %d, %d, %d].%n", End_Times),
/*146*/
printf("
End = %d%2n", End),
/*147*/
printf("
%d%2n", Assembling_Time).
402
8,
1, 3, 3, 5, 7, 7, 15].
6.15
403
:- lib(ic).
:- lib(ic_edge_finder3).
:- lib(branch_and_bound).
/*4*/
top:-
13 This
404
405
D12,D13,D14,D15,D16,D17,D18,D19,D20,D21,D22,
D23,D24,D25,D26,D27,D28,D29,D30,D31,D32,D33,D34],
% List of task manpower requirements - list of number of dockers
% needed to accomplish the tasks:
/*7*/
LR = [R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,
R12,R13,R14,R15,R16,R17,R18,R19,R20,R21,R22,
R23,R24,R25,R26,R27,R28,R29,R30,R31,R32,R33,R34],
% List of task surfaces - list of man-hours needed to accomplish the tasks:
/*8*/
LF = [12,16,12,24,25,10,12,12,12,16,12,
10,4,15,6,9,12,14,4,4,4,8,
28,40,16,3,3,12,8,9,6,3,6,6],
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
LS
:: 1..400,
LD :: 1..40,
LR :: 1..12,
End :: 1..400,
Limit :: 1..12,
/*14*/
cumulative(LS,LD,[R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,
R12,R13,R14,R15,R16,R17,R18,R19,R20,R21,R22,
R23,R24,R25,R26,R27,R28,R29,R30,R31,R32,R33,R34],
LF,Limit),
/*15*/
/*16*/
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
S1 + D1 #=< S2,
S1 + D1 #=< S4,
S2 + D2 #=< S3,
S3 + D3 #=< S5,
S3 + D3 #=< S7,
S4 + D4 #=< S5,
S5 + D5 #=< S6,
S6 + D6 #=< S8,
S7 + D7 #=< S8,
S8 + D8 #=< S9,
S9 + D9 #=< S10,
S9 + D9 #=< S14,
S10 + D10 #=< S11,
S10 + D10 #=< S12,
S11 + D11 #=< S13,
S12 + D12 #=< S13,
S13 + D13 #=< S15,
S13 + D13 #=< S16,
S14 + D14 #=< S15,
S15 + D15 #=< S18,
S16 + D16 #=< S17,
S17 + D17 #=< S18,
S18 + D18 #=< S19,
S18 + D18 #=< S20,
406
/*39*/
/*40*/
/*41*/
/*42*/
/*43*/
/*44*/
/*45*/
/*46*/
/*47*/
/*48*/
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
S18
S19
S20
S21
S22
S23
S24
S25
S25
S25
S25
S26
S27
S28
S29
S30
S31
S32
S33
S34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
D18
D19
D20
D21
D22
D23
D24
D25
D25
D25
D25
D26
D27
D28
D29
D30
D31
D32
D33
D34
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
#=<
S21,
S23,
S23,
S22,
S23,
S24,
S25,
S26,
S30,
S31,
S32,
S27,
S28,
S29,
400,
S28,
S28,
S33,
S34,
400,
maxlist(LK,End),
minimize(labeling(LS,LD,LR),End),nl,
/*75*/
/*76*/
/*77*/
/*78*/
/*79*/ labeling([X1|X],[Y1|Y],[Z1|Z]):/*80*/
indomain(X1),
407
/*81*/
indomain(Y1),
/*82*/
indomain(Z1),
/*83*/
labeling(X,Y,Z).
/*84*/ labeling([],[],[]).
/*85*/ present_results([Sg|Sk],[Dg|Dk],[Rg|Rk],[Kg|Kk],N):/*86*/
printf("%d\t%d\t%d\t%d\t%d\t",[N,Sg,Dg,Rg,Kg]),nl,
/*87*/
N1 is N+1,
/*88*/
present_results(Sk,Dk,Rk,Kk,N1).
/*89*/ present_results([],[],[],[],_).
Dockers
End
1
2
Start Duration
1
2
1
2
12
8
2
4
12
4
5
5
7
2
5
12
5
7
12
6
7
12
7
1
2
10
6
13
9
13
12
14
9
10
14
15
1
2
12
8
15
17
11
17
12
18
12
13
18
19
1
1
10
4
19
20
14
19
22
15
16
22
20
1
3
6
3
23
23
17
18
23
24
1
2
12
7
24
26
19
26
27
408
20
26
27
21
22
26
27
1
1
4
8
27
28
23
28
32
24
25
32
36
4
2
10
8
36
38
26
38
39
27
28
39
40
1
1
3
12
40
41
29
30
41
38
2
1
4
9
43
39
31
39
40
32
33
39
41
1
1
3
6
40
42
34
42
43,
where Start means the time to start the task, Duration is the time needed
to accomplish the task, Dockers is the number of dockers employed for a task
and End is the time the tasks is accomplished. This message is dicult to
understand. Therefore its content is presented as Gantt chart in Figure 6.17.
To check for surface declarations and usage, see e.g. that for task 24 the
number of man-hours is 40; it amounts to 10 dockers working 4 hours.
6.16
What is a job-shop?
The newspaper reading problem from Sections 6.11, 6.12 and 6.13 belongs to
a category of scheduling problems known as job-shop scheduling. It could be
dened as follows: n jobs have to be done, each one consisting of m tasks performed in prescribed order by m machines on the workshop oor. It is assumed
that:
at any time, a machine can perform only one task;
for all tasks on all machines the durations are known;
for all jobs there is a prescribed order of tasks to be performed;
the task performance cannot be interrupted;
any machine is either available or unavailable;
409
Figure 6.17: Gantt chart for optimum unloading and loading of a ship
410
411
where
Mj,i M,
and each one having a known duration:
Tj,1 Dj,1
Tj,2 Dj,2
.......................
Tj,i Dj,i
.......................
Tj,m Dj,m .
Let
T = {1, 2, . . . , i, . . . , m}
be an ordered set of natural numbers corresponding to prescribed order of
tasks. Associating with any element (j, i) of the Cartesian product J T a
pair Mj,i , Dj,i , leads to two functions dening a job-shop problem: a machine
function and a duration function.
For an illustration of these concept the Reader is kindly asked to have another look at Table 6.2, where those two functions were dened for the newspaper reading problem: the rows correspond to student readings (i.e. to jobs),
the columns correspond to reading order (i.e. to a prescribed order of tasks),
and inside each cell of the table names of newspapers to be read (i.e. machines
to be used) and durations of reading them (durations of tasks on those machines) may be found.
Let us return to the general denition. Assume that all n jobs are performed
using all m machines, and forget for a while the precedence constraints. Then
the number of possible schedules is equal (n!)m . It means that, while trying to
solve the problem using exhaustive search, it is necessary to generate all (n!)m
schedules, testing the precedence of tasks and when they are fullled - calculate
the makespan14 .
Table 6.4 demonstrates how quickly the number of schedules increases.
14 It is emphasized that all those schedules have to be generated and tested: one never knows
whether the optimum makespan will occur for the last schedule generated.
412
m machines
1
3
5
n jobs
5
5
5
(n!)m
120
1.7 million
25000 million
6.17
The benchmark MT6 is dened by the table from Figure 6.18. The problem
has 6 jobs that have to be done, each one consisting of 6 tasks, performed
in the order given by task numbers, by 6 machines. It is solved by program
6_13_MT6.ecl:
/*1*/
/*2*/
/*3*/
/*4*/
::::-
/*5*/
top:%
/*5*/
/*6*/
lib(ic).
lib(ic_edge_finder3).
lib(branch_and_bound).
lib(lists).
/*6*/
/*7*/
/*8*/
413
/*21*/
/*22*/
/*23*/
/*24*/
414
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
append(S, E, SE),
maxlist(E, M),
bb_min(grounding(SE), M, bb_options with [strategy:continue,
from:0,to:100]),
write("End of job times = "),write(E),nl,
write("Minimal makespan = "),write(M),nl,nl,
/*38*/
/*39*/
/*40*/
/*40*/
/*41*/
/*42*/
write("
write("
write("
write("
write("
write("
S00="),write(S00),
S01="),write(S01),
S02="),write(S02),
S03="),write(S03),
S04="),write(S04),
S05="),write(S05),nl,
/*43*/
/*44*/
/*45*/
/*46*/
/*47*/
/*48*/
write("
write("
write("
write("
write("
write("
S10="),write(S10),
S11="),write(S11),
S12="),write(S12),
S13="),write(S13),
S14="),write(S14),
S15="),write(S15),nl,
/*49*/
/*50*/
write("
write("
S20="),write(S20),
S21="),write(S21),
/*51*/
/*52*/
/*53*/
/*54*/
write("
write("
write("
write("
S22="),write(S22),
S23="),write(S23),
S24="),write(S24),
S25="),write(S25),nl,
/*55*/
/*56*/
/*57*/
/*58*/
/*59*/
/*60*/
write("
write("
write("
write("
write("
write("
S30="),write(S30),
S31="),write(S31),
S32="),write(S32),
S33="),write(S33),
S34="),write(S34),
S35="),write(S35),nl,
/*61*/
/*62*/
/*63*/
/*64*/
/*65*/
/*66*/
write("
write("
write("
write("
write("
write("
S40="),write(S40),
S41="),write(S41),
S42="),write(S42),
S43="),write(S43),
S44="),write(S44),
S45="),write(S45),nl,
/*37*/
/*68*/
/*69*/
/*70*/
/*71*/
/*72*/
write("
write("
write("
write("
write("
write("
S50="),write(S50),
S51="),write(S51),
S52="),write(S52),
S53="),write(S53),
S54="),write(S54),
S55="),write(S55),nl.
/*73*/ grounding(All_Variables):/*74*/
middle_first(All_Variables, All_VariablesP),
/*75*/
(fromto(All_VariablesP, Variables, VariablesRem, []) do
/*76*/
delete(Variable, Variables, VariablesRem, 0, max_regret),
/*77*/
indomain(Variable, min)
/*78*/
).
/*79*/ middle_first(List, Ord):/*80*/
halve(List, F, B),
/*81*/
reverse(F, RF),
/*82*/
415
416
6.18
417
418
The complexity of MT10 is the reason to rst of all test the existence of a feasible solution. This may be done with the help of program 6_9_mt10_tes.ecl15:
/*1*/
:- lib(ic).
/*2*/
/*3*/
top:S = [S11,S12,S13,S14,S15,S16,S17,S18,S19,S1A,
S21,S22,S23,S24,S25,S26,S27,S28,S29,S2A,
S31,S32,S33,S34,S35,S36,S37,S38,S39,S3A,
S41,S42,S43,S44,S45,S46,S47,S48,S49,S4A,
S51,S52,S53,S54,S55,S56,S57,S58,S59,S5A,
S61,S62,S63,S64,S65,S66,S67,S68,S69,S6A,
S71,S72,S73,S74,S75,S76,S77,S78,S79,S7A,
S81,S82,S83,S84,S85,S86,S87,S88,S89,S8A,
S91,S92,S93,S94,S95,S96,S97,S98,S99,S9A,
SA1,SA2,SA3,SA4,SA5,SA6,SA7,SA8,SA9,SAA],
/*4*/
/*5*/
/*6*/
15 This
E = [E1,E2,E3,E4,E5,E6,E7,E8,E9,EA],
E :: 655..1000,
S :: 0..1000,
is an FS-type problem.
/*7*/
/*9*/
/*11*/
/*13*/
/*15*/
S12
S14
S16
S18
S1A
#>=
#>=
#>=
#>=
#>=
S11+29,
S13+9,
S15+49,
S17+62,
S19+44,
/*8*/
/*10*/
/*12*/
/*14*/
/*16*/
S13
S15
S17
S19
E1
#>=
#>=
#>=
#>=
#>=
S12+78,
S14+36,
S16+11,
S18+56,
S1A+21,
/*17*/
/*19*/
/*21*/
/*23*/
/*25*/
S22
S24
S26
S28
S2A
#>=
#>=
#>=
#>=
#>=
S21+43,
S23+75,
S25+69,
S27+46,
S29+72,
/*18*/
/*20*/
/*22*/
/*24*/
/*26*/
S23
S25
S27
S29
E2
#>=
#>=
#>=
#>=
#>=
S22+90,
S24+11,
S26+28,
S28+46,
S2A+30,
/*27*/
/*29*/
/*31*/
/*33*/
/*35*/
S32
S34
S36
S38
S3A
#>=
#>=
#>=
#>=
#>=
S31+91,
S33+39,
S35+90,
S37+12,
S39+45,
/*28*/
/*30*/
/*32*/
/*34*/
/*36*/
S33
S35
S37
S39
E3
#>=
#>=
#>=
#>=
#>=
S32+85,
S34+74,
S36+10,
S38+89,
S3A+33,
/*37*/
/*39*/
/*41*/
/*43*/
/*45*/
S42
S44
S46
S48
S4A
#>=
#>=
#>=
#>=
#>=
S41+81,
S43+71,
S45+9,
S47+85,
S49+22,
/*38*/
/*40*/
/*42*/
/*44*/
/*46*/
S43
S45
S47
S49
E4
#>=
#>=
#>=
#>=
#>=
S42+95,
S44+99,
S46+52,
S48+98,
S4A+43,
/*47*/
/*49*/
/*51*/
/*53*/
/*55*/
S52
S54
S56
S58
S5A
#>=
#>=
#>=
#>=
#>=
S51+14,
S53+22,
S55+26,
S57+21,
S59+72,
/*48*/
/*50*/
/*52*/
/*54*/
/*56*/
S53
S55
S57
S59
E5
#>=
#>=
#>=
#>=
#>=
S52+6,
S54+61,
S56+69,
S58+49,
S5A+53,
/*57*/
/*59*/
/*61*/
/*63*/
/*65*/
S62
S64
S66
S68
S6A
#>=
#>=
#>=
#>=
#>=
S61+84,
S63+52,
S65+48,
S67+47,
S69+6,
/*58*/
/*60*/
/*62*/
/*64*/
/*66*/
S63
S65
S67
S69
E6
#>=
#>=
#>=
#>=
#>=
S62+2,
S64+95,
S66+72,
S68+65,
S6A+25,
/*67*/
/*69*/
/*71*/
/*73*/
/*75*/
S72
S74
S76
S78
S7A
#>=
#>=
#>=
#>=
#>=
S71+46,
S73+61,
S75+32,
S77+32,
S79+30,
/*68*/
/*70*/
/*72*/
/*74*/
/*76*/
S73
S75
S77
S79
E7
#>=
#>=
#>=
#>=
#>=
S72+37,
S74+13,
S76+21,
S78+89,
S7A+55,
/*77*/
/*79*/
/*81*/
/*83*/
S82
S84
S86
S88
#>=
#>=
#>=
#>=
S81+31,
S83+46,
S85+32,
S87+19,
/*78*/
/*80*/
/*82*/
/*84*/
S83
S85
S87
S89
#>=
#>=
#>=
#>=
S82+86,
S84+74,
S86+88,
S88+48,
419
420
/*85*/
/*86*/
E8
#>= S8A+79,
/*87*/
/*89*/
/*91*/
/*93*/
/*95*/
S92
S94
S96
S98
S9A
#>=
#>=
#>=
#>=
#>=
S91+76,
S93+76,
S95+85,
S97+40,
S99+26,
/*88*/
/*90*/
/*92*/
/*94*/
/*96*/
S93
S95
S97
S99
E9
#>=
#>=
#>=
#>=
#>=
S92+69,
S94+51,
S96+11,
S98+89,
S9A+74,
/*97*/
/*99*/
/*101*/
/*103*/
/*105*/
SA2
SA4
SA6
SA8
SAA
#>=
#>=
#>=
#>=
#>=
SA1+85,
SA3+61,
SA5+64,
SA7+47,
SA9+90,
/*98*/
/*100*/
/*102*/
/*104*/
/*106*/
SA3
SA5
SA7
SA9
EA
#>=
#>=
#>=
#>=
#>=
SA2+13,
SA4+7,
SA6+76,
SA8+52,
SAA+45,
/*107*/
append(S,E,SE),
/*108*/
labeling(SE).
421
ual corrections were introduced for some domains to make them yet smaller.
Obviously, a program tailored that way has no generality at all: any change of
data will require ne tuning of domains. This makeshift brute-force approach
conveys however an important and general principle: the more we know about
the variable domains, and the smaller they can be declared, the quicker solutions
are obtained. The program 6_10_mt10.ecl17 is as follows:
/*1*/
/*2*/
/*3*/
/*4*/
::::-
/*5*/
/*6*/
top:S = [S11,S12,S13,S14,S15,S16,S17,S18,S19,S1A,
S21,S22,S23,S24,S25,S26,S27,S28,S29,S2A,
S31,S32,S33,S34,S35,S36,S37,S38,S39,S3A,
S41,S42,S43,S44,S45,S46,S47,S48,S49,S4A,
S51,S52,S53,S54,S55,S56,S57,S58,S59,S5A,
S61,S62,S63,S64,S65,S66,S67,S68,S69,S6A,
S71,S72,S73,S74,S75,S76,S77,S78,S79,S7A,
S81,S82,S83,S84,S85,S86,S87,S88,S89,S8A,
S91,S92,S93,S94,S95,S96,S97,S98,S99,S9A,
SA1,SA2,SA3,SA4,SA5,SA6,SA7,SA8,SA9,SAA],
%
/*7*/
/*8*/
/*9*/
lib(ic).
lib(ic_edge_finder3).
lib(branch_and_bound).
lib(lists).
/*10*/
/*12*/
/*14*/
/*16*/
/*18*/
S11
S31
S51
S71
S91
::
::
::
::
::
0..605,
0..432,
0..607,
0..584,
0..403,
/*11*/
/*13*/
/*15*/
/*17*/
/*19*/
S21
S41
S61
S81
SA1
::
::
::
::
::
0..490,
0..345,
0..504,
0..461,
0..460,
/*20*/
/*22*/
/*24*/
/*26*/
/*28*/
S12
S32
S52
S72
S92
::
::
::
::
::
29..634,
91..523,
14..621,
46..630,
76..479,
/*21*/
/*23*/
/*25*/
/*27*/
/*29*/
S22
S42
S62
S82
SA2
::
::
::
::
::
43..533,
81..426,
84..588,
31..492,
85..370,
/*30*/
/*32*/
/*34*/
S13 :: 107..712,
S33 :: 176..608,
S53 :: 20..627,
/*31*/
/*33*/
/*35*/
S23 :: 133..628,
S43 :: 176..521,
S63 :: 86..590,
17 This
is an OST-type problem.
422
/*36*/
/*38*/
S73 :: 83..667,
S93 :: 145..548,
/*37*/
/*39*/
S83 :: 117..578,
SA3 :: 98..548,
/*40*/
/*42*/
/*44*/
S14 :: 116..721,
S34 :: 215..647,
S54 :: 42..649,
% correction:
S74 :: 100..450,
S94 :: 221..624,
/*41*/
/*43*/
/*45*/
S24 :: 208..698,
S44 :: 247..592,
S64 :: 138..642,
% correction:
S84 :: 100..450,
SA4 :: 159..619,
/*46*/
/*48*/
/*47*/
/*49*/
/*50*/
/*52*/
/*54*/
/*56*/
/*58*/
S15
S35
S55
S75
S95
::152..757,
::289..721,
::103..710,
::157..741,
::272..675,
/*51*/
/*53*/
/*55*/
/*57*/
/*59*/
S25
S45
S65
S85
SA5
::219..709,
::346..691,
::233..737,
::237..698,
::166..626,
/*60*/
/*62*/
/*64*/
/*66*/
/*68*/
S16
S36
S56
S76
S96
::201..806,
::300..700,
::129..736,
::189..736,
::250..600,
/*61*/
/*63*/
/*65*/
/*67*/
/*69*/
S26
S46
S66
S86
SA6
::288..778,
::355..700,
::281..736,
::269..730,
::230..690,
/*70*/
/*72*/
/*74*/
/*76*/
/*78*/
S17
S37
S57
S77
S97
::
::
::
::
::
/*80*/
/*82*/
/*84*/
/*86*/
/*88*/
212..817,
389..821,
198..805,
210..793,
368..771,
/*71*/
/*73*/
/*75*/
/*77*/
/*79*/
S27
S47
S67
S87
SA7
::
::
::
::
::
316..806,
407..821,
353..857,
357..818,
306..766,
S18 :: 274..879,
S38 :: 401..833,
% correction:
S58 :: 450..800,
S78 :: 242..826,
S98 :: 408..811,
/*81*/
/*83*/
S28 :: 362..852,
S48 :: 492..837,
/*85*/
/*87*/
/*89*/
S68 :: 400..904,
S88 :: 376..837,
SA8 :: 353..813,
/*90*/
/*92*/
/*94*/
/*96*/
/*98*/
S19
S39
S59
S79
S99
::
::
::
::
::
330..935,
490..922,
268..875,
450..800,
497..900,
/*91*/
/*93*/
/*95*/
/*97*/
/*99*/
S29
S49
S69
S89
SA9
::
::
::
::
::
408..898,
590..935,
450..800,
424..885,
405..865,
/*100*/
/*102*/
/*104*/
/*106*/
/*108*/
S1A
S3A
S5A
S7A
S9A
::
::
::
::
::
374..979,
535..967,
340..947,
361..945,
523..921,
/*101*/
/*103*/
/*105*/
/*107*/
/*109*/
S2A
S4A
S6A
S8A
SAA
::
::
::
::
::
480..970,
612..957,
471..975,
460..921,
495..955,
%
%
%
Machine 1 may perform at any time only a single task:
/*110*/
cumulative([S11,S21,S32,S43,S52,S67,S72,S82,S91,SA2],
[29,43,85,71,6,47,37,86,76,13],R,1),
%
Machine 2 may perform at any time only a single task:
/*111*/
cumulative([S12,S26,S31,S41,S53,S62,S71,S83,S92,SA1],
[78,28,91,81,22,2,46,46,69,85],R,1),
/*112*/
cumulative([S13,S22,S34,S42,S51,S61,S74,S81,S95,SA3],
[9,90,74,95,14,84,13,31,85,61],R,1),
/*113*/
cumulative([S14,S25,S33,S48,S55,S64,S73,S8A,S93,SA8],
[36,69,39,98,26,95,61,79,76,52],R,1),
/*114*/
cumulative([S15,S23,S3A,S44,S56,S69,S7A,S85,S99,SA9],
[49,75,33,99,69,6,55,32,26,90],R,1),
/*115*/
cumulative([S16,S28,S36,S4A,S54,S63,S76,S84,S94,SA7],
[11,46,10,43,61,52,21,74,51,47],R,1),
/*116*/
cumulative([S17,S27,S38,S45,S5A,S68,S75,S86,S97,SA4],
[62,46,89,9,53,65,32,88,40,7],R,1),
/*117*/
cumulative([S18,S29,S37,S47,S58,S6A,S79,S89,S98,SAA],
[56,72,12,85,49,25,30,36,89,45],R,1),
/*118*/
cumulative([S19,S2A,S35,S46,S57,S65,S78,S87,S9A,SA5],
[44,30,90,52,21,48,89,19,74,64],R,1),
/*119*/
cumulative([S1A,S24,S39,S49,S59,S66,S77,S88,S96,SA6],
[21,11,45,22,72,72,32,48,11,76],R,1),
%
%
%
/*120*/
/*122*/
/*124*/
/*126*/
/*128*/
S12
S14
S16
S18
S1A
#>=
#>=
#>=
#>=
#>=
S11+29,
S13+9,
S15+49,
S17+62,
S19+44,
/*121*/
/*123*/
/*125*/
/*127*/
/*129*/
S13
S15
S17
S19
E1
#>=
#>=
#>=
#>=
#>=
S12+78,
S14+36,
S16+11,
S18+56,
S1A+21,
/*130*/
/*132*/
/*134*/
/*136*/
/*138*/
S22
S24
S26
S28
S2A
#>=
#>=
#>=
#>=
#>=
S21+43,
S23+75,
S25+69,
S27+46,
S29+72,
/*131*/
/*133*/
/*135*/
/*137*/
/*139*/
S23
S25
S27
S29
E2
#>=
#>=
#>=
#>=
#>=
S22+90,
S24+11,
S26+28,
S28+46,
S2A+30,
/*140*/
/*142*/
/*144*/
/*146*/
/*148*/
S32
S34
S36
S38
S3A
#>=
#>=
#>=
#>=
#>=
S31+91,
S33+39,
S35+90,
S37+12,
S39+45,
/*141*/
/*143*/
/*145*/
/*147*/
/*149*/
S33
S35
S37
S39
E3
#>=
#>=
#>=
#>=
#>=
S32+85,
S34+74,
S36+10,
S38+89,
S3A+33,
423
424
/*150*/
/*152*/
/*154*/
/*156*/
/*158*/
S42
S44
S46
S48
S4A
#>=
#>=
#>=
#>=
#>=
S41+81,
S43+71,
S45+9,
S47+85,
S49+22,
/*151*/
/*153*/
/*155*/
/*157*/
/*159*/
S43
S45
S47
S49
E4
#>=
#>=
#>=
#>=
#>=
S42+95,
S44+99,
S46+52,
S48+98,
S4A+43,
/*160*/
/*162*/
/*164*/
/*166*/
/*168*/
S52
S54
S56
S58
S5A
#>=
#>=
#>=
#>=
#>=
S51+14,
S53+22,
S55+26,
S57+21,
S59+72,
/*161*/
/*163*/
/*165*/
/*167*/
/*169*/
S53
S55
S57
S59
E5
#>=
#>=
#>=
#>=
#>=
S52+6,
S54+61,
S56+69,
S58+49,
S5A+53,
/*170*/
/*172*/
/*174*/
/*176*/
/*178*/
S62
S64
S66
S68
S6A
#>=
#>=
#>=
#>=
#>=
S61+84,
S63+52,
S65+48,
S67+47,
S69+6,
/*171*/
/*173*/
/*175*/
/*177*/
/*179*/
S63
S65
S67
S69
E6
#>=
#>=
#>=
#>=
#>=
S62+2,
S64+95,
S66+72,
S68+65,
S6A+25,
/*180*/
/*182*/
/*184*/
/*186*/
/*188*/
S72
S74
S76
S78
S7A
#>=
#>=
#>=
#>=
#>=
S71+46,
S73+61,
S75+32,
S77+32,
S79+30,
/*181*/
/*183*/
/*185*/
/*187*/
/*189*/
S73
S75
S77
S79
E7
#>=
#>=
#>=
#>=
#>=
S72+37,
S74+13,
S76+21,
S78+89,
S7A+55,
/*190*/
/*192*/
/*194*/
/*196*/
/*198*/
S82
S84
S86
S88
S8A
#>=
#>=
#>=
#>=
#>=
S81+31,
S83+46,
S85+32,
S87+19,
S89+36,
/*191*/
/*193*/
/*195*/
/*197*/
/*199*/
S83
S85
S87
S89
E8
#>=
#>=
#>=
#>=
#>=
S82+86,
S84+74,
S86+88,
S88+48,
S8A+79,
/*200*/
/*202*/
/*204*/
/*206*/
/*208*/
S92
S94
S96
S98
S9A
#>=
#>=
#>=
#>=
#>=
S91+76,
S93+76,
S95+85,
S97+40,
S99+26,
/*201*/
/*203*/
/*205*/
/*207*/
/*209*/
S93
S95
S97
S99
E9
#>=
#>=
#>=
#>=
#>=
S92+69,
S94+51,
S96+11,
S98+89,
S9A+74,
/*210*/
/*212*/
/*214*/
/*216*/
/*218*/
SA2
SA4
SA6
SA8
SAA
#>=
#>=
#>=
#>=
#>=
SA1+85,
SA3+61,
SA5+64,
SA7+47,
SA9+90,
/*211*/
/*213*/
/*215*/
/*217*/
/*219*/
SA3
SA5
SA7
SA9
EA
#>=
#>=
#>=
#>=
#>=
SA2+13,
SA4+7,
SA6+76,
SA8+52,
SAA+45,
%
%
/*219*/
/*220*/
/*221*/
/*222*/
/*223*/
/*224*/
/*225*/
/*226*/
/*227*/
/*228*/
cumulative([S11,S12,S13,S14,S15,S16,S17,S18,S19,S1A],
[29,78,9,36,49,11,62,56,44,21],R,1),
cumulative([S21,S22,S23,S24,S25,S26,S27,S28,S29,S2A],
[43,90,75,11,69,28,46,46,72,30],R,1),
cumulative([S31,S32,S33,S34,S35,S36,S37,S38,S39,S3A],
[91,85,39,74,90,10,12,89,45,33],R,1),
cumulative([S41,S42,S43,S44,S45,S46,S47,S48,S49,S4A],
[81,95,71,99,9,52,85,98,22,43],R,1),
cumulative([S51,S52,S53,S54,S55,S56,S57,S58,S59,S5A],
[14,6,22,61,26,69,21,49,72,53],R,1),
cumulative([S61,S62,S63,S64,S65,S66,S67,S68,S69,S6A],
[84,2,52,95,48,72,47,65,6,25],R,1),
cumulative([S71,S72,S73,S74,S75,S76,S77,S78,S79,S7A],
[46,37,61,13,32,21,32,89,30,55],R,1),
cumulative([S81,S82,S83,S84,S85,S86,S87,S88,S89,S8A],
[31,86,46,74,32,88,19,48,36,79],R,1),
cumulative([S91,S92,S93,S94,S95,S96,S97,S98,S99,S9A],
[76,69,76,51,85,11,40,89,26,74],R,1),
cumulative([SA1,SA2,SA3,SA4,SA5,SA6,SA7,SA8,SA9,SAA],
[85,13,61,7,64,76,47,52,90,45],R,1),
/*229*/
/*230*/
append(S,E,SE),
maxlist(E,M),
/*231*/
/*232*/
/*233*/
write("E = "),write(E),nl,
write("Minimum makespan = "),write(M),nl,nl,
/*234*/
write("S11="),write(S11),write(" S12="),write(S12),
write(" S13="),write(S13),write(" S14="),write(S14),
write(" S15="),write(S15),nl,write("S16="),write(S16),
write(" S17="),write(S17),write(" S18="),write(S18),
write(" S19="),write(S19),write(" S1A="),write(S1A),nl,nl,
/*235*/
write("S21="),write(S21),write(" S22="),write(S22),
write(" S23="),write(S23),write(" S24="),write(S24),
write(" S25="),write(S25),nl,write("S26="),write(S26),
write(" S27="),write(S27),write(" S28="),write(S28),
write(" S29="),write(S29),write(" S2A="),write(S2A),nl,nl,
/*236*/
write("S31="),write(S31),write(" S32="),write(S32),
write(" S33="),write(S33),write(" S34="),write(S34),
write(" S35="),write(S35),nl,write("S36="),write(S36),
write(" S37="),write(S37),write(" S38="),write(S38),
write(" S39="),write(S39),write(" S3A="),write(S3A),nl,nl,
425
426
/*237*/
write("S41="),write(S41),write(" S42="),write(S42),
write(" S43="),write(S43),write(" S44="),write(S44),
write(" S45="),write(S45),nl,write("S46="),write(S46),
write(" S47="),write(S47),write(" S48="),write(S48),
write(" S49="),write(S49),write(" S4A="),write(S4A),nl,nl,
/*238*/
write("S51="),write(S51),write(" S52="),write(S52),
write(" S53="),write(S53),write(" S54="),write(S54),
write(" S55="),write(S55),nl,write("S56="),write(S56),
write(" S57="),write(S57),write(" S58="),write(S58),
write(" S59="),write(S59),write(" S5A="),write(S5A),nl,nl,
/*239*/
write("S61="),write(S61),write(" S62="),write(S62),
write(" S63="),write(S63),write(" S64="),write(S64),
write(" S65="),write(S65),nl,write("S66="),write(S66),
write(" S67="),write(S67),write(" S68="),write(S68),
write(" S69="),write(S69),write(" S6A="),write(S6A),nl,nl,
/*240*/
write("S71="),write(S71),write(" S72="),write(S72),
write(" S73="),write(S73),write(" S74="),write(S74),
write(" S75="),write(S75),nl,write("S76="),write(S76),
write(" S77="),write(S77),write(" S78="),write(S78),
write(" S79="),write(S79),write(" S7A="),write(S7A),nl,nl,
/*241*/
write("S81="),write(S81),write(" S82="),write(S82),
write(" S83="),write(S83),write(" S84="),write(S84),
write(" S85="),write(S85),nl,write("S86="),write(S86),
write(" S87="),write(S87),write(" S88="),write(S88),
write(" S89="),write(S89),write(" S8A="),write(S8A),nl,nl,
/*242*/
write("S91="),write(S92),write(" S92="),write(S92),
write(" S93="),write(S93),write(" S94="),write(S94),
write(" S95="),write(S95),nl,write("S96="),write(S96),
write(" S97="),write(S97),write(" S98="),write(S98),
write(" S99="),write(S99),write(" S9A="),write(S9A),nl,nl,
/*243*/
write("SA1="),write(SA1),write(" SA2="),write(SA2),
write(" SA3="),write(SA3),write(" SA4="),write(SA4),
write(" SA5="),write(SA5),nl,write("SA6="),write(SA6),
write(" SA7="),write(SA7),write(" SA8="),write(SA8),
write(" SA9="),write(SA9),write(" SAA="),write(SAA),nl.
/*244*/ my_labeling(All_Variables):/*245*/
middle_first(All_Variables,All_VariablesP),
/*246*/
( fromto(All_VariablesP, Variables, VariablesRem, []) do
/*247*/
delete(Variable, Variables, VariablesRem, 0, max_regret),
/*248*/
indomain(Variable,min)
/*249*/
).
427
/*250*/ middle_first(List,Ord):/*251*/
/*252*/
halve(List,F,B),
reverse(F,RF),
/*253*/
splice(B,RF,Ord).
S12=445
S17=645
S13=523
S18=721
S14=532
S19=792
S15=568
S1A=887
S32=408
S37=709
S33=493
S38=753
S34=532
S39=842
S35=609
S3A=887
S52=256
S57=499
S53=286
S58=530
S54=308
S59=593
S55=370
S5A=842
S82=275
S87=699
S83=399
S88=718
S84=445
S89=777
S85=519
S8A=813
S91=217
S96=506
S92=217
S97=517
S93=294
S98=579
S94=370
S99=668
S95=421
S9A=718
SA1=132
SA2=262
SA3=327
SA4=388
SA5=420
SA6=517
SA7=628
SA8=735
SA9=787
SAA=885
428
Figure 6.22: Machine coloring codes for the jobs Gantt chart
Figure 6.24: Job coloring codes for the machines Gantt charts
429
430
Figure 6.21 is the Gantt chart for jobs, with Figure 6.22 explaining the colour
coding for machines.
On Figure 6.21 it may be dicult to spot task 2 for job 6, because - as
follows from line /*170*/ of the program, he duration of this task is equal 2,
and this cannot be properly shown for the scale used. The meaning of Figure
6.21 is obvious. E.g. for job 4 the consecutive tasks are the tasks performed
by the: light-green machine (machine 2), light-blue machine (machine 3), red
machine (machine 1) etc. etc.
In order to make the Gantt chart for machines communicative, the color
coding used for the job Gantt chart cannot be used any longer: otherwise all
boxes in a row will be of the same color. Figure 6.23 is the Gantt chart for
machines and Figure 6.24 shows the color coding used for jobs18 .
The meaning of Figure 6.23 is as follows, e.g. the red box for machine 1 corresponds to task 1 for job 1 in Figure 6.21 (also a red box ), the red box formachine
2 corresponds to task 2 from job 1 in Figure 6.21 (light-green box ), the red box
(quite narrow) for machine 3 corresponds to task 3 of job 1 in Figure 6.21,
depicted by an also rather narrow light-blue box, etc. etc.
Scheduling problems are rightly considered to belong to the most dicult
combinatorial decision problems. They are ubiquitous. There is hardly any
human activity where they may not be found. They are important as being one
of the tools to control cost and time. Sometimes they may be of exorbitant size:
the Viking NASA mission to Mars is believed to be based on scheduling activities of over 20.000 people. The techniques to solve them evolved considerably
over time, starting with classical, often heuristic approaches (see [Muth-63]),
but still used (see e.g. [Baker-09]), to constraint programming techniques, see
[Baptiste-95] and [Baptiste-01].
6.19
431
strong combinatorial explosion, or - as theoreticians prefer to call it - is NPhard : the second city may be chosen in n 1 ways, the third city in n 2
ways, so for the second and third cities we have (n 1) (n 2) choices, added
the fourth city we arrive at (n 1) (n 2) (n 3) choices etc. So any
attempt to solve the problem by exhaustive search requires generally (i.e. while
between cities i and j is a dierent distance than between cities j and i) (n1)!
distance evaluations, which seems practical for no more than 10 cities. However,
a large number of heuristics and exact methods are known at present (most of
them utilizing parallel computations), which solve TSP instances with tens of
thousands of cities.
6.19.1
Hamiltonian circuits
432
To sharpen the concept, Figure 6.26 presents a graph that is not a Hamiltonian circuit: the destination node list is not a permutation of the starting node
list.
Figure 6.26: A graph that is not a Hamiltonian circuit for nodes 1,2,3,4,5,6,7.
The program 6_11_hamilton.ecl19 may be used to verify the nature of
both graphs using the built-in circuit/1:
/*1*/
:-lib(ic).
/*2*/ top:/*3*/
circuit([2, 3, 4, 5, 6, 7, 1]),
/*4*/
~(circuit([2, 3, 5, 5, 6, 7, 1])).
% ~Goal is the sound negation operator, which delays if +Goal is not grounded.+
/*5*/ circuit(DestinationNodeList):/*6*/
length(DestinationNodeList,NodeCount),
/*7*/
dim(DestinationNodeArray,[NodeCount]),
/*8*/
DestinationNodeArray=..[[]|DestinationNodeList],
/*9*/
(
/*10*/
count(StartingNodeNr,1,NodeCount),
/*11*/
param(DestinationNodeArray,NodeCount)
/*12*/
do
/*13*/
arg(StartingNodeNr,DestinationNodeArray,DestinationNode),
/*14*/
CycleLength is NodeCount -2 ,
/*15*/
(
/*16*/
count(_,1,CycleLength),
/*17*/
fromto(DestinationNode,DestinationNodeIn,DestinationNodeOut,_),
19 This program and the program dening the built-in circuit/1 that forces a Hamiltonian
cycle in a directed graph, has been proposed by L
ukasz Domagala.
/*18*/
/*19*/
/*20*/
param(StartingNodeNr,DestinationNodeArray)
do
arr_element(DestinationNodeIn, DestinationNodeArray,
DestinationNodeOut),
DestinationNodeOut #\= StartingNodeNr
)
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
433
).
arr_element(Index,Array,Value):(
/*26*/
ground(Index)->
/*27*/
/*28*/
arg(Index,Array,Value)
;
/*29*/
suspend(
/*30*/
/*31*/
arg(Index,Array,Value),
0,
/*32*/
/*33*/
[Index->inst],
_ThisSusp
/*34*/
/*35*/
).
6.19.2
The TSP has several applications that seem far removed from the original salesman problem. They are to be found in planning and scheduling various production installations, in the manufacture of microchips and even in DNA sequencing. In these applications, the concept city (or more generally - node) represents,
for example, installation set-ups, soldering points, or DNA fragments, and the
concept distance represents set-up times or set-up costs, or a similarity measure
between DNA fragments.
To start with a small-size problem, an installation set-up will be considered
rst. A process line may manufacture any of 7 types of gasoline, provided it
is properly set-up. The set-up time depends upon the sequence in which these
fuels are produced. In a full production cycle, during which one batch is devoted
to each product, the amount of non-productive time (the set-up time)is given
by Table 6.520 .
20 The
example was inspired by a simpler one presented by [Baker-09]. There it was solved
434
Gasoline
Diesel 1
Regular 2
Premium 3
Ethanol_5% 4
Racing 5
Unleaded 6
Aviation 7
1
0
20
47
38
46
40
30
2
30
0
88
43
39
11
45
3
67
88
0
62
32
20
37
4
50
43
42
0
41
59
40
5
60
39
32
41
0
52
19
6
70
11
20
59
52
0
55
7
90
74
47
57
29
69
0
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
/*12*/
/*13*/
element(X1,
element(X2,
element(X3,
element(X4,
element(X5,
element(X6,
element(X7,
[ 0,
[20,
[47,
[38,
[46,
[40,
[30,
/*14*/
/*15*/
/*16*/
circuit(DestinationNodeList),
Sum_of_setup_times #= C1+C2+C3+C4+C5+C6+C7,
SearchGoal=search(DestinationNodeList, 0, most_constrained,
30,
0,
88,
43,
39,
11,
45,
67,
88,
0,
62,
32,
20,
37,
50,
43,
42,
0,
41,
59,
40,
60,
39,
32,
41,
0,
52,
19,
70,
11,
20,
59,
52,
0,
55,
90],
74],
47],
57],
29],
69],
0],
C1),
C2),
C3),
C4),
C5),
C6),
C7),
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
435
: [1, 2, 3, 4, 5, 6, 7]
436
6.19.3
Scheduling a salesman
Consider the problem of optimal scheduling a salesman visiting all 16 Absurdolands district capitals. For this problem the approach used in the already
presented example 6_12_TSP_small.ecl turns out to be hopelessly inecient.
This is mostly due to the bad propagation properties of the element/3 predicate.
A more ecient solution is given by program 6_13_TSP_large.ecl22, where
the module circuit.ecl has been evoked once more, but where no element/3
built-ins where used to dene the geometry of places to be visited. The program
6_13_TSP_large.eclis as follows :
/*1*/
/*2*/
/*3*/
/*4*/
%
%
%
%
%
:-use_module(circuit).
:-lib(ic).
:-lib(branch_and_bound).
:-lib(ic_global).
/*5*/
/*6*/
22 This
distance_matrix(Distance_matrix):Distance_matrix=[](
is an OST-type problem.
14 15 16
% Starting
% district
% capitals:
/*7, 1*/
[]( 0,384,484,214,234,267,524,656,446,371,459,561,585,683,634,751),
/*8, 2*/
[](384, 0,156,411,296,167,339,379,340,432,485,545,483,500,565,642),
/*9, 3*/
[](484,156, 0,453,323,217,213,223,281,442,452,479,394,370,500,516),
/*10, 4*/
[](214,411,453, 0,130,259,413,601,303,157,245,356,422,542,427,585),
/*11, 5*/
[](234,296,323,130, 0,129,310,491,212,178,261,335,354,465,403,517),
/*12, 6*/
[](267,167,217,259,129, 0,255,389,205,265,318,391,348,421,430,516),
/*13, 7*/
[](524,339,213,413,310,255, 0,188,134,344,319,297,181,161,295,303),
/*14, 8*/
[](656,379,223,601,491,389,188, 0,322,532,507,485,363,260,477,430),
/*15, 9*/
[](446,340,281,303,212,205,134,322, 0,204,181,196,143,242,220,306),
/*16, 10*/
[](371,432,442,157,178,265,344,532,204, 0, 86,199,300,428,268,433),
/*17, 11*/
[](459,485,452,245,261,318,319,507,181, 86, 0,113,220,382,182,347),
/*18, 12*/
[](561,545,479,356,335,391,297,485,196,199,113, 0,156,323, 75,244),
/*19, 13*/
[](585,483,394,422,354,348,181,363,143,300,220,156, 0,167,114,163),
/*20, 14*/
[](683,500,370,542,465,421,161,260,242,428,382,323,167, 0,269,170),
/*21, 15*/
[](634,565,500,427,403,430,295,477,220,268,182, 75,114,269, 0,165),
/*22, 16*/
[](751,642,516,585,517,516,303,430,306,433,347,244,163,170,165, 0)
/*23*/
).
/*24*/
/*25*/
/*26*/
437
top:distance_matrix(Distance_matrix),
dim(Distance_matrix,[CityCount,CityCount]),
%
%
/*27*/
/*28*/
/*29*/
%
%
/*30*/
%
/*31*/
%
/*32*/
/*33*/
%
/*34*/
%
/*35*/
/*36*/
/*37*/
/*38*/
(foreach(DestinationCity,DestinationCityList),
construct a distance array and distance list for pairs
StartingCity - DestinationCity:
count(StartingCity,1,CityCount),
construct a list of all distances:
foreach(Distance,DistanceList),
construct a list of all starting city numbers:
foreach(StartingCity,StartingCityList),
param(Distance_matrix) do
Destination city must be different from starting city:
DestinationCity#\=StartingCity,
The distance between starting city and destination city:
arg(StartingCity,Distance_matrix,DistanceArray),
DistanceArray=..[[]|DistanceList],
element(DestinationCity, DistanceList, Distance)
),
438
%
/*39*/
%
%
%
/*40*/
%
/*41*/
/*42*/
circuit(DestinationCityList),
/*43*/
SearchGoal=search(DestinationCityList, 0, most_constrained,
indomain_split, complete, []),
BBOptions=bb_options{strategy:dichotomic, timeout:_},
bb_min(SearchGoal, SumOfDistances, BBOptions),
/*44*/
/*45*/
/*46*/
/*47*/
/*48*/
The program solves the problem in 1.75 seconds and generates the message:
Found a solution with cost 3928
Found a solution with cost 3021
Found a solution with cost 2565
Found no solution with cost 2130.0 .. 2347.5
Found no solution with cost 2347.5 .. 2456.25
Found no solution with cost 2456.25 .. 2510.625
Found a solution with cost 2521
Found no solution with cost 2510.625 .. 2515.8125
Found no solution with cost 2515.8125 .. 2518.40625
Found no solution with cost 2518.40625 .. 2519.703125
Found no solution with cost 2519.703125 .. 2520.3515625
Overall distance = 2521
Starting capitals:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Destination capitals:[4, 6, 2,10, 1, 5, 8, 3, 7, 11, 12, 15, 9, 13, 16, 14]
Search time = 1.75
439
Figure 6.28: Hamiltonian circuit for the TSP solution for Absurdolands district
capitals.
:-use_module(distance_matrix).
:-lib(ic).
:-lib(branch_and_bound).
:-lib(cycle).
/*5*/ top:/*6*/
distance_matrix(Distance_matrix),
/*7*/
dim(Distance_matrix,[CityCount,CityCount]),
/*8*/
length(DestinationCityList,CityCount),
/*9*/
DestinationCityList#::1..CityCount,
23 This
24 This
440
/*10*/
cycle(DestinationCityList,Distance_matrix,SumOfDistances),
/*11*/
/*11*/
/*12*/
/*13*/
/*14*/
cputime(StartTime),
SearchGoal=search(DestinationCityList, 0, most_constrained,
indomain_max, complete, []),
bb_min(SearchGoal, SumOfDistances, bb_options{strategy:dichotomic}),
cputime(EndTime),
SearchTime is EndTime - StartTime,
/*15*/
/*16*/
/*17*/
/*18*/
11,12,13,14,15,16]),
This time the program solves the problem in in shorter time (0.906) seconds
and generates the message:
Found a solution with cost 4914
Found a solution with cost 3701
Found a solution with cost 3072
Found a solution with cost 2781
Found a solution with cost 2644
Found a solution with cost 2521
Overall distance = 2521
Starting capitals =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Destination capitals = [4, 6, 2,10, 1, 5, 8, 3, 7, 11, 12, 15, 9, 13, 16, 14]
Search time = 0.906
6.20 Appendices
6.20
441
Appendices
6.20.1
/*1*/
/*2*/
/*3*/
:- module(circuit).
:- export(circuit/1).
:- lib(ic).
/*4*/ circuit(DestinationNodeList):/*5*/
length(DestinationNodeList,NodeCount),
/*6*/
dim(DestinationNodeArray,[NodeCount]),
/*7*/
DestinationNodeArray=..[[]|DestinationNodeList],
/*8*/
(
/*9*/
count(StartingNodeNr,1,NodeCount),
/*10*/
param(DestinationNodeArray,NodeCount)
/*11*/
do
/*12*/
arg(StartingNodeNr,DestinationNodeArray,DestinationNode),
/*13*/
CycleLength is NodeCount -2 ,
/*14*/
(
/*15*/
count(_,1,CycleLength),
/*16*/
fromto(DestinationNode,DestinationNodeIn,
DestinationNodeOut,_),
/*17*/
param(StartingNodeNr,DestinationNodeArray)
/*18*/
do
/*19*/
arr_element(DestinationNodeIn, DestinationNodeArray,
DestinationNodeOut),
/*20*/
DestinationNodeOut #\= StartingNodeNr
/*21*/
)
/*22*/
).
/*23*/
arr_element(Index,Array,Value):-
/*24*/
/*25*/
/*26*/
ground(Index)->
arg(Index,Array,Value)
/*27*/
/*28*/
/*29*/
suspend(
arg(Index,Array,Value),
/*30*/
/*31*/
0,
[Index->inst],
/*32*/
_ThisSusp
442
/*33*/
/*34*/
).
6.20.2
/*1*/
:- module(distance_matrix).
/*2*/ :- export(distance_matrix/1).
/*3*/ :- lib(ic).
/*4*/
/*5*/
distance_matrix(Distance_matrix):Distance_matrix=[](
[](
0,384,484,214,234,267,524,656,446,371,459,561,585,683,634,751),
[](384, 0,156,411,296,167,339,379,340,432,485,545,483,500,565,642),
[](484,156, 0,453,323,217,213,223,281,442,452,479,394,370,500,516),
[](214,411,453, 0,130,259,413,601,303,157,245,356,422,542,427,585),
[](234,296,323,130, 0,129,310,491,212,178,261,335,354,465,403,517),
[](267,167,217,259,129,
0,255,389,205,265,318,391,348,421,430,516),
[](524,339,213,413,310,255, 0,188,134,344,319,297,181,161,295,303),
[](656,379,223,601,491,389,188, 0,322,532,507,485,363,260,477,430),
[](446,340,281,303,212,205,134,322,
0,204,181,196,143,242,220,306),
[](371,432,442,157,178,265,344,532,204, 0, 86,199,300,428,268,433),
[](459,485,452,245,261,318,319,507,181, 86, 0,113,220,382,182,347),
[](561,545,479,356,335,391,297,485,196,199,113, 0,156,323, 75,244),
[](585,483,394,422,354,348,181,363,143,300,220,156, 0,167,114,163),
[](683,500,370,542,465,421,161,260,242,428,382,323,167,
0,269,170),
6.21
Exercises
Simple scheduling
There are 4 identical machines, on which seven tasks should be performed
with durations given in Table 6.625 . Write a program for a minimum
makespan schedule provided there are no precedence constraints among
tasks.
25 This
6.21 Exercises
443
Task
Duration
1
3
2
3
3
3
4
1
5
1
6
1
7
4
Task
Ta1
Ta2
Tb1
Tb2
Tb3
Tc
Td1
Td2
Machine
M1
M2
M2
M1
M2
M2
M1
M2
Duration
2
6
5
3
3
4
5
2
444
Task
Release time
Duration
Delivery time
1
0
2
5
2
2
1
2
3
3
2
6
4
0
3
3
5
6
2
1
Duration
6
8
4
4
4
12
14
6
8
16
2
12
Predecessors
A
A
B,E
B,E
B,C,E
D,F
D,F,G
D,F,G
H,K
Resource requirement
2
3
3
4
2
3
1
4
2
1
1
3
6.21 Exercises
445
x
1
3
5
7
8
y
2
1
3
2
3
Hole
1
2
3
4
5
Due date
End of day 8
End of day 4
End of day 12
End of day 16
446
Job
number
1
2
3
Job duration
(in days)
5
20
15
Due date
(in days)
End of day 25
End of day 20
End of day 35
Late penalty
(in MU/day)
19
12
34
Chapter 7
All examples discussed so far were for discrete variables. The search trees were
of nite depth and the state spaces had a nite number of points, which could
be explored state after state, to search for feasible states.
ECLi P S e provides also tools for solving constraint satisfaction problems
and constraint optimization problems for continuous variables, i.e. variables
having continuous domains, like e.g. 0 X 150;
1. A continuous constraint satisfaction problem (CCSP) is dened by:
a nite set S of continuous decision variables X1 , ..., Xn , with values
from continuous domains D1 , ..., Dn , where Di = M axi Xi M ini ,
{<, , =};
a set of constraints between variables. The constraint Ci (Xi1 , ..., Xik )
between k variables from S is given by a relation dened as subset of
the Cartesian product Di1 , ..., Dik that determines variable values corresponding to each other in a sense dened by the problem.
Constraints for continuous variables are most often stated by means
of equations and inequalities.
447
448
Continuous domains would make the search tree innitely deep if the approach used for discrete domains as we know it from Chapters 2,..., 6
would be applied. To avoid this, the depth of search trees is limited by using constraint propagation methods that successfully narrow the variable
domains, e.g. for some initial domain 10 X 90 the next domain may
be 5 X 65, etc. Such narrowing never results in a single value, but in
a comparatively narrow domain. Therefore the results obtained have the
form:
X = Lower_bound__Upper_bound,
e.g.:
X = 36345.099404108__36345.099448266.
So bounded real results are written as two oating point bounds separated
by a double underscore__. They may also be written as:
X{Lower_bound .. Upper_bound}
e.g.:
X{36345.099404108 .. 36345.099448266},
with two oating point bounds separated by a double full stop ... The
apparatus needed to accomplish this is known as interval arithmetic 1 . So
a CCSP solution is given by any assignment of domain subintervals to
variables so that all constraints are satised. It may be non-unique or
unique. As for discrete CSP, CCSPs may be divided into feasible state
determination problems and feasible trajectory determination problems.
For CCSP problems there is no need to evoke the eplex library, the library
ic being just right. However, symbols of arithmetic operations and relations for continuous variables have to be prexed by $.
1 Interval arithmetic - as contrasted with normal arithmetic - deals with arithmetic operations on intervals. The result of arithmetic interval operations is not given by some set of
state variable values, but by some set of state variable intervals.
449
7.2
7.2.1
450
7.2.2
List = [PV,T,I],
List :: 0.0..1000000.0,
T $= 24,
% Number of periods
I $= 8/100, % Interest rate per period
PV $= 1000, % Initial prinicple
compound_interest(PV,T,I).
/*9*/ compound_interest(PV,T,I):/*10*/
T $>= 1,
% There are still some periods of payments,
/*11*/
NT $= T-1, % but each period it is one period less.
/*12*/
FV $= PV + (PV * I), % Updated principle
/*13*/
compound_interest(FV,NT,I).
/*14*/ compound_interest(FV,T,_):- %
/*15*/
/*16*/
T $= 0,
write("Future Value = "),write(FV), nl.
451
Principle = 6341.18073133441__6341.18073724012
So the domain of the variable Principle has been reduced to a suitably small
interval.
7.2.3
To retire as millionaire - 1
Consider the following example: assume that while being 20 years old we decided to retire at 65 being a millionaire. How large should the initial (and only)
deposit be at our personal account with a yearly compounded interest of 6% to
achieve this goal?
The solution is given by program 7_2_millionaire_1.ecl3 :
/*1*/
:- lib(ic).
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
T $= 0.0,
/*16*/
K $= 1000000.
is an FS-type problem.
452
7.2.4
To retire as millionaire - 2
Assume now that we cant aord to make a deposit of 72650 MU at the age
of 20, but in order to retire as millionaire at 65 we will deposit each year for
45 years a xed amount on our personal account with a yearly compounded
interest of 6%. How large must that yearly deposit be?
This is settled by program 7_3_millionaire_2.ecl5:
/*1*/
:- lib(ic).
/*2*/ top:/*3*/
LD = [K,T,I,R],
/*4*/
LD :: 0.0..1000000,
/*5*/
K $= 0.0,
% Initial state of pensioners account
/*6*/
T $= 45.0, % Number of saving years
/*7*/
I $= 6/100, % Interest rate per year
/*8*/
R =< 4701, % Yearly payment
/*9*/
pension(K,T,I,R),
/*10*/
write("Yearly payment = "), write(R), nl.
/*11*/ pension(K,T,I,R):/*12*/
T $>= 1.0,
/*13*/
NK $= K + (K * I) + R, % New state of pensioners account
/*14*/
NT $= T-1, % Yearly decrease of saving years
/*15*/
pension(NK, NT,I,R).
/*16*/ pension(K,T,_,_):/*17*/
T $= 0.0,
/*18*/
K $= 1000000.0.
The private predicate pension(K,T,I,R) has - compared with the version from
Section 7.2.3 - one more argument. This is the yearly payment R that according
4 Of
5 This
453
to line /*13*/ augments yearly our account. Because the problem is nonlinear,
ECLi P S e has to be helped by a trial and error determination of the bound in
line /*8*/.
The message generated is:
Yearly payment = _11419{4696.74977810691 .. 4701.0}
The variable _11419 is an internal variable used by ECLi P S e to store the nal
result. Rounding up a little bit, the yearly deposit is between 4696.75 and
4701.0. So depositing yearly 4701 MU, which corresponds roughly to 392 MU
per month, we could retire after 45 years of toil having at our pensioners account
one million of MU6 .
Notice that your overall payments would be this time 45 4701 = 211545,
which is roughly three times as much as for the one-time deposit from Section
7.2.3.
7.2.5
We got a mortgage to be payed for the next 24 years, the yearly payment being 12000 MU, the mortgage being at yearly interest 8%7 . How large was the
mortgage we got? What is the price of this mortgage? This will be claried by
program 7_4_mortgage.ecl8:
/*1*/
:- lib(ic).
/*2*/ top:/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*10*/
/*11*/
List = [K,T,I,R],
List :: 0.0..1000000.0,
T $= 24.0,
% Number of paying years
I $= 8/100,
% Interest rate per year
R $= 12000.0,
% Yearly mortgage payments
mortgage(K,T,I,R),
Cost $= T * R,
write("Principle = "),write(K),nl,
write("Cost of mortgage = "),write(Cost),nl.
6 It would be really nice if governments stopped looking after our well-fare and stopped
being good to us.
7 Being young, healthy and having a secure academic employment, we surly can aord a
mortgage like this!
8 This is an FS-type problem.
454
/*12*/ mortgage(K,T,I,R):/*13*/
T $>= 1.0, % There are still some years of payments,
/*14*/
NT $= T-1, % but each year it is one year less.
/*15*/
NK $= K + (K * I) - R, % Updated principal or amount of loan
/*16*/
mortgage(NK,NT,I,R).
/*17*/ mortgage(K,T,_,_):/*18*/
T $= 0,
/*19*/
K $= 0.
7.2.6
While making business it is sometimes worthwhile to remember lost opportunities. Lost, because we could not engage in them just because of this business.
But in order to make a true balance of what has been gained (or lost), we better
take those lost opportunities into account. This is done by a concept known
as Net Present Value (NPV), which is estimating our future gains (or loses) in
terms of its present values, while considering the most likely (and most certain)
lost opportunity. The basic fact underlying NPV is that the value of money
changes in time because it may be invested and bring prot. So some m MU
gained (or lost) a year from now have a dierent present value, equal to:
m
,
(1 + r)
referred to as Net Present Value of those m MU gained (or lost) a year from now.
m
MU invested now will yield (with certainty) m MU a year
This means that (1+r)
455
later, r being the annual rate of return (or discount rate) . The words with
certainty mean that there is a market commodity (e.g. government bonds)
guaranteeing an annual rate of return equal to r. A simple extension fo this
m
reasoning shows that (1+r)
k MU invested now will yield (with certainty) m MU
k years later. The concept is readily generalized to any future cash ows, and
therefore is used for comparing the desirability of dierent investments. Lets
consider the following example of two investments:
1. Investment A requires a cash outlay of 8 million MU at time 0, will yield
a return of 26 million MU a year from now and requires yet another cash
outlay of 18 million MU two years from now in order to clear some environmental damage due to our business activities. The net cash ow for
this investment is:
8 + 26 18 = 0,
and that looks rather discouraging. Suppose there are government bonds
guaranteeing an annual rate of return equal to 0.25. This makes the NPV
of our investment equal to:
8 +
18
26
and that is not so bad, because it means investment A will increase the
companys value expressed in time 0 by 1.2 million MU.
2. Investment B requires a cash outlay of 6 million MU at time 0, will yield
a return of 8 million MU a year from now and requires yet another cash
outlay of 18 million MU two years from now in order to clear some environmental damage due to our business activities. The net cash ow for
this investment is:
6 + 8 1 = 1,
however its NPV is
6 +
8
1
So investment B, in spite of the positive cash ow, will decrease the companys value expressed in time by 0 by 0.25 million MU.
456
Inv. 1
11
3
13
Inv. 2
53
6
10
Inv. 3
5
5
16
Inv. 4
5
1
14
Inv. 5
29
14
39
% time 0 constraint
% time 1 constraint
/*12*/
/*13*/
/*14*/
/*15*/
(foreach(Name,["X1","X2","X3","X4","X5"]),
foreach(V, Variables) do
9 This
457
/*16*/
/*17*/
/*18*/
write(Name),write(" = "),write(V),nl),
write("Profit = "),write(Profit).
X2 = 0.200859950859951
X3 = 1.0
X5 = 0.288083538083538
X4 = 1.0
Profit = 57.4490171990172
7.3
Warehouses - suppliers
is an OS-type problem.
458
/*1*/ :- lib(eplex).
/*2*/ top :/*3*/
solve(_,_).
/*4*/ solve(Cost,Variables):% Declaring variables and their domains:
/*5*/
Variables = [Delivery_1_1,Delivery_2_1,Delivery_3_1,
Delivery_1_2,Delivery_2_2,Delivery_3_2,
Delivery_1_3,Delivery_2_3,Delivery_3_3,
Delivery_1_4,Delivery_2_4,Delivery_3_4],
/*6*/
Variables $:: 0.0..1.0Inf,
/*7*/
% (integers(Variables)),
/*8*/
Cost_1_1 is 6.5,
/*9*/
Cost_1_2 is 2,
/*10*/
Cost_1_3 is 6.3,
/*11*/
Cost_1_4 is 7.3,
/*12*/
Cost_2_1 is 4,
/*13*/
Cost_2_2 is 9.7,
/*14*/
Cost_2_3 is 5.2,
/*15*/
Cost_2_4 is 3,
/*16*/
Cost_3_1 is 5.8,
/*17*/
Cost_3_2 is 2.4,
/*18*/
Cost_3_3 is 1.7,
/*19*/
Cost_3_4 is 9,
/*20*/
Capacity_1 is 60,
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
% Contract
/*27*/
Capacity_2 is 55,
Capacity_3 is 51,
Contract_1 is 35.5,
Contract_2 is 37,
Contract_3 is 22.7,
Contract_4 is 32,
constraints for clients:
Delivery_1_1 + Delivery_2_1
Contract_1,
/*28*/
Delivery_1_2 + Delivery_2_2
Contract_2,
/*29*/
Delivery_1_3 + Delivery_2_3
Contract_3,
/*30*/
Delivery_1_4 + Delivery_2_4
Contract_4,
% Space constraints for warehouses:
/*31*/
Delivery_1_1 + Delivery_1_2
Delivery_1_4 $=<
/*32*/
Delivery_2_1 + Delivery_2_2
Delivery_2_4 $=<
/*33*/
Delivery_3_1 + Delivery_3_2
Delivery_3_4 $=<
% Configuring eplex solver for
% minimizing the performance index:
/*34*/
eplex_solver_setup(min(
Cost_1_1 * Delivery_1_1 +
Cost_3_1 * Delivery_3_1 +
Cost_2_2 * Delivery_2_2 +
Cost_1_3 * Delivery_1_3 +
Cost_3_3 * Delivery_3_3 +
Cost_2_4 * Delivery_2_4 +
)),
459
+ Delivery_3_1 $=
+ Delivery_3_2 $=
+ Delivery_3_3 $=
+ Delivery_3_4 $=
+ Delivery_1_3 +
Capacity_1,
+ Delivery_2_3 +
Capacity_2,
+ Delivery_3_3 +
Capacity_3,
Cost_2_1
Cost_1_2
Cost_3_2
Cost_2_3
Cost_1_4
Cost_3_4
*
*
*
*
*
*
Delivery_2_1
Delivery_1_2
Delivery_3_2
Delivery_2_3
Delivery_1_4
Delivery_3_4
(foreach(Name,[
"Delivery_1_1","Delivery_2_1","Delivery_3_1",
"Delivery_1_2","Delivery_2_2","Delivery_3_2",
"Delivery_1_3","Delivery_2_3","Delivery_3_3",
"Delivery_1_4","Delivery_2_4","Delivery_3_4"]),
/*37*/
/*38*/
/*39*/
foreach(V, Variables)
do
eplex_var_get(V, typed_solution, V),
+
+
+
+
+
460
/*40*/
write(Name),write(" = "),write(V),nl
/*41*/
/*42*/
),
write("Cost"),write(" = "),writeCost),nl.
Decommenting the code in line /*7*/ makes the solver an integer programming solver. If additionally in lines /*27*/, /*28*/, /*29*/ and /*30*/ the
relations $= are swapped for $>= (i.e. some over-realization of contracts will
be acceptable), the programm changes into 7_5_warehouses_clients _2.ecl
giving the solution:
Delivery_1_1 = 0
Delivery_2_1 = 23
Delivery_3_1 = 13
Delivery_1_2 = 37
Delivery_2_2 = 0
Delivery_3_2 = 0
Delivery_1_3 = 0
Delivery_2_3 = 0
Delivery_3_3 = 23
Delivery_1_4 = 0
Delivery_2_4 = 32
Delivery_3_4 = 0
Cost = 376.5
461
This solution is intuitively obvious. Because in order to get an integer solution the constraints in lines /*27*/, /*28*/, /*29*/ and /*30*/ have been
relaxed (contracts could be over-realized), the minimum cost has to increase.
7.4
Parameters
Cost
Hardness
C1
110
8.8
C2
120
6.1
Oils
T1
130
2.0
T2
110
4.2
T3
115
5.0
462
:- lib(eplex).
top :oils_1(_,_).
instance:
foreach(V, Variables) do
prob: eplex_var_get(V, typed_solution, V),
/*18*/
write(Name),write(" = "),write(V),nl
/*19*/
/*20*/
),
write("Profit = "),write(Profit).
XC2 = 40.7407407407409
XT2 = 250.0
XT3 = 0.0
Profit = 17592.5925925926
Y = 450.0
11 This
is an OS-type problem.
463
XC2 = 41
XT1 = 0
XT3 = 0
XT2 = 250
Y = 450
Profit = 17590.0
7.5
464
Managers suggestions.
The Financial Advisor could not satisfactory explain the dierence in outcome (if any) of both strategies. In appreciation of services rendered to the Society by the Celebrated Senator, a befriended CLP programmer wrote a program
(7_8_getting_rich.ecl13 ) designed to dispel any doubts about the outcomes
of both strategies:
/*1*/
:- lib(eplex).
/*2*/ top:/*4*/
write("Choose the version (1
/*4*/
read_token(Number, integer),
/*5*/
solve(Number).
/*6*/ solve(1):/*7*/
A $>= 10,
% payment after
/*8*/
B $>= 10,
% payment after
/*9*/
C $>= 10,
% payment after
/*10*/
D $>= 10,
% payment after
or 2):"),nl,
first year
second year
third year
fourth year
/*11*/
/*12*/
/*13*/
/*14*/
/*15*/
/*16*/
payments([A,B,C,D], 100),
Profit_A $= 100*(1.07)-A,
Profit_B $= Profit_A*(1.06)-B,
Profit_C $= Profit_B*(1.05)-C,
Profit_D $= Profit_C*(1.04)-D,
Profit_D $:: 0..250,
/*17*/
/*18*/
/*19*/
/*20*/
/*21*/
eplex_solver_setup(max(Profit_D)),
eplex_solve(Profit_D),
eplex_get(vars, Vars),
eplex_get(typed_solution, Vals),
Vars = Vals,
/*22*/
Cost_of_credit is
A*0.95+B*0.95*0.96+C*0.95*0.96*0.97+
D*0.95*0.96*0.97*0.98,
/*23*/
/*24*/
/*25*/
/*26*/
/*27*/
/*28*/
13 This
is an OST-type problem.
/*29*/
/*39*/
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
/*39*/
/*40*/
/*41*/
/*42*/
/*43*/
/*44*/
eplex_solver_setup(min(Cost_of_credit)),
eplex_solve(Cost_of_credit),
eplex_get(vars, Vars),
eplex_get(typed_solution, Vals),
Vars = Vals,
Profit_A is 100*(1.07)-A,
Profit_B is Profit_A*(1.06)-B,
Profit_C is Profit_B*1.05-C,
Profit_D is Profit_C*1.04-D,
/*45*/
/*46*/
/*47*/
/*48*/
/*49*/
write("Payment
write("Payment
write("Payment
write("Payment
write("Minimum
/*50*/
/*51*/
/*52*/
/*53*/
payments([Payment|List_of_payments],Loan) :-
/*54*/
/*55*/
465
Updated_principal $=(1+2/100)*Loan-Payment,
payments(List_of_payments,Updated_principal).
466
It follows that no matter what strategy the Celebrated Senators Wife will
opt for, the prot (a nice 13.932304 MM MU) and the payment strategy will
always be the same.
7.6
ECLi P S e formulations of LP problems may be far, far removed from the conventional LP canonical form. This is illustrated by the following example:
The chief accountant of some small company has forecast the cash requirements for the next ve years. It turned out that the company would have some
free cash in the future. He considered the following investments options:
1. Short term (one-year bonds) with interest rates (return after a year) 20%.
2. Intermediate term (two-year bonds) with interest rates (return after two
years) 47%.
3. Long term (three-year bonds) with interest rates (return after three years)
78%.
He wishes to plan the investments over ve years taking into account the cash
requirements and one of the following three investment options, given the initial
cash of 100000 MU:
Option 1: satisfy yearly demands and maximize the amount of cash at the end
of the ve years period.
Option 2: satisfy yearly demands and minimize initial cash.
Option 3: satisfy yearly demands and determine the minimum initial cash
needed to have at the end of the ve years period the same amount of
cash.
467
Cash requirements at the beginnings of each year are given by Table 7.3:
Year
1
2
3
4
5
Amount
10000
10000
20000
20000
20000
Variable
Crx1
Crx2
Crx3
Crx4
Crx5
is an OST-type problem.
468
/*9*/
writelist(Names, Variables),
write("Initial cash: "),writeln(Initial_cash),
write("Final cash:
"),writeln(Final_cash),nl.
/*18*/
/*19*/
/*20*/
Names =
/*21*/
/*22*/
/*23*/
/*24*/
/*25*/
/*26*/
Tin1
Tin2
Tin3
Tin4
Tin5
/*27*/
/*28*/
$=
$=
$=
$=
$=
[
"Sin1","Sin2","Sin3","Sin4","Sin5",
"Iin1","Iin2","Iin3","Iin4","Iin5",
"Lin1","Lin2","Lin3","Lin4","Lin5",
"Tin1","Tin2","Tin3","Tin4","Tin5",
"Sre2","Sre3","Sre4","Sre5","Sre6",
"Ire3","Ire4","Ire5","Ire6",
"Lre4","Lre5","LreC",
"Tre2","Tre3","Tre4","Tre5","Tre6",
"Ebc1","Ebc2","Ebc3","Ebc4","Ebc5"
],
Iin1
Iin2
Iin3
Iin4
Iin5
+
+
+
+
+
Sin1
Sin2
Sin3
Sin4
Sin5
+
+
+
+
+
Lin1,
Lin2,
Lin3,
Lin4,
Lin5,
/*29*/
/*30*/
/*31*/
/*32*/
/*33*/
/*34*/
/*35*/
/*36*/
/*37*/
/*38*/
Sre2
Sre3
Sre4
Sre5
Sre6
$=
$=
$=
$=
$=
1.2
1.2
1.2
1.2
1.2
/*39*/
/*40*/
/*41*/
/*42*/
/*43*/
Tre2
Tre3
Tre4
Tre5
Tre6
$=
$=
$=
$=
$=
Sre2,
Sre3 +
Sre4 +
Sre5 +
Sre6 +
/*44*/
/*45*/
/*46*/
/*47*/
/*48*/
Cr1
Cr2
Cr3
Cr4
Cr5
$>=
$>=
$>=
$>=
$>=
10000,
10000,
20000,
20000,
20000,
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
/*54*/
/*55*/
/*56*/
writelist([], []).
writelist([FN|RN], [FV|RV]) :-
/*57*/
/*58*/
writelist(RN, RV).
*
*
*
*
*
469
Sin1,
Sin2,
Sin3,
Sin4,
Sin5,
Ire3,
Ire4 + Lre4,
Ire5 + Lre5,
Ire6 + Lre6,
To enhance the expressive power of the results they are presented in table 7.4,
which makes it easy to compare various investment options. The double negations in lines /*4*/, /*6*/ and /*8*/ may be astonishing at rst sight.
470
Variable
Sin1
Sin2
Sin3
Sin4
Sin5
Iin1
Iin2
Iin3
Iin4
Iin5
Lin1
Lin2
Lin3
Lin4
Lin5
Tin1
Tin2
Tin3
Tin4
Tin5
Sre2
Sre3
Sre4
Sre5
Sre6
Ire3
Ire4
Ire5
Ire6
Lre4
Lre5
Lre6
Option 1
8333.33333333333
0.0
0.0
0.0
0.0
22860.8450182794
0.0
13605.4421768707
84674.3625341293
0.0
58805.8216483872
0.0
0.0
0.0
0.0
90000.0
0.0
13605.4421768707
84674.3625341293
0.0
10000.0
0.0
0.0
0.0
0.0
33605.4421768707
0.0
20000.0
124471.31292517
104674.362534129
0.0
0.0
Option 2
8333.33333333333
0.0
0.0
0.0
0.0
80187.1463253183
0.0
13605.4421768696
0.0
0.0
11235.9550561798
0.0
84269.6629213483
0.0
0.0
99756.4347148322
0.0
97875.105098218
0.0
0.0
10000.0
0.0
0.0
0.0
0.0
117875.105098218
0.0
19999.9999999984
0.0
20000.0
0.0
150000.0
Option 3
8333.33333333333
0.0
0.0
0.0
0.0
55293.192790018
0.0
13605.4421768707
0.0
0.0
11235.9550561798
0.0
47675.5512244557
0.0
0.0
74862.4811795311
0.0
61280.9934013264
0.0
0.0
10000.0
0.0
0.0
0.0
0.0
81280.9934013264
0.0
20000.0
0.0
20000.0
0.0
84862.4811795311
Variable
Tre2
Tre3
Tre4
Tre5
Tre6
Gnad1
Gnad2
Gnad3
Gnad4
Gnad5
Initial cash
Final cash
Option 1
10000.0
33605.4421768707
104674.362534129
20000.0
124471.31292517
0.0
0.0
0.0
0.0
0.0
100000.0
124471.31292517
Option 2
10000.0
117875.105098218
20000.0
19999.9999999984
150000.0
0.0
0.0
0.0
0.0
0.0
109756.434714832
150000.0
471
Option 3
10000.0
81280.9934013264
20000.0
20000.0
84862.4811795311
0.0
0.0
0.0
0.0
0.0
84862.4811795311
84862.4811795311
7.7
The mathematical model used for LP are mainly various balances. The nature
of those balances may sometimes be strange indeed. This is illustrated by the
following example. inspired by one presented by [Taha-08]:
Clever Young, a computer prodigy as well as a mathematical and business
whiz-kid, has been thinking a long time about how to make money on-line.
He nally decided to make some currency speculations using general available
15 Thanks are due to Joachim Schimpf from ECLiPSe for drawing the Authors attention to
this trick.
472
USD
EUR
GBP
JPY
PLN
USD
1
1.1972
1.445
0.01088
0.2867
EUR
0.8353
1
1.2073
0.009088
0.2392
GBP
0.692
0.8283
1
0.007575
0.1983
JPY
91.89
110.03
132
1
0.2635
PLN
3.4872
4.181
5.0414
3.7950
1
Ex_rate_USD_to_EUR
Ex_rate_USD_to_GBP
Ex_rate_USD_to_JPY
Ex_rate_USD_to_PLN
Ex_rate_EUR_to_GBP
Ex_rate_EUR_to_JPY
Ex_rate_EUR_to_PLN
Ex_rate_GBP_to_JPY
Ex_rate_GBP_to_PLN
Ex_rate_JPY_to_PLN
=
=
=
=
=
=
=
=
=
=
/*25*/
/*26*/
/*27*/
/*28*/
/*29*/
/*30*/
/*31*/
Ex_rate_EUR_to_USD
Ex_rate_GBP_to_USD
Ex_rate_JPY_to_USD
Ex_rate_PLN_to_USD
Ex_rate_GBP_to_EUR
Ex_rate_JPY_to_EUR
Ex_rate_PLN_to_EUR
is
is
is
is
is
is
is
16 This
is an OS-type problem.
0.8353,
0.692,
91.89,
3.4872,
0.8283 ,
110.03,
4.181,
132,
5.0414,
3.7950,
1/(Ex_rate_USD_to_EUR),
1/(Ex_rate_USD_to_GBP),
1/(Ex_rate_USD_to_JPY),
1/(Ex_rate_USD_to_PLN),
1/(Ex_rate_EUR_to_GBP),
1/(Ex_rate_EUR_to_JPY),
1/(Ex_rate_EUR_to_PLN),
473
474
/*33*/
/*33*/
/*34*/
Ex_rate_JPY_to_GBP is 1/(Ex_rate_GBP_to_JPY),
Ex_rate_PLN_to_GBP is 1/(Ex_rate_GBP_to_PLN),
Ex_rate_PLN_to_JPY is 1/(Ex_rate_JPY_to_PLN),
% USD balance:
/*35*/
Z + USDtoEUR + USDtoGBP + USDtoJPY + USDtoPLN $=
A + (Ex_rate_EUR_to_USD)*EURtoUSD + (Ex_rate_GBP_to_USD)*GBPtoUSD +
(Ex_rate_JPY_to_USD)*JPYtoUSD + (Ex_rate_PLN_to_USD)*PLNtoUSD,
% EUR balance:
/*36*/
EURtoUSD + EURtoGBP + EURtoJPY + EURtoPLN $=
(Ex_rate_USD_to_EUR)*USDtoEUR + (Ex_rate_GBP_to_EUR)*GBPtoEUR +
(Ex_rate_JPY_to_EUR)*JPYtoEUR + (Ex_rate_PLN_to_EUR)*PLNtoEUR,
% GBP balance:
/*37*/
GBPtoUSD + GBPtoEUR + GBPtoJPY + GBPtoPLN $=
(Ex_rate_USD_to_GBP)*USDtoGBP + (Ex_rate_EUR_to_GBP)*EURtoGBP +
(Ex_rate_JPY_to_GBP)*JPYtoGBP + (Ex_rate_PLN_to_GBP)*PLNtoGBP,
% JPY balance:
/*38*/
JPYtoUSD + JPYtoEUR + JPYtoGBP + JPYtoPLN $=
(Ex_rate_USD_to_JPY)*USDtoJPY + (Ex_rate_EUR_to_JPY)*EURtoJPY +
(Ex_rate_GBP_to_JPY)*GBPtoJPY + (Ex_rate_PLN_to_JPY)*PLNtoJPY,
% PLN balance:
/*39*/
PLNtoUSD + PLNtoEUR + PLNtoGBP + PLNtoJPY $=
(Ex_rate_USD_to_PLN)*USDtoPLN + (Ex_rate_EUR_to_PLN)*EURtoPLN +
(Ex_rate_GBP_to_PLN)*GBPtoPLN + (Ex_rate_JPY_to_PLN)*JPYtoPLN,
/*40*/
/*41*/
/*42*/
/*43*/
/*44*/
eplex_solver_setup(max(Z)),
eplex_solve(Z),
eplex_get(vars, Vars),
eplex_get(typed_solution, Vals),
Vars = Vals,
/*45*/
/*46*/
/*47*/
/*48*/
/*49*/
/*50*/
/*51*/
/*52*/
/*53*/
/*54*/
/*55*/
/*56*/
/*57*/
/*58*/
/*59*/
/*60*/
/*61*/
/*62*/
/*63*/
/*64*/
/*65*/
/*66*/
write_positive("JPYtoUSD",
write_positive("JPYtoEUR",
write_positive("JPYtoGBP",
write_positive("JPYtoPLN",
write_positive("PLNtoUSD",
write_positive("PLNtoEUR",
write_positive("PLNtoGBP",
write_positive("PLNtoJPY",
JPYtoUSD),
JPYtoEUR),
JPYtoGBP),
JPYtoPLN),
PLNtoUSD),
PLNtoEUR),
PLNtoGBP),
PLNtoJPY),
/*67*/
/*68*/
/*69*/
/*70*/
/*71*/
/*72*/
/*73*/
/*74*/
/*75*/
/*76*/
/*77*/
/*78*/
/*79*/
/*80*/
/*81*/
/*82*/
/*83*/
/*84*/
/*85*/
/*86*/
writeln("Ex_rate_USD_to_EUR":Ex_rate_USD_to_EUR),
writeln("Ex_rate_USD_to_GBP":Ex_rate_USD_to_GBP),
writeln("Ex_rate_USD_to_JPY":Ex_rate_USD_to_JPY),
writeln("Ex_rate_USD_to_PLN":Ex_rate_USD_to_PLN),
writeln("Ex_rate_EUR_to_USD":Ex_rate_EUR_to_USD),
writeln("Ex_rate_EUR_to_GBP":Ex_rate_EUR_to_GBP),
writeln("Ex_rate_EUR_to_JPY":Ex_rate_EUR_to_JPY),
writeln("Ex_rate_EUR_to_PLN":Ex_rate_EUR_to_PLN),
writeln("Ex_rate_GBP_to_USD":Ex_rate_GBP_to_USD),
writeln("Ex_rate_GBP_to_EUR":Ex_rate_GBP_to_EUR),
writeln("Ex_rate_GBP_to_JPY":Ex_rate_GBP_to_JPY),
writeln("Ex_rate_GBP_to_PLN":Ex_rate_GBP_to_PLN),
writeln("Ex_rate_JPY_to_USD":Ex_rate_JPY_to_USD),
writeln("Ex_rate_JPY_to_EUR":Ex_rate_JPY_to_EUR),
writeln("Ex_rate_JPY_to_GBP":Ex_rate_JPY_to_GBP),
writeln("Ex_rate_JPY_to_PLN":Ex_rate_JPY_to_PLN),
writeln("Ex_rate_PLN_to_USD":Ex_rate_PLN_to_USD),
writeln("Ex_rate_PLN_to_EUR":Ex_rate_PLN_to_EUR),
writeln("Ex_rate_PLN_to_GBP":Ex_rate_PLN_to_GBP),
writeln("Ex_rate_PLN_to_JPY":Ex_rate_PLN_to_JPY).
/*87*/
/*88*/
475
476
Ex_rate_EUR_to_JPY : 110.03
Ex_rate_EUR_to_PLN : 4.181
Ex_rate_GBP_to_USD : 1.44508670520231
Ex_rate_GBP_to_EUR : 1.20729204394543
Ex_rate_GBP_to_JPY : 132
Ex_rate_GBP_to_PLN : 5.0414
Ex_rate_JPY_to_USD : 0.0108825769942322
Ex_rate_JPY_to_EUR : 0.00908843042806507
Ex_rate_JPY_to_GBP : 0.00757575757575758
Ex_rate_JPY_to_PLN : 3.795
Ex_rate_PLN_to_USD : 0.286763019041064
Ex_rate_PLN_to_EUR : 0.239177230327673
Ex_rate_PLN_to_GBP : 0.198357599079621
Ex_rate_PLN_to_JPY : 0.263504611330698
The result was so astonishing that Clever Young decided to check all balances:
The USD check:
6+0+0+0+0 = 5+0+0+0+0.286763019041064*3.4872
gives:
6 = 6
The EUR check:
0+0+0.00843576360267486+0 = 0+0+0+
0.239177230327673*0.0352699276227836
gives:
0.008435763602674869 = 0.008435763602674869
The GBP check is trivial:
0+0+0+0 = 0+0+0+0
The JPY check:
0+0+0+0.928187069202315 = 0+110.03*0.00843576360267486+0+0
gives:
0.928187069202315 = 0.9281870692023148458
The PLN check:
3.4872+0.0352699276227836+0+0 = 0+0+0+3.795*0.928187069202315
477
gives:
3.5224699 = 3.5224699
So everything is O.K.! If the obtained solution is submitted to the currency
dealer as one order, there is no need for waiting until some other currencies are
accumulated to make a buy. However the problem remains: where to get the
5 MM of USD from in order to convert them to 6 MM USD. Clever Young,
having an enterprising nature, made one more try, this time with A=0, i.e. with
no initial USD at all. The result was as follows, the exchange rates messages
being omitted:
A
: 0.0
478
5.56912241521389 = 5.56912241521389
The PLN check:
20.9232+0.211619565736702+0+0 = 0+0+0+3.795*5.56912241521389
gives:
21.13481956573 = 21.1348195657
So everything is O.K. one more time. However, Clever Young still wondered
about getting the same 6 MM USD as before. Because those 6 MM USD were
equal to the (somewhat arbitrarily) upper level in line /*6*/ (domain denition
for Z), he decided to make yet one more simulation, but this time with the
upper level equal to 120 MM USD. he result was as follows wit the exchange
rates messages being omitted:
A
: 0.0
: 21.208105932626
EURtoUSD : 3.0
EURtoJPY : 1.08782427718034
GBPtoUSD : 3.5
JPYtoUSD : 100.0
JPYtoPLN : 19.6933052181531
PLNtoUSD : 40.0
PLNtoEUR : 17.091193302891
PLNtoGBP : 17.6449
17 A hypothetical machine that produces more energy than it consumes, no matter how long
it operates. Scientists agree that a Perpetuum Mobile is unfeasible: its existence would violate
fundamental laws of physics.
18 Well, the mathematics used by Clever Young was O.K., but his data was faulty. He
inputed wrong numbers for the JPYtoPLN and PLNtoJPY exchange rates into Table 7.6.
7.8 Exercises
7.8
479
Exercises
Building a factory
An enterprizing businessman decided to build a factory producing XYZ
Gizmos, which - he believed - will be much in demand the moment they
appear on the market. The rst thing to do was to get nancing. To
secure a loan of 6 MM MU costs him 0.1 MM MU and took 4 months to
arrange. The loan was at a bargain-basement price of 7% per year, to be
repaid in 3 years. If defaulted, the balance after three years had to be
repaid at 12% per year. Next, he bought a piece of property for 1 MM
MU. To arrange the purchase took an unbelievable short time of 4 months.
He began to pay property taxes on it immediately, which goes to pay for
re, police and roads, etc., to the amount of 0.01 MM MU per month.
Next he had to get an environmental impact study done, which normally
may take as long as 1.5 years. Unfortunately, he was challenged by an
Environmental Group claiming that his property is the habitat of some
very rare micro-rodents, now on the verge of extinction. The businessman
had to defend himself in a court of law for 2 years, and nally settled with
the Environmental Group to drop their charges by paying them 0.2 MM
MU for resettling the entire micro-rodent population from his property.
He also needed to place microphones and cameras in his grass to monitor
if some remnants of the micro-rodent population did not remain there and
are not disturbed by business activities. This contributed a yearly cost of
0.05 MM MU to the budget. Only then could he provide electric, water
and sewage hookups for his property. It took 3 month at the cost of 0.2
MM MU. At the same time he started to design and pay for sidewalks,
roads, drainage swales, green belts; because his property was near an
established road, he had to pay to have it widened. This took 5 months
and costed 0.2 MM MU. Next he hired an architect to do the drawings.
They were submitted for approval, and rejected because of protests from
the religious community of Boo-Woo Worshipers demanding a Room for
Prayer at the factory for their Brothers/Sisters in Faith (in case they
are employed at the factory), and because of protests from the Nursing
Mother Association demanding a Nursing Mother Rest-and-Care Room
at the factory for nursing mothers to be surely employed at the factory.
Ultimately, after 3 months and multiple checks and revisions, at the overall
cost of 0.5 MM MU, the drawings were approved by proper Authorities.
Only then (i.e. 3 years after getting the loan, for which no nickel has
been repaid yet) the businessman hired a general contractor who agreed
480
to build the factory in 7 months (at the overall cost of 3.2 MM MU),
and at the same time the businessman started to buy several permits:
building permit, electrical permit, plumbing permit, and had multiple
inspections all along the way, each inspection costing him a fee; all the
fees for permits and inspections amount to 0.3 MM MU; unfortunately,
they have to be renewed at 3-months intervals. Once the factory was
built, the businessman began outtting it with necessary tools, machines
and oce equipment, which took 3 month and costed 1.2 MM MU). At
the same time he started to sta his factory with employees; because
of the large percentage of unemployable unemployed in the working age
population, and because of the local LGBT Community accusing him of
discriminatory hiring practices, it was quite a job and took 6 month at the
cost of 0.1 MM MUs. Now, everything was ready to start producing those
XYZ Gizmos. However, by chance entirely, the businessman visited a local
World Market Mall outlet, and found that the Famous Eastern Global
Company has already ooded the market with a large spectrum of various
XYZ Gizmos at ridiculously low prices. In seeing that, the businessman
suered a fatal heart attack. Write a program to determine how long did
it take and how much did it cost to arrive at this situation, assuming no
payment of the purchase loan (neither the principal nor the interest rate)
has ever been made and any money needed by the businessman above the
initial loan of 6 MM has been granted by the loan provider but at 12% per
year. In order to make the time-structure of events evident, it has been
shown in Figure 7.2.
Private investments
A private investor wishes to invest 15000 MU over the next year in two
types of investment: investment I1 yields 5% and investment I2 yields 9%.
The broker advises to allocate at least 30% in I1 and at most 55% in I2.
Besides, the investment in I1 should be at least half the investment in I2.
How to invest to maximize the yearly return?
PR campaign
The well-known party All Things to All People is misleading the electorate
by a well-organized PR campaign on radio and television. Its PR budget
is limited to 15000 MU per month. Each minute of radio hype costs 15
MU, and each minute of TV hype costs 300 MU. The party likes radio
hype at least twice as much as it likes TV hype. Research indicates that
it is not practical to broadcast party hype on radio more than 400 minutes
7.8 Exercises
481
per month. The same research show that TV hype is 25 times more
eective than radio hype. How to allocate the PR budget to maximize
eectiveness of the PR campaign?
Assembling phones
An assembling line, consisting of four consecutive workstations, is used to
assemble 2 phones, Handy_1 and Handy_2. The assembly data is given by
Table 7.7. The shift-wise maintenance of workstations consumes a given
percentage of the overall 480 minutes work-time on a shift. Write a program to determine the optimum numbers of Handy_1 and Handy_2 phones
produced at a shift that will minimize the overall idle time for a shift.
482
Station
number
l
2
3
4
Assembly time
in minutes
per unit
for Handy_1
6
4
5
7
Assembly time
in minutes
per unit
for Handy_2
4
6
5
8
Daily maintenance
in % of
480 minutes
10
12
14
16
7.8 Exercises
483
Plant
number
l
2
3
4
Production
capacity
10000
8000
9000
6000
Plant xed
cost (MM MU)
9
5
3
1
Cost per
computer (MU)
1000
1700
2300
2900
Cost
MM MU
20
17
23
24
25
21
Length of
validity, years
1
2
3
4
5
6
Overall interest
rate, %
7
15
23
32
41
50
Table 7.9: Construction costs each year and interest rates for bonds
Buses
Two Bus Depots (D1 and D2) are dispatching buses to four Bus Stations
(S1, S2, S3 and S4). Table 7.10 shows the distances between the depots
and stations, the number of buses available at the depots and the demands
of the bus stations. Write a program allocating buses from depots to
stations so as to minimize the overall distance traveled between depots
and stations.
19 This
484
Depot
D1
D2
Demand
S1
15
5
40
Station
S2 S3
12 10
18 24
65 45
Buses available
S4
17
7
60
100
150
7.8 Exercises
485
At the beginning of July, E.J. may take out a six-month loan. Any money
borrowed for a six-month period must be paid back at the end of December
along with 9% interest (early payback does not reduce the the interest
cost of the loan). E.J. may also meet cash needs through month-to-month
borrowing. Any money borrowed for a one-month period incurs an interest
cost of 4% per month. Write a program to determine how E.J. can minimize
the cost of paying its bills on time.
Loan policy
The Famous Bank is in the process of designing a loan policy for maximum
12 million MU. Table 7.1222 provides pertinent data about types of loans
available at the bank.
Type of loan
Personal
Car
Home
Farm
Commercial
Interest rate
0.140
0.130
0.120
0.125
0.100
Bad-debt ratio
0.1
0.07
0.03
0.05
0.02
486
to a number of degenerative illnesses. The BigPharma Board of Directors had analyzed in depth a number of possible strategies to market
this stu and had nally decided to sell it for supposedly healing the invented (by their marketing people) disease named No Symptoms Disorder
(NSD ). The marketing people have described NSD as a fatal-outcome disease to be endemic in Normal People, i.e. people who seem to be quite
healthy, enjoy their life, family and work, lead a healthy life style with
no cigarettes, recreational drugs or alcohol, devote some time to risk-free
sporting activities, steer clear of high-carb low-fat nutrition and prefer
natural saturated fat food over industry-manufactured concoctions, avoid
ridiculous expenses and stressful occupations, are strong proponents of
various natural healing methods (including legally banned hydrotherapy
cures designed by Sebastian Kneipp). Now the job was to convince Normal
People they need pharmaceuticals to treat their disorder, the best being
obviously BHFD. Therefore Main-Stream Media, generously nanced by
BigPharma, started a hysterical campaign highlighting all No Symptoms
Disorder fatalities, usually forgetting to mention the rather advanced age
of those who died, but praising the healing-power of BHFD. This has been
supported nancially by the Department of Longevity of the World Institute for Wellness, worried about the constantly rising number of ageing
Normal People, being a drain on all pension schemes and not contributing
enough to any taxing schemes. The cynical quotation from one of its highlevel functionaries: How can you control a population if you dont keep
them medicated? was quickly and thoroughly swept under the carpet.
To use its monopoly on BHFD, BigPharma started to work on BHFD technologies, aiming at producing BHFD pills, suppositories, syrups, vaccines
and patches, so as to satisfy the preferences of a wide range of customers.
However, the production of all those BHFD articles was hampered by
some constraints:
The Basic Raw Material (BRM ) for BHFD turned out to be an
extract from some tropical plant found only in the Famous Tropical
( Forest), which - for the time being - could be harvested at no more
than 1000 kg monthly.
The production of pills and suppositories run - for the time being on the same production line, which constraints the overall monthly
output of pills and suppositories to 1000 standard packages;
The production of patches needed a special textile fabric which was
7.8 Exercises
487
available up to 10 m2 monthly;
The production of vaccines and syrups depended upon the same solvent available up to 100 liters monthly.
Write a program determining the monthly production volume of all BHFD
articles in order to maximize BigPharma prot provided that:
for producing a single pill package 0.01 kg BRM was needed, for
producing a single suppository package 0.015 kg BRM was needed,
for producing a single syrup bottle 0.01 kg BRM was needed, for
producing a single vaccine package 0.02 kg BRM was needed, and for
producing a single package of patches - 0.012 kg BRM was needed,;
for producing a single package of patches 10 cm2 special textile fabric
was needed;
for producing a single syrup container 0.001 liters, and for producing
a single package of vaccines 0.01 liters of solvent was needed.
and that:
selling a single pill package gives prot equal to 1.5 MU;
selling a single suppository package gives prot equal to 1.8 MU;
selling a single sirup bottle gives prot equal to 2.0 MU;
selling a single vaccine package gives prot equal to 3.5 MU;
selling a single package of patches gives prot equal to 2.5 MU.
Afterword
Well, in our country, said Alice, still panting a little, youd generally get
to somewhere else if you ran very fast for a long time, as weve been doing.
A slow sort of country! said the Queen. Now, here, you see, it takes all the
running you can do, to keep in the same place. If you want to get somewhere
else, you must run at least twice as fast as that!
Lewis Carroll, Through the Looking Glass
In spite of the territory covered in this book in what seems to be a fast and
long run, we have barely scratched the surface of ECLi P S e CP S.
The ECLi P S e platform is oering to knowledgeable users much, much more
than could be described in this elementary introduction, which concentrated on
basic ideas only. The doubting Reader is kindly asked to have a close look
at all the standard predicates listed in the Alphabetical Predicate Index, see
Figure 5. A number of advanced topics has been presented rather cursorily (e.g.
controlling search), a number of important features has not been presented at all
like graphics, and interfacing with procedural languages. Finally the important
subject of nding sub-optimum solutions by means of heuristics like local search
including Hill Climbing, Tabu Search and Simulated Annealing, has simply been
omitted.
The interested Reader may nd more about it on the continuously updated
ECLi P S e website and on the ECLi P S e discussion forum.
The books aim was educating ECLi P S e (and CLP) novices. The Author
always believed that education in anything is not like lling a vessel, but rather
like igniting a re. Its up to the Reader to judge to what extend this book
meets those claims. However, its up to the Author to state that writing this
book was a source of personal satisfaction and enjoyment.
489
Glossary
Absurdoland - a totally ctitious country, being a place where unusual, unbelievable and
extraordinary things are happening, as recounted in many problem stories of this book.
Accumulator - an initially empty list (or zero variable) to which head (or values) are added
on each recursion of the predicate containing the accumulator.
AI - Articial Intelligence.
Algorithm - a solution method guaranteeing success.
Anonymous variable - a variable which does not need to be grounded.
AoA - Activity on Arcs network: uses directed arcs to represent activities.
Appearance of variable - the presence of some predicate variable in many places of the
body of a rule, or in the same predicate in other rules.
Argument - a variable associated with a predicate.
Argument - an atom associated with a structure.
Argument - free - an argument with no assigned value from its domain. item[Argument ground] - an argument with assigned value from its domain.
Arity - the number of arguments to a term. The notation Name/Arity is used to specify a
term by giving its name and arity.
Arity - of predicate - number of variables in a predicate.
Arity - of relation - number of variables in Cartesian product.
Array - a generalization of variable, capable of storing multiple values as vectors or matrices.
Artificial Intelligence - a branch of computer science trying to emulate human performance
usually deemed to be intelligent.
Assert - to save a grounded predicate in a database.
Assigning - pairing elements of some set with elements of another sets so as to fulll belongness constraints.
Atom - a Prolog/CLP non-numerical (i.e. logical or symbolic) constant with zero arity,
presented by a sequence of characters starting with a lower case letter or by any sequence
of characters put between double quotes or single quotes.
491
492
Glossary
Backtracking - the process of degrounding the recently grounded variable followed by making the contracted state equal to one corresponding to the nearest choice point.
Backtracking - Forward Checking - backtracking in CLP, initiated when, as the result
of the last variable grounding, an empty domain appears.
Backtracking - Looking Ahead - backtracking in CLP, initiated when, as the result of the
last variable grounding, for the next search step the appearance of an empty domain
is predicted.
Backtracking - Standard - backtracking in Prolog, initiated when a grounded predicate
fails.
Belongness constraint - a constraint stating that some items belong together as parts of
some entity.
Body - see rule.
Boolean - see Variable - Boolean.
Built-in - see Predicate - built-in.
Branch and bound - a form of backtracking search with the additional constraint to nd
a state that minimizes some objective function.
Cartesian product - of n sets - the set of all possible n-tuples, each element of which belongs
to a dierent set.
CCOP - continuous constraint optimization problem.
CCSP - continuous constraint satisfaction problem.
Choice point - a predicate having at least one variable with value not yet grounded to
some value of its domain, serving as point of return when - during search - a recently
grounded variable results in failure.
Clause - a basic building block of Prolog and CLP programs, being either a fact or a rule.
Closed World Assumption - - the assumption that the head of a not satised rule is
considered to be false.
Combinatorial variable - see Variable - discrete.
Combinatorial explosion - - the eect of rapid state space growth caused by increasing
number of decision variables.
Command mode - an execution mode for CLP programs, run in DOS-like command window.
Compound interest - addition of interest to the principal before next interest is calculated.
Configuring - selecting, from some sets, subsets fullling constraints of belongness and compatibility constraints.
Conjunction - an operation on logical operands that produces a true value if and only if all
of its operands are true.
Consistency techniques - algorithms making a set of integer variables, dened by names
and domains, to fulll a set of constraints by properly adjusting the initial variable
domains. Used for constraint propagation in CLP. Consistency techniques are not
complete inference method.
Glossary
493
Constant - an atom (starting with a small letter), an integer number, a real number, a list
or array of atoms, of integer numbers, of real numbers.
Constraint - a relation over a set of domain variables, which constricts the combination
of domain values to which the variables may be grounded. A constraint represents
conditions which these variables must satisfy.
Constraint - active - a constraint that could initiate search in case it is either not consistent
or not all of its variables have been grounded.
Constraint - consistent - a constraint with variables grounded in a way the constraint is
satised.
Constraint - passive - a constraint that is used as a test in case all its variables are
grounded.
Constraint propagation - a process initiated by making a constraint consistent by grounding its variables.
Constraint propagation in CLP - a process by which the value of a grounded constraint
variable is modifying domains of relevant variables so that their constraints are satised.
The modication consists of removing those values from all domains that violate the
constraint. Constraint propagation in CLP may be performed without search, but it is
s not a complete inference method.
Constraint propagation in Prolog - a process by which the grounding done by unication
for a constraint variable in some rule is spread i.e. repeated for all instances of this
variable in the body of this rule and for all other instances of the predicates in other
rules. Constraint propagation in Prolog cannot be performed without search.
Continuous variable - see Variable - continuous.
COP constraint optimization problem.
Critical path - the shortest sequence of projects activities starting from the initial activity
and ending with the nal activity.
CSP - constraint satisfaction problem.
Decision variable - see Variable - decision.
Declarative programming - a programming paradigm based on describing problems to be
solved, rather than describing how to go about solving them.
Decomment - remove % comment lines.
Degrounding a variable - making a grounded variable free.
Delayed goals - goals that could not have been instantiated because of insucient information.
Direct enumeration - see Search - exhaustive.
Discrete variable - see Variable - discrete.
Disequation - ?Term1 \== ?Term2 - succeeds if Term1 and Term2 are not identical terms,
?ExprX \= ?ExprY - succeeds if ExprX is not equal to ExprY where Expr - an integer
arithmetic expression.
Disjunction - an operation on logical operands that produces a value of true if at least one
of its operands is true.
494
Glossary
Glossary
495
496
Glossary
Glossary
497
498
Glossary
Rule - a conditional statement with the meaning: If conditions are true, then conclusion is
true, the conclusion being an ungrounded predicate referred to as the head of the rule,
the conditions being a conjunction of grounded or ungrounded predicates referred to as
the body of the rule. Rules are written in the form conclusion:- conditions, the symbol
(:-) being a convenient way of writing the rule implication arrow ().
Satisfied - having the logical value true.
Scheduling - ordering elements of some set so as to fulll precedence constraints and resource
constraints.
Search - the following sequence of steps: 1)grounding a selected decision variable, and 2)testing the satisfaction of relevant constraints: if some constraint fails, backtracking is
initiated. Otherwise another decision variable is selected and grounded. Search is a
complete inference method.
Search and propagation - a process of searchand propagation performed alternately.
Search - exhaustive - generating consecutively all states of the state space and testing
whether they satisfy all constraints of the problem.
Search space - see state space.
Solver - software for solving optimization problems.
Sequencing - ordering elements of some set so as to fulll precedence constraints.
Semantics - meaning of symbols and clauses of a language.
Spreading a variable value - the grounding done for a predicate variable in some rule is
repeated by unication for all instances of this variable in the body of this rule and for
all other instances of the predicates in other rules.
State - complete - any grounding of domain values to all decision variables.
State - contracted - any grounding of domain values to some decision variables.
State - feasible - such assignment of domain values to decision variables that satises all
constraints.
State - optimal - a feasible state for which some objective function achieves its optimum.
State - optimal trajectory - a feasible state trajectory, for which some objective function
achieves its optimum.
State space - all groundings of domain values to all decision variables.
State space - contracted - all groundings of domain values to some decision variables.
State trajectory, feasible - a sequence of feasible states leading from some initial feasible
state to some nal feasible state of the state space.
State trajectory, optimal - a sequence of feasible states leading from some initial feasible
state to some nal feasible state of the state space, while optimizing some cost function.
State - unfeasible - an grounding of domain values to decision variables for which at lest
one constraint is unsatised.
String - any sequence of characters enclosed in double quotes.
Structure - a tuple of a xed number of atoms with a name.
Success - a grounded predicate is satised, i.e. corresponds to a true clause.
Glossary
499
Variable - degrounding - making a grounded variable free while restoring its value to its
domain.
Variable - discrete - a variable with nite domain.
Variable - free - a variable with no assigned value from its domain.
Variable - grounded - a variable with assigned value from its domain.
Variable - grounding - assigning to a free variable a value from its domain.
Variable - identity - the sameness of a predicate variable is assured by assigning to it the
same name in a rule and by assigning it to the same argument position in the predicate
in other rules.
Variable - meaning - to make Prolog/CLP programs understandable, the meaning of all
variables used should be precisely dened.
Variable - regrounded - a variable to which is assigned at least a second value from its
domain in turn.
Variable - regrounding - assigning to a degrounded variable at least a second value from
its domain.
Variable choice heuristic - a heuristic that determines the order of variables to be grounded
while searching.
Bibliography
[Aggoun-93] Aggoun, A. and N. Baldiceanu, Extending CHIP in Order to Solve Complex
Scheduling and Placement Problems, Mathl. Comput. Modelling, Vol. 17, No. 7, pp.
57-73, 1993.
[Apt-03] Apt, K. R., Principles of Constraint Programming, Cambridge University Press,
Cambridge 2003.
[Apt-07] Apt, K. R. and M. G. Wallace, Constraint Logic Programming using ECLi P S e ,
Cambridge University Press, Cambridge 2007.
[Ahriz-13] Ahriz, H., Z models for constraint and optimisation problems
http://www.comp.rgu.ac.uk/sta/ha/ZCSP/, 2013.
[Baker-09] Baker, K. R. and D. Trietsvch, Principles of Sequencing and Scheduling, John
Wiley and Sons, Hoboken, 2009.
[Baldiceanu-94] Baldiceanu, N. and Contejean E., Introducing Global Constraints in CHIP
Math.Comput.Modelling, Vol. 20, No. 12, pp. 97-123, 1994.
[Baldiceanu-10] Baldiceanu, N., Global Constraints Catalog
http://www.emn.fr/x-info/sdemasse/gccat/, 2010.
[Baptiste-95] Baptiste, Ph., C. Le Pape and W. Nuijten, Constraint-Based Optimization and
Approximation for Job-Shop Scheduling, Proceedings of the AAAI-SIGMAN Workshop
on Intelligent Manufacturing Systems, IJCAI-95, Montreal, Canada, 1995.
[Baptiste-01] Baptiste, Ph., C. Le Pape and W. Nuijten,
Kluwer Academic Publishers, Boston, 2001.
Constraint-Based Scheduling,
[Bartak-10] Bart
ak, R., On-Line Guide to Prolog Programming,
http://kti.m.cuni.cz/ bartak/prolog/, 2010.
[Bartak-10a] Bart
ak, R., On-Line Guide to Constraint Programming,
http://kti.m.cuni.cz/ bartak/constraints/, 2010.
[Bellman-61] Bellman, R., Adaptive Control Processes,
Princeton University Press, Princeton 1961.
501
502
BIBLIOGRAPHY
[Bizam-75] Biz
am, G. and J. Herczeg, Games and logic, A Polish translation (Gry i logika)
from the Hungarian original, Wydawnictwa Naukowo-Techniczne, Warszawa, 1975.
[Brachman-04] Brachman, R. J. and H. J. Levesque, Knowledge Representation and Reasoning, Elsevier - Morgan Kaufmann, Amsterdam, 2004.
[Bratko-01] Bratko, I., Prolog programming for Articial Intelligence, Addison Wesley, Harlow, 3rd ed., 2001.
[Carlier-89] Carlier, J. and E. Pinson, An algorithm for solving the job-shop problem, Management Science, 35(2), 164-176, 1989.
[Clark-84] Clark K.L. and F.G. McCabe. Micro-PROLOG: programming in logic.
Prentice Hall, 1984.
[CHIP-07] COSYTEC Complex Systems Technologies. CHIP V5.
http://www.cosytec.com/.
[Dechter-03] Dechter, R., Constraint Processing, Morgan Kaufmann, San Francisco, 2003.
[Duncan-90] Duncan, T., Scheduling Problems and Constraint Logic Programmingf: A Simple Example and its Solution, AIAI-TR-120,AIAI University of Edinburgh, 1990.
[ECLiPSe-10] CISCO, The ECLiPSe Constraint Programming System,
http://www.eclipse-clp.org/, 2010.
[Edmund-98] Edmund, D., Bobs Shish Kebabs,
Dell Logic Puzzles, June, 1998, p. 24.
[Edmund-10] Edmund, D., Dough Edmunds Puzzle Page,
http://www.eclipse-clp.org/eclipse/examples, 2010.
[French-82] French, S., Sequencing and Scheduling: An Introduction to the Mathematics of
Job-Shop, Ellis Horwood, 1982.
[Friedman-Hill-03] Friedman-Hill, E., Jess in Action. Rule-Based Systems in Java, Manning
Publ. Co., Greewich, 2003.
[From-94] From, A., Programmation par Contraintes, Addison-Wesley, Paris, 1994.
[Goluchowski-07] Goluchowski, J., Technologie informatyczne w zarz
adzaniu wiedz
a w organizacji, (Information Technologies in Kowledge Management), Wydawnictwo Akademii
Ekonomicznej, Katowice, wyd. 2, 2007.
[Graham-78] Graham, R. L., Combinatorial Scheduling Theory, In L. A. Steen (Ed.), Mathematics Today: Twelve Informal Essays, Springer-Verlag, New York, 1978, pp. 183-211.
[Hansen-03] Hansen, J., Constraint Programming versus Mathematical Programming, Orbit,
Vol. 3, Feb. 2003.
[Hooker-00] Hooker, J.N., Logic-Based Methods for Optimization: Combining Optimization
and Constraint Satisfaction, John Wiley and Sons, New York, 2000.
BIBLIOGRAPHY
503
[Hooker-07] Hooker, J.N., Integrated Methods for Optimization, Springer, Pittsburgh, 2007.
[Hunt-13] Hunt, W., The Stable Marriage Problem,
http://www.csee.wvu.edu/ ksmani/courses/fa01/random/lecnotes/lecture5.pdf, 2013.
[Jaar-94] Jaar, J. and M. J. Maher, Constraint Logic Programming: A Survey, Journal of
Logic Programming, 1994, 19-20, str. 503-581.
[Kjellerstrand-13] Kjellerstrand, H., Constraint Programming Blog,
http://www.hakank.org/ECLiPSe/, 2013.
[Legierski-06] Legierski, W., Automated Timetabling via Constraint Programming,
J. Skalmierski CS, Gliwice, 2006.
[Lines-92] Lines, M.E., Think of a number, IOP Publishing Ltd, London, 1992.
[Luger-98] Luger, G. F. and Stubbleeld, W.A., Articial Intelligence. Structures and Strategies for Complex Problem Solving, Addison Wesley Longman, Inc, Harlow, 3rd ed., 1998.
[Mackworth-92] Mackworth, A.K., Constraint Satisfaction, W: Shapiro S.C. (Ed.) Encyclopedia of Articial Intelligence John Wiley and Sons, New York, 1992.
[Marriott-98] Marriott, K. and P. J. Stuckey, Programming with Constraints: An Introduction, The MIT Press, Cambridge Mass., 1998.
[Michalewicz-07] Michalewicz, Z. and M. Michalewicz, Puzzle Based Learning, Proceedings
of the 2007 AaeE Conference, Melbourne, 2007.
[Michalewicz-08] Michalewicz, Z. and M. Michalewicz, Puzzle-Based Learning: Introduction
to Critical Thinking, Mathematics, and Problem Solving, Hybrid Publishers, Melbourne,
2008.
[Milano-04] Milano, M.,(ed.) Constrained and Integere Programming. Towards a Unied
Methodology, Kluwer Academic Publishers, Boston, 2004.
[Morgan-08] Morgan, T., Business Rules and Information Systems.Aligning IT with Business
Goals, Addison-Wesley, Boston, 4th Printing, 2008.
[Mozart/Oz-10] Mozart/Oz multi-paradigm language,
http://www.mozart-oz.org/home/doc/fdt/node37.html, 2010.
[Muth-63] Muth, J.F. and G. L. Thompson, Industrial Scheduling, Prentice-Hall, Inc., Englewood Clis, 1963.
[Niederli
nski-99] Niederli
nski, A., Constraint Logic Programming - from Prolog to CHIP, Proceedings of the Workshop on Constraint Programming for Decision and Control,Editor
J. Figwer, Institute of Automation, Silesian University of Technology, Gliwice, 1999, str.
27-34.
[Niederli
nski-06] Niederli
nski, A.,
PKJS.com.pl, Gliwice, 2008.
504
BIBLIOGRAPHY
[von Halle-02] von Halle, B., Business Rules Applied, John Wiley and Sons, New York, 2002.
[Wagner-75] Wagner, H. M., Principles of Operations Resaerch, Prentice Hall, Englewood
Clis, 1975.
BIBLIOGRAPHY
505
Index
=/2, 24
#, 5, 124
$, 5, 291, 448
&, 138
0.0..1.0Inf, 449
accumulator, 34
algorithm, 4
All Things to All People, 192
alldierent/1, 160, 192
annual rate of return, 455
arg/3, 199
array, 196
Articial Intelligence, 6
assembly line, 363, 373, 481
assembly plant, 254
assignment, feasible, 11, 72, 163, 164
assignment, optimum, 12, 280
associativity, 22
atom, 14
backtracking, 26, 27, 45, 59, 66, 116, 246
backtracking, forward checking, 117
backtracking, looking ahead + forward checking, 119
bb_min/3, 251
belongness constraint, 164
bicycle assembling, 389
Black and White, 138
Bobs Shish Kebab, 226
body, 17
branch-and-bound, 48, 246, 247
branch-and-bound, forward checking, 249
branch-and-bound, looking ahead, 249
capacity constraint, 223
CCOP, 449
CCSP, 447
choice point, 26
circuit/1, 434
clause, 17
Closed World Assumption, 18
combinatorial explosion, 3
compatibility, 11
compound interest, 449
conclusion, 17
condition, 17
Condition - Then ; Else, 72
conguration, feasible, 11, 40, 44, 151
conguration, optimum, 12, 47, 256, 259
conjunction, rules, 39
consistency techniques, 114, 117, 123
constant, logical, 14
constant, symbolic, 14
constraint, 1, 5
constraint optimization problem, continuous,
449
constraint optimization problem, discrete, 2
constraint propagation, 114, 123
constraint satisfaction problem, continuous,
447
constraint satisfaction problem, discrete, 1
constraint, active, 5
constraint, disjunctive, 334
constraint, passive, 5
constraint, precedence, 333, 334
constraint, reied, 263
constraint, sets, 265
constraints, conicting, 341
constraints, disjunctive, 339
constraints, elementary, 159
constraints, global, 159
COP, 2
count/3, 203
506
INDEX
507
FS-type problems, 11
FST-type problems, 11
functions, 16
data, 9
declarativity, 4, 13
degrounding, 28
destination node list, 431
dinner calamity, 233
direct enumeration, 2
discount rate, 455
disequality, 371
disequation, 160
disjunctive/2, 366
do/2, 201
dog service, 324
domain, 2
domain of inference, Prolog, 14
domain, continuous, 447
domain, discrete, 1
domain, implicit, 212
domain, narrowing, 448
domains, CLP, 114, 289
domains, Prolog, 114
job-shop,
job-shop,
job-shop,
job-shop,
job-shop,
job-shop,
facts, 17
fail/0, 162
feasible state, continuous, 448
feasible state, discrete, 11
feasible states, 11
FIFTEEN, 167
ndall/3, 34, 217, 272, 301, 302, 336
re and rescue stations location, 274
ve rooms, 181
for/3, 204
for/4, 204
foreach/2, 201
foreacharg/2, 202
fromto/4, 206
ic, 115
imperativity, 4, 13
implication, logic, 18
implication, Prolog, 17
indomain/1, 114, 161
inference, complete, 28
inference, incomplete, 129
inference, system, 13, 25
inx notation, 15, 16
information, 10
input, 19
insetdomain/4, 268
interval arithmetic, 115
is, 24
iteration, 200
408
benchmark MT10, 416
benchmark MT6, 412
jobs, 410
machines, 410
tasks, 410
508
INDEX
INDEX
509