1% BEGIN LICENSE BLOCK
2% Version: CMPL 1.1
3%
4% The contents of this file are subject to the Cisco-style Mozilla Public
5% License Version 1.1 (the "License"); you may not use this file except
6% in compliance with the License.  You may obtain a copy of the License
7% at www.eclipse-clp.org/license.
8% 
9% Software distributed under the License is distributed on an "AS IS"
10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11% the License for the specific language governing rights and limitations
12% under the License. 
13% 
14% The Original Code is  The ECLiPSe Constraint Logic Programming System. 
15% The Initial Developer of the Original Code is  Cisco Systems, Inc. 
16% Portions created by the Initial Developer are
17% Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18% 
19% Contributor(s): 
20% 
21% END LICENSE BLOCK
22
23%----------------------------------------------------------------------
24\chapter{Implementing Constraints}
25\label{chapimpl}
26%HEVEA\cutdef[1]{section}
27%----------------------------------------------------------------------
28
29This chapter describes how to use \eclipse{}'s advanced control
30\index{implementing constraints}
31facilities for implementing constraints.
32Note that the Generalised Propagation library lib(propia) and
33the Constraint Handling Rules library lib(ech) provide other,
34higher-level ways to implement constraints. Those are more
35suited for prototyping, while this chapter introduces those low-level
36primitives that are actually used in the implementation of the various
37\eclipse{} constraint solvers.
38
39
40%----------------------------------------------------------------------
41\section{What is a Constraint in Logic Programming?}
42%----------------------------------------------------------------------
43
44Constraints fit very naturally into the Logic Programming paradigm.
45Declaratively, a constraint is just the same as any other predicate.
46Indeed, in \eclipse{}, ``constraints'' are not a particular
47programming language construct, constraints are just a conceptual notion.
48
49Consider the following standard Prolog query:
50\begin{quote}\begin{verbatim}
51?- member(X, [5,7,3,4]), X =< 4.
52\end{verbatim}\end{quote}
53This will succeed with X = 3 after some search.
54In this example, both the member/2 goal and the inequality goal could
55be considered `constraints on X' because they both restrict the
56possible values for X. Usually, however, member/2 would not be considered
57a ``constraint'' because of its backtracking (search) behaviour:
58\begin{quote}\begin{verbatim}
59?- member(X, [5, 7, 3, 4]).
60X = 5
61More (0.00s cpu)
62X = 7
63More (0.04s cpu)
64\end{verbatim}\end{quote}
65Also, the standard Prolog inequality would not be considered a ``constraint'',
66because if invoked on its own it will raise an error:
67\begin{quote}\begin{verbatim}
68?- X =< 4.
69instantiation fault in X =< 4
70\end{verbatim}\end{quote}
71\index{constraint}
72In the following, we will call a predicate a {\bf constraint} only if it
73\begin{itemize}
74\item behaves deterministically
75\item somehow actively enforces its declarative meaning
76\end{itemize}
77
78
79%----------------------------------------------------------------------
80\section{Background: Constraint Satisfaction Problems}
81\index{constraint satisfaction problem}
82\index{CSP}
83\label{csp}
84%----------------------------------------------------------------------
85
86There is a large body of scientific work and literature about
87Constraint Satisfaction Problems, or CSPs.
88CSPs are a restricted class of constraint problems with the
89following properties
90\enableunderscores
91\begin{itemize}
92\item there is a fixed set of variables $X_1, ..., X_n$
93\item every variable $X_i$ has a finite domain $D_i$ of values that the variable
94        is allowed to take. In general, this can be an arbitrary, unordered
95        domain.
96\item usually one considers only binary (2-variable) constraints $c_{ij}(X_i,X_j)$.
97        Every constraint is simply defined as a set of pairs of consistent values.
98\item the problem is to find a valuation (labeling) of the variables such
99        that all the constraints are satisfied.
100\end{itemize}
101\disableunderscores
102The restriction to binary constraints is not really limiting since every CSP
103can be transformed into a binary CSP. However, this is often not necessary
104since many algorithms can be generalised to n-ary constraints.
105
106A CSP network is the graph formed by considering the variables as nodes
107and the constraints as arcs between them.
108In such a network, several levels of consistency can be defined:
109\index{node consistency}
110\index{arc consistency}
111\index{path consistency}
112\enableunderscores
113\begin{description}
114\item[Node consistency] $\forall{v \in D_i} : c_i(v)$
115        (not very interesting).  It means that
116	all unary constraints are reflected in the domains
117\item[Arc consistency] $\forall{v \in D_i}\ \exists{w \in D_j} : c_{ij}(v,w)$
118	(most practically relevant).
119	It means that for every value in the domain of one
120	variable, there is a compatible value in the domain of the
121	other variable in the constraint.  In practice, constraints
122	are symmetric, so the reverse property also holds.
123\item[Path consistency] $\forall{v \in D_i}\ \forall{w \in D_j}\ \exists{u \in D_k} : c_{ik}(v,u), c_{kj}(u,w)$
124        (usually too expensive). One can show that this property extends to
125	whole paths, i.e.\ on any path of constraints between variables i and j 
126	the variables have domain values which are compatible with any
127	domain values for i and j.
128\end{description}
129\disableunderscores
130Note that neither of these conditions is sufficient for the
131problem to be satisfiable. It is still necessary to search for solutions.
132Computing networks with these consistency levels can however be a useful
133intermediate step to finding a solution to the CSP.
134
135Consequently, a complete CSP solver needs the following design decisions:
136\begin{itemize}
137\item what level of consistency do we want to employ?
138\item at what time during search do we want to (re)establish this consistency?
139\item what algorithm do we use to establish this consistency?
140\end{itemize}
141In practice, the most relevant consistency level is arc-consistency.
142Consequently, a number of algorithms have been proposed for the
143purpose of establishing arc-consistency. The algorithms used in \eclipse{}
144\index{AC-3}
145are mostly variants of AC-3 \cite{mackworth77}
146\index{AC-5}
147and AC-5 \cite{vanhentenryck92generic}.
148
149\ignore{
150procedure REVISE(Vi,Vj)
151    DELETE <- false;
152    for each X in Di do
153        if there is no such Y in Dj such that (X,Y) is consistent,
154        then
155            delete X from Di;
156            DELETE <- true;
157        endif;
158    endfor;
159    return DELETE;
160    end REVISE
161
162procedure AC-3
163    Q <- {(Vi,Vj) in arcs(G),i#j};
164    while not Q empty
165        select and delete any arc (Vk,Vm) from Q;
166        if REVISE(Vk,Vm) then
167            Q <- Q union {(Vi,Vk) such that (Vi,Vk) in arcs(G),i#k,i#m}
168        endif
169    endwhile
170    end AC-3
171}
172
173
174%----------------------------------------------------------------------
175\section{Constraint Behaviours}
176\index{behaviour of a constraint}
177%----------------------------------------------------------------------
178
179As opposed to the theoretical CSP framework sketched in the previous section,
180in \eclipse{} we usually deal with more heterogeneous situation.
181We want to allow the integration of very different constraints,
182and we want to achieve a separation of constraint propagation and search.
183Therefore, we are not interested in an overall problem solving algorithm
184which controls search and constraint propagation globally for the whole
185problem and all constraints.
186We prefer to view the constraint solving process as in figure \ref{figclpexec}:
187the search process is controlled by an algorithmic program,
188while constraint propagation is performed by data-driven agents which
189do local (again algorithmic) computations on one or several constraints.
190\begin{figure}
191\begin{center}
192\resizebox{0.4\textwidth}{!}{\includegraphics{clpexec.eps}}
193\end{center}
194\caption{Control during Constraint Solving}
195\label{figclpexec}
196\end{figure}
197Individual constraints can then be implemented with different behaviours,
198and freely mixed within a single computation.
199Constraint behaviours can essentially be characterised by
200\index{trigger condition}
201\begin{itemize}
202\item their triggering condition ({\bf when} are they executed)
203\item the action they perform when triggered ({\bf what} do they do)
204\end{itemize}
205Let us now look at examples of different constraint behaviours.
206
207\subsection{Consistency Check}
208\index{consistency check}
209The \verb.=<./2 predicate, whose standard Prolog version raises an error
210when invoked with uninstantiated variable, is also implemented by the
211{\bf suspend} library. Both implementations
212have the same declarative meaning, but the {\bf suspend} version can
213be considered to be a proper constraint.
214It implements a {\bf passive test}, i.e.\
215it simply delays until both arguments are numbers, and then succeeds or fails:
216\begin{quote}\begin{verbatim}
217?- suspend : (X =< 4).
218X = X
219There is 1 delayed goal.
220Yes (0.00s cpu)
221
222?- suspend : (X =< 4), X = 2.
223X = 2
224Yes (0.00s cpu)
225
226?- suspend : (X =< 4), X = 5.
227No (0.00s cpu)
228\end{verbatim}\end{quote}
229
230\subsection{Forward Checking}
231\index{forward checking}
232Often a constraint can already do useful work before all its arguments
233are instantiated. In particular, this is the case when we are working
234with domain variables. Consider {\bf ic}'s disequality constraint \verb.#\=.  :
235Even when only one side is instantiated, it can already remove this value
236from the domain of the other (still uninstantiated) side:
237\begin{quote}\begin{verbatim}
238?- X :: 1 .. 5,
239   X #\= 3.
240X = X{[1, 2, 4, 5]}
241Yes (0.00s cpu)
242\end{verbatim}\end{quote}
243If both sides are uninstantiated, the constraint cannot do anything useful.
244It therefore waits (delays) until one side becomes instantiated,
245but then wakes up and acts as before.
246This behaviour is sometimes called forward checking \cite{VanHentenryck}:
247\begin{quote}\begin{verbatim}
248?- [X,Y] :: 1 .. 5,
249   X #\= Y.        % delays
250X = X{1 .. 5}
251Y = Y{1 .. 5}
252There is 1 delayed goal.
253Yes (0.00s cpu)
254
255?- X :: 1 .. 5,
256   X #\= Y,         % delays
257   Y = 3.           % wakes
258X = X{[1, 2, 4, 5]}
259Y = 3
260Yes (0.01s cpu)
261\end{verbatim}\end{quote}
262
263\subsection{Domain (Arc) Consistency}
264\index{arc consistency}
265\index{domain consistency}
266For many constraints, even more eager behaviour is possible.
267For example, {\bf ic}'s inequality constraints performs {\bf domain updates} as
268soon as possible, even when one or both arguments are still variables:
269\begin{quote}\begin{verbatim}
270?- [X, Y] :: 1 .. 5, X #< Y.
271X = X{1 .. 4}
272Y = Y{2 .. 5}
273There is 1 delayed goal.
274Yes (0.00s cpu)
275
276?- [X, Y] :: 1 .. 5, X #< Y, X #> 2.
277Y = Y{[4, 5]}
278X = X{[3, 4]}
279There is 1 delayed goal.
280Yes (0.00s cpu)
281\end{verbatim}\end{quote}
282Inconsistent values are removed form the domains as soon as possible.
283This behaviour corresponds to {\bf arc consistency} as discussed in
284section \ref{csp}.
285
286\subsection{Bounds Consistency}
287\index{bounds consistency}
288Note however that not all {\bf ic} constraints maintain full domain
289arc consistency.  For performance reasons, 
290the \verb.#=. constraint only maintains bounds consistency, which is
291weaker, as illustrated by the following example:
292\begin{quote}\begin{verbatim}
293?- [X, Y] :: 1 .. 5, X #= Y + 1, X #\= 3.
294Y = Y{1 .. 4}
295X = X{[2, 4, 5]}
296There is 1 delayed goal.
297Yes (0.00s cpu)
298\end{verbatim}\end{quote}
299Here, the value 2 for Y was not removed even though it is not arc consistent
300(there is no value for X which is compatible with it).
301
302\index{incompleteness of propagation}
303It is important to understand that this kind of propagation incompleteness
304does not affect correctness: the constraint will simply detect the
305inconsistency later, when its arguments have become more instantiated.
306In terms of the search tree, this means that a branch will not be pruned
307as early as possible, and extra time might be spent searching.
308
309
310\quickref{Typical Constraint Behaviours}{
311\begin{description}
312\item[Consistency Checking] 
313        wait until all variables instantiated, then check
314\item[Forward Checking] 
315        wait until one variable left, then compute consequences
316\item[Domain (Arc) Consistency] 
317        wait until a domain changes, then compute consequences for other domains
318\item[Bounds Consistency] 
319        wait until a domain bound changes, then compute consequences for other bounds
320\end{description}
321}
322
323
324\ignore{
325\subsection{The Resolvent}
326\index{resolvent}
327The term {\bf resolvent} originates from Logic Programming.
328It is the set of all goals that need to be satisfied.
329The computation typically starts with a top-level goal,
330then gets successively transformed (by substituting goals that
331match a clause head with an instance of the clause body, ie.\ a
332sequence of sub-goals),
333and eventually terminates with one of the trivial goals
334{\bf true} or {\bf fail}.
335For example, given the program
336\begin{quote}\begin{verbatim}
337p :- q,r.
338q.
339r :- q.
340\end{verbatim}\end{quote}
341and the goal p, the resolvent goes through the following states
342before the goal is proven and the computation terminates:
343\begin{quote}\begin{verbatim}
344p ----> q,r ----> r ----> q ----> {}
345\end{verbatim}\end{quote}
346
347\index{Prolog}
348While in Prolog the resolvent is always processed from left to right,
349the resolvent in {\eclipse} is more structured, and can be manipulated
350in a much more flexible way.
351This is achieved by two basic mechanisms, {\bf suspension}
352and {\bf priorities}.
353
354\index{suspended goal}
355{\bf Suspended} goals form the part of the resolvent which is
356currently not being considered. This is typically done when we
357know that we cannot currently infer any interesting information from them.
358
359\index{priority}
360The remaining goals are ordered according to their {\bf priority}.
361At any time, the system attempts to solve the most urgent subgoal first.
362{\eclipse} currently supports a fixed range of 12 different priorities,
363priority 1 being the most urgent and 12 the least urgent.
364
365Figure \ref{figresolv} shows the structure of the resolvent.
366When a toplevel goal is launched, it has priority 12 and is the only
367member of the resolvent. As execution proceeds, active goals may be
368suspended, and suspended goals may be woken and scheduled with a
369particular priority.
370\begin{figure}
371% picture has been made with xfig and exported as encapsulated postscript
372\includegraphics{resolv.eps}
373\caption{Structure of the resolvent}
374\label{figresolv}
375\end{figure}
376}
377
378
379
380%----------------------------------------------------------------------
381\section{Programming Basic Behaviours}
382%----------------------------------------------------------------------
383
384As an example, we will look at creating constraint versions of the
385following predicate.
386It defines a relationship between containers of type 1, 2 or 3,
387and their capacity:
388\begin{code}
389capacity(1, N) :- N>=0.0, N=<350.0.
390capacity(2, N) :- N>=0.0, N=<180.0.
391capacity(3, N) :- N>=0.0, N=<50.0.
392\end{code}
393This definition gives the intended declarative meaning,
394but does not behave as a constraint:
395{\tt capacity(3, C)} will raise an error, and
396{\tt capacity(Type, 30.5)} will generate several solutions nondeterministically.
397Only calls like {\tt capacity(3, 27.1)} will act correctly as a test.
398
399
400\subsection{Consistency Check}
401\index{consistency check}
402
403To program the passive consistency check behaviour, we need to wait until
404both arguments of the predicate are instantiated.
405This can be achieved by adding an \eclipse{} {\bf delay clause}:
406\begin{code}
407delay capacity(T,N) if var(T);var(N).
408capacity(1, N) :- N>=0.0, N=<350.0.
409capacity(2, N) :- N>=0.0, N=<180.0.
410capacity(3, N) :- N>=0.0, N=<50.0.
411\end{code}
412The delay clause specifies that any call to capacity/2 will delay as long
413as one of the arguments is a variable. When the variables become instantiated
414later, execution will be resumed automatically, and 
415the instantiations will be checked for satisfying the constraint.
416
417
418\subsection{Forward Checking}
419\index{forward checking}
420
421For Forward Checking, we will assume that we have interval domain variables,
422as provided by the {\bf ic} library (without domain variables, there would
423not be much interesting propagation to be done).
424
425Here is one implementation of a forward checking version:
426\begin{code}
427:- lib(ic).
428delay capacity(T, N) if var(T), var(N).
429capacity(T, N) :- nonvar(N), !,
430        N >= 0,
431        ( N =< 50.0 -> T :: [1,2,3]
432        ; N =< 180.0 -> T :: [1,2]
433        ; N =< 350.0 -> T = 1
434        ; fail
435        ).
436capacity(1, N) :- N\$>=0.0, N\$=<350.0.
437capacity(2, N) :- N\$>=0.0, N\$=<180.0.
438capacity(3, N) :- N\$>=0.0, N\$=<50.0.
439\end{code}
440Note that the delay clause now only lets goals delay when both
441arguments are variables. As soon as one is instantiated, the
442goal wakes up and, depending on which is the instantiated argument,
443either the first, or one of the last three clauses is executed.
444Some examples of the behaviour:
445\begin{quote}\begin{verbatim}
446?- capacity(T, C).
447There is 1 delayed goal.
448Yes (0.00s cpu)
449
450?- capacity(3, C).
451C = C{0.0 .. 50.0}
452Yes (0.00s cpu)
453
454?- capacity(T, C), C = 100.
455T = T{[1, 2]}
456C = 100
457Yes (0.00s cpu)
458\end{verbatim}\end{quote}
459
460A disadvantage of the above implementation is that when the predicate wakes
461up, it can be either because T was instantiated, or because C was
462instantiated. An extra check ({\tt nonvar(N)}) is needed to distinguish the two cases.
463Alternatively, we could have created two agents (delayed goals), each one
464specialised for one of these cases:
465\begin{code}
466capacity(T, N) :-
467        capacity_forward(T, N),
468        capacity_backward(T, N).
469
470delay capacity_forward(T, _N) if var(T).
471capacity_forward(1, N) :- N\$>=0.0, N\$=<350.0.
472capacity_forward(2, N) :- N\$>=0.0, N\$=<180.0.
473capacity_forward(3, N) :- N\$>=0.0, N\$=<50.0.
474
475delay capacity_backward(_T, N) if var(N).
476capacity_backward(T, N) :-
477        N >= 0,
478        ( N =< 50.0 -> T :: [1,2,3]
479        ; N =< 180.0 -> T :: [1,2]
480        ; N =< 350.0 -> T = 1
481        ; fail
482        ).
483\end{code}
484Unfortunately, there is a drawback to this implementation as well:
485once one of the two delayed goals has done its work, all the constraint's
486information has been incorporated into the remaining variable's domain.
487However, the other delayed goal is still waiting, and will eventually
488wake up when the remaining variable gets instantiated as well, at which time
489it will then do a redundant check.
490
491The choice between having one or several agents for a constraint is a
492choice we will face every time we implement a constraint.
493
494
495
496%----------------------------------------------------------------------
497\section{Basic Suspension Facility}
498%----------------------------------------------------------------------
499
500For the more complex constraint behaviours (beyond those waiting for
501instantiations), we need to employ lower-level primitives of the \eclipse{}
502kernel (suspensions and priorities).
503\index{suspension}
504\index{priority}
505If we want to add a new constraint to an existing solver, we also
506need to use the lower-level interface that the particular solver
507provides.
508
509Apart from the delay clauses used above,
510\eclipse{} also provides a more powerful (though less declarative) way of
511causing a goal to delay.
512The following is another implementation of the constraint checking behaviour,
513this time using the suspend/3 built-in predicate to create a delayed goal for
514\index{suspend/3}
515capacity/2:
516\begin{code}
517capacity(T,N) :- (var(T);var(N)), !,
518        suspend(capacity(T,N), 0, [T,N]->inst).
519capacity(1, N) :- N>=0.0, N=<350.0.
520capacity(2, N) :- N>=0.0, N=<180.0.
521capacity(3, N) :- N>=0.0, N=<50.0.
522\end{code}
523\quickref{The Basic Suspension Facilities}{
524\begin{description}
525\item[{\bf suspend(Goal, Priority, Triggers)}] 
526	\index{suspend/3}
527        Creates Goal as a delayed goal with a given waking priority and
528        triggering conditions.
529        Triggers is a list of Variables->Conditions terms, specifying
530        under which conditions the goal will be woken up.
531        The priority specifies with which priority the goal will be scheduled
532        after it has been triggered.
533        A priority of 0 selects the default for the predicate.
534        Otherwise, valid priorities range are from
535        1 (most urgent, reserved for debugging purposes) to 12 (least urgent).
536\end{description}
537Some valid triggers:
538\index{trigger condition}
539\begin{description}
540\item[X->inst] wake when the variable becomes instantiated (most specific)
541\item[X->constrained] wake when the variable becomes constrained somehow
542        (most general)
543\item[X->ic:min] wake when the lower bound of an ic-variable changes
544\item[X->ic:max] wake when the upper bound of an ic-variable changes
545\item[X->ic:hole] wake an internal domain value gets removed
546\end{description}
547}
548
549
550\section{A Bounds-Consistent IC constraint}
551
552To show the basic ideas, we will simply reimplement a constraint that
553already exists in the {\bf ic} solver, the inequality constraint.
554We want a constraint ge/2 that takes two {\bf ic} variables (or numbers)
555and constrains the first to be greater or equal to the second.
556
557\index{bounds consistency}
558The behaviour should be to maintain bounds-consistency:
559If we have a goal {\tt ge(X,Y)}, where the domain of \verb/X is X{1..5}/ and
560the domain of \verb/Y is Y{3..7}/, we would like the domains to be updated such
561that the upper bound of Y gets reduced to 5, and the lower bound of X
562gets increased to 3. The following code achieves this:
563\begin{code}
564ge(X, Y) :-
565        get_bounds(X, _, XH),
566        get_bounds(Y, YL, _),
567        ( var(X),var(Y) ->
568            suspend(ge(X,Y), 0, [X->ic:max, Y->ic:min])
569        ;
570            true
571        ),
572        X #>= YL,    % impose new bounds
573        Y #=< XH.
574\end{code}
575We have used a single primitive from the low-level interface of the
576{\bf ic} library:  {\bf get_bounds/3}, which extracts the current
577domain bounds from a variable.  Further, we have used the information
578that the library implements trigger conditions called {\bf min}
579and {\bf max}, which cause a goal to wake up when the lower/upper
580bound on an {\bf ic} variable changes.
581
582Note that we suspend a new instance of the {\tt ge(X,Y)} goal {\em before}
583we impose the new bounds on the variables. This is important when the
584constraint is to be used together with other constraints of higher
585priority: imposing a bound may immediately wake and execute such
586a higher-priority constraint. The higher-priority constraint may then
587in turn change one of the bounds that ought to wake ge/2 again.
588This only works if ge/2 has already been (re-)suspended at that time.
589
590
591\section{Using a Demon}
592\index{demon}
593Every time the relevant variable bounds change, the delayed ge/2 goal
594wakes up and (as long as there are still two variables) a new,
595identical goal gets delayed.
596To better support this situation, {\eclipse} provides a special type
597of predicate, called a {\bf demon}.
598A predicate is turned into a
599\index{demon}
600demon by annotating it with a
601\bipref{demon/1}{../bips/kernel/compiler/demon-1.html}
602declaration.
603A demon goal differs from a normal goal only in its behaviour on
604waking. While a normal goal disappears from the resolvent when it is
605woken, the demon remains in the resolvent.
606Declaratively, this corresponds to an implicit recursive call in
607the body of each demon clause.
608Or, in other words, the demon goal forks into one goal that remains in the
609suspended part of the resolvent, and an identical one
610that gets scheduled for execution.
611
612With a demon, our above example can be done more
613efficiently. One complication arises, however. Since the goal
614implicitly re-suspends, it now has to be explicitly killed when
615it is no longer needed. The easiest way to achieve this is to
616let it have a handle to itself (its `suspension') in one of its arguments.
617This can then be used to kill the suspension when required:
618\begin{code}
619ge(X, Y) :-
620        suspend(ge(X,Y,MySusp), 0, [X->ic:max, Y->ic:min], MySusp),
621        ge(X, Y, MySusp).
622
623:- demon ge/3.
624ge(X, Y, MySusp) :-
625        get_bounds(X, _, XH),
626        get_bounds(Y, YL, _),
627        ( var(X),var(Y) ->
628            true     % implicitly re-suspend
629        ;
630            kill_suspension(MySusp)
631        ),
632        X #>= YL,    % impose new bounds
633        Y #=< XH.
634\end{code}
635We have used the new primitives suspend/4 and kill_suspension/1.
636
637
638%----------------------------------------------------------------------
639%\section{Constraints with many variables}
640%----------------------------------------------------------------------
641
642%----------------------------------------------------------------------
643\section{Exercises}
644%----------------------------------------------------------------------
645
646\begin{enumerate}
647
648\item Implement a constraint atmost/3 
649\begin{quote}\begin{verbatim}
650atmost(+N, +List, +V)
651\end{verbatim}\end{quote}
652   which takes an integer N, an integer V and a list List
653   containing integers or integer domain variables.
654
655   Meaning: at most N elements of List have value V.
656
657   Behaviour: Fail as soon as too many list elements are
658   instantiated to value V.
659   This requires only basic suspension facilities, no domain
660   information needs to be taken into account.
661
662   Tests are provided in the file {\tt atmost.tst}.
663   You can test your constraint by loading the library {\tt lib(test_util)}
664   and then calling {\tt test(atmost)}.
665
666
667\item Implement a constraint offset/3
668
669\begin{quote}\begin{verbatim}
670offset(?X,+Const,?Y)
671\end{verbatim}\end{quote}
672which is declaratively like
673\begin{quote}\begin{verbatim}
674offset(X,Const,Y) :- Y #= X+Const.
675\end{verbatim}\end{quote}
676  but maintains domain-arc-consistency (i.e. propagates
677  "holes", while the above definition only maintains
678  bounds-consistency).
679
680  Use suspension built-ins and domain-access primitives
681  from the ic_kernel module.
682  Use not_unify/2 to test whether a value is outside
683  a variable's domain.
684
685   Tests are provided in the file {\tt offset.tst}.
686   You can test your constraint by loading the library {\tt lib(test_util)}.
687   and then calling {\tt test(offset)}.
688
689\end{enumerate}
690
691%HEVEA\cutend
692