implementing constraints
DESCRIPTION
Implementing Constraints. Overview. A look at the literature CSPs Arc consistency algorithms Implementation in ECLiPSe: Low level:Suspensions and Attributes Prototyping in ECLiPSe: Intermediate:Constraint Handling Rules (CHR) High level:Propia. Constraint Satisfaction Problems (CSP). - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/1.jpg)
Implementing Constraints
![Page 2: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/2.jpg)
2
Overview
A look at the literatureCSPs
Arc consistency algorithms
Implementation in ECLiPSe:Low level: Suspensions and Attributes
Prototyping in ECLiPSe:Intermediate: Constraint Handling Rules (CHR)
High level: Propia
A look at the literatureCSPs
Arc consistency algorithms
Implementation in ECLiPSe:Low level: Suspensions and Attributes
Prototyping in ECLiPSe:Intermediate: Constraint Handling Rules (CHR)
High level: Propia
![Page 3: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/3.jpg)
3
Constraint Satisfaction Problems (CSP)
Much of the literature talks about “CSPs”
This usually refers to binary CSPs:
A fixed set of variables X1,…Xn
Every variable has a finite domain Di arbitrary domain, does not have to be ordered
Binary (2-variable) constraints only cij(Xi,Xj) constraint defined as sets of consistent value pairs
Any CSP can be transformed to binary CSPWe don’t normally do that
Instead generalise binary techniques
![Page 4: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/4.jpg)
4
Static properties of a CSP network
Node consistencyvDi: ci(v)
Not very interesting
Arc consistencyvDi w Dj : cij(v,w)
Most relevant
Path consistencyvDi wDj u Dk: cik(v,u),ckj(u,w)
Usually too expensive
…
![Page 5: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/5.jpg)
5
Arc consistency algorithms
Consistency in networks of relations [AC1-3]A.K. Mackworth, in Artificial Intelligence 8, pages 99-118, 1977.
Arc and path consistency revised [AC4]R. Mohr and T.C. Henderson, in Artificial Intelligence 28, pages 225-233, 1986.
A generic arc-consistency algorithm and its specializations [AC5]P. Van Hentenryck, Y. Deville, and C.-M. Teng, in Artificial Intelligence 57, pages 291-
321, 1992.
Arc-consistency and arc-consistency again [AC6]C. Bessiere, in Artificial Intelligence 65, pages 179-190, 1994.
Using constraint metaknowledge to reduce arc consistency
computation [AC7]C. Bessiere, E.C. Freuder, and J.-R. Régin, in Artificial Intelligence 107, pages 125-
148, 1999.
![Page 6: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/6.jpg)
6
AC-1
procedure REVISE(Vi,Vj) DELETE <- false; for each X in Di do if there is no such Y in Dj such that (X,Y) is consistent, then delete X from Di; DELETE <- true; endif; endfor; return DELETE;
procedure AC-1 end REVISE Q <- {(Vi,Vj) in arcs(G),i#j}; repeat CHANGE <- false; for each (Vi,Vj) in Q do CHANGE <- REVISE(Vi,Vj) or CHANGE; endfor until not(CHANGE) end AC-1
G is the constraint graph, Q is a queue
![Page 7: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/7.jpg)
7
AC-3
procedure AC-3 Q <- {(Vi,Vj) in arcs(G),i#j}; while not Q empty select and delete any arc (Vk,Vm) from Q; if REVISE(Vk,Vm) then Q <- Q union {(Vi,Vk) such that
(Vi,Vk) in arcs(G),i#k,i#m}
endif endwhile end AC-3
Re-check only arcs that were affected Queue contains arcs (constraints) This is a practical algorithm Easy to generalise to n-ary constraints
![Page 8: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/8.jpg)
8
AC-4 - initialization
procedure INITIALIZE Q <- {}; S <- {}; % initialize each element of structure S for each (Vi,Vj) in arcs(G) do % (Vi,Vj) and (Vj,Vi) are same
elements for each a in Di do total <- 0; for each b in Dj do if (a,b) is consistent according to the constraint (Vi,Vj) then total <- total+1; Sj,b <- Sj,b union {<i,a>}; endif endfor; counter[(i,j),a] <- total; if counter[(i,j),a]=0 then delete a from Di; Q <- Q union {<i,a>}; endif; endfor; endfor; return Q; end INITIALIZE
![Page 9: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/9.jpg)
9
AC-4 - fixpoint computation
procedure AC-4 Q <- INITIALIZE; while not Q empty select and delete any pair <j,b> from Q; counter[(i,j),a] <- counter[(i,j),a] - 1; for each <i,a> from Sj,b do if counter[(i,j),a]=0 & a is still in Di then delete a from Di; Q <- Q union {<i,a>}; endif endfor endwhile end AC-4
Maintains support counters for each domain element
Queue contains information about the deleted domain value
![Page 10: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/10.jpg)
10
Relation to Search
These algorithms look at the constraint network statically
They are not strong enough to enforce global consistency
of the network, so we still need search
Search decisions change some domain(s), which means
we may lose any achieved xxx-consistency
Overall design needs to answer 2 questions: What level(s) of consistency do we want to employ? At what time (during search) do we want which consistency?
![Page 11: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/11.jpg)
11
Consistency during search
Generate and testInstantiate all problem variables, then check all constraints
Standard backtrackingCheck every constraint as soon as both its variables are instantiated
Forward Checking (~ Label Propagation) Look ahead
When one variable is instantiated make the constraint arc consistent
When a variable is instantiated, make the whole graph arc consistent again (maintain arc consistency at all times)
(This terminology used in P.v.Hentenryck: Constraint Satisfaction in LP)
![Page 12: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/12.jpg)
12
Other forms of consistency
Interval (bounds) consistencyUseful for ordered domainsWe don’t look at every domain valueOnly make sure that smallest and largest domain value are consistentDepending on the constraint semantics, bounds consistency implies arc
consistency, or not
Used in many ECLiPSe librarieslib(fd) - integer domainlib(ic) - integer and real number domainlib(ic_sets) - integer set domainlib(ic_symbolic) - ordered symbolic domain…
![Page 13: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/13.jpg)
Implementing Constraints with Suspensions and Atrributes
![Page 14: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/14.jpg)
14
What you need to know
To implement additional constraint for existing solver: suspend / resume mechanism the solver’s domain access interface
To implement a solver over a new domain: variable attribute mechanism
![Page 15: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/15.jpg)
15
Basic Programming Support
Suspending the execution of goalsdelay-clause or suspend/3,4
Corresponds to the queue in AC-3!
Data/Event-driven waking on changeattaching to variables + condition
Change notifications Allows to say when computation should happen
messages from variables to constraints (see lib(notify_ports)) Information about what changed (for AC-4 style algorithms)
Priorities for goals Allows to tune efficiency
Suspending the execution of goalsdelay-clause or suspend/3,4
Corresponds to the queue in AC-3!
Data/Event-driven waking on changeattaching to variables + condition
Change notifications Allows to say when computation should happen
messages from variables to constraints (see lib(notify_ports)) Information about what changed (for AC-4 style algorithms)
Priorities for goals Allows to tune efficiency
![Page 16: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/16.jpg)
16
Resolvent in ECLiPSe
q1, …, qm,
schedule(wake)
p1 , … , pn . Delayed Goals
suspend (delay)
s1
s4sl
s2 s3
r1, …, rk,
Prio 1 Prio 2 … Prio 12
![Page 17: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/17.jpg)
17
Consistency check
capacity(1, N) :- N>=0.0, N=<350.0.
capacity(2, N) :- N>=0.0, N=<180.0.
capacity(3, N) :- N>=0.0, N=<50.0.
capacity(1, N) :- N>=0.0, N=<350.0.
capacity(2, N) :- N>=0.0, N=<180.0.
capacity(3, N) :- N>=0.0, N=<50.0.
delay capacity(T,N) if var(T);var(N).delay capacity(T,N) if var(T);var(N).
capacity(T,N) :- (var(T);var(N)), !,
suspend(capacity(T,N), 0, [T,N]->inst).
capacity(1, N) :- N>=0.0, N=<350.0.
capacity(2, N) :- N>=0.0, N=<180.0.
capacity(3, N) :- N>=0.0, N=<50.0.
capacity(T,N) :- (var(T);var(N)), !,
suspend(capacity(T,N), 0, [T,N]->inst).
capacity(1, N) :- N>=0.0, N=<350.0.
capacity(2, N) :- N>=0.0, N=<180.0.
capacity(3, N) :- N>=0.0, N=<50.0.
Declarative style
Imperative style
![Page 18: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/18.jpg)
18
Forward Checking
:- lib(ic).
delay capacity(Type,N) if var(Type),var(N).
capacity(Type, N) :- var(N),
( Type=1 -> N :: 0.0..350.0
; Type=2 -> N :: 0.0..180.0
; Type=3 -> N :: 0.0..50.0
; fail
).
capacity(Type, N) :- nonvar(N),
N>=0.0,
( N=<50.0 -> Type :: [1,2,3]
; N=<180.0 -> Type :: [1,2]
; N=<350.0 -> Type = 1
; fail
).
:- lib(ic).
delay capacity(Type,N) if var(Type),var(N).
capacity(Type, N) :- var(N),
( Type=1 -> N :: 0.0..350.0
; Type=2 -> N :: 0.0..180.0
; Type=3 -> N :: 0.0..50.0
; fail
).
capacity(Type, N) :- nonvar(N),
N>=0.0,
( N=<50.0 -> Type :: [1,2,3]
; N=<180.0 -> Type :: [1,2]
; N=<350.0 -> Type = 1
; fail
).
![Page 19: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/19.jpg)
19
Constraint via Propagation Goals
X Yc
X Y
c_fwd
c_bwd
X Yc_prop
Alternativelyimplemented
as
![Page 20: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/20.jpg)
20
Forward Checking - 2 agents
capacity(Type, N) :-
capacity_forward(Type, N),
capacity_backward(Type, N).
delay capacity_forward(Type, _N) if var(Type).
capacity_forward(Type, N) :-
( Type=1 -> N :: 0.0..350.0
; Type=2 -> N :: 0.0..180.0
; Type=3 -> N :: 0.0..50.0
; fail ).
delay capacity_backward(_Type, N) if var(N).
capacity_backward(Type, N) :- N>=0.0,
( N=<50.0 -> Type :: [1,2,3]
; N=<180.0 -> Type :: [1,2]
; N=<350.0 -> Type = 1
; fail ).
capacity(Type, N) :-
capacity_forward(Type, N),
capacity_backward(Type, N).
delay capacity_forward(Type, _N) if var(Type).
capacity_forward(Type, N) :-
( Type=1 -> N :: 0.0..350.0
; Type=2 -> N :: 0.0..180.0
; Type=3 -> N :: 0.0..50.0
; fail ).
delay capacity_backward(_Type, N) if var(N).
capacity_backward(Type, N) :- N>=0.0,
( N=<50.0 -> Type :: [1,2,3]
; N=<180.0 -> Type :: [1,2]
; N=<350.0 -> Type = 1
; fail ).
![Page 21: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/21.jpg)
21
Explicitly Suspending Goals
Providing more flexibility than delay-clauses Creation
make_suspension(+Goal, +Priority, -Suspension)
Attaching to attributed variableinsert_suspension(+Vars, +Suspension, +Index,
+AttributeName)
Combined create & attachsuspend(+Goal, +Priority, +Condition)suspend(+Goal, +Priority, +Condition, -Suspension)
Delayed goal viewer shows suspended goals
Providing more flexibility than delay-clauses Creation
make_suspension(+Goal, +Priority, -Suspension)
Attaching to attributed variableinsert_suspension(+Vars, +Suspension, +Index,
+AttributeName)
Combined create & attachsuspend(+Goal, +Priority, +Condition)suspend(+Goal, +Priority, +Condition, -Suspension)
Delayed goal viewer shows suspended goals
![Page 22: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/22.jpg)
22
Triggering of suspensions
When goals (constraints) are suspended, they are usually
attached to variables with trigger conditions:
X->instwhen X becomes instantiated (most specific)
X->constrainedwhen X becomes constrained in any way (most general)
X->ic:min, X->ic:max, X->ic:hole, X->typewhen the lower bound / upper bound / other value in the domain of X changes
Other trigger conditions are defined by the various
solvers
When goals (constraints) are suspended, they are usually
attached to variables with trigger conditions:
X->instwhen X becomes instantiated (most specific)
X->constrainedwhen X becomes constrained in any way (most general)
X->ic:min, X->ic:max, X->ic:hole, X->typewhen the lower bound / upper bound / other value in the domain of X changes
Other trigger conditions are defined by the various
solvers
![Page 23: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/23.jpg)
23
Bounds consistency
ge(X, Y) :-
get_max(X, XH), % get current
bounds
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
ge(X, Y) :-
get_max(X, XH), % get current
bounds
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
X >= Y
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [[X,Y]->constrained])
; true ),
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [[X,Y]->constrained])
; true ),
Bounds-consistent greater-equal:Bounds-consistent greater-equal:
![Page 24: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/24.jpg)
24
More precise waking conditions
ge(X, Y) :-
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [X->ic:max,Y->ic:min])
; true ),
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL),
impose_max(Y, XH).
ge(X, Y) :-
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [X->ic:max,Y->ic:min])
; true ),
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL),
impose_max(Y, XH).
X >= YBounds-consistent greater-equal:Bounds-consistent greater-equal:
![Page 25: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/25.jpg)
25
Variables, Attributes and Suspended Goals
X { suspend: inst constrained ic: 1..9 min max hole}
X { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
ge(X,Y) ge(X,Y)
![Page 26: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/26.jpg)
26
Directional propagators
ge(X, Y) :-
ge_fwd(X,Y),
ge_bwd(X,Y).
ge_fwd(X, Y) :-
( var(X) -> suspend(ge_fwd(X,Y), 0, [X->ic:max])
; true ),
get_max(X, XH),
impose_max(Y, XH).
ge_bwd(X, Y) :-
( var(Y) -> suspend(ge_bwd(X,Y), 0, [Y->ic:min])
; true ),
get_min(Y, YL),
impose_min(X, YL).
ge(X, Y) :-
ge_fwd(X,Y),
ge_bwd(X,Y).
ge_fwd(X, Y) :-
( var(X) -> suspend(ge_fwd(X,Y), 0, [X->ic:max])
; true ),
get_max(X, XH),
impose_max(Y, XH).
ge_bwd(X, Y) :-
( var(Y) -> suspend(ge_bwd(X,Y), 0, [Y->ic:min])
; true ),
get_min(Y, YL),
impose_min(X, YL).
X >= Y
![Page 27: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/27.jpg)
27
ge_bwd(X,Y) ge_bwd(X,Y)
ge_fwd(X,Y) ge_fwd(X,Y)
Directional Propagators
X { suspend: inst constrained ic: 1..9 min max hole}
X { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
![Page 28: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/28.jpg)
28
Repeated waking on domain updates
E.g. propagating boundsge(X, Y) :-
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [X->ic:max, Y->ic:min])
; true ),
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
Propertiesvariables remain variablesarbitrary number of steps (limited only by domain size)
Potential performance problem:re-suspending identical goal over and over again!
E.g. propagating boundsge(X, Y) :-
( var(X),var(Y) ->
suspend(ge(X,Y), 0, [X->ic:max, Y->ic:min])
; true ),
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
Propertiesvariables remain variablesarbitrary number of steps (limited only by domain size)
Potential performance problem:re-suspending identical goal over and over again!
X >= Y
![Page 29: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/29.jpg)
29
Domain/bounds propagation using a “demon”
Same constraint as before:ge(X, Y) :-
suspend(ge(X,Y,Susp), 0, [X->ic:max, Y->ic:min], Susp),
ge(X, Y, Susp).
:- demon ge/3. % demon declaration
ge(X, Y, Susp) :-
( var(X),var(Y) -> true % implicitly re-suspend
; kill_suspension(Susp) ), % explicit kill
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
A “demon” does not need to be re-suspendedWhen woken, it splits into a woken and a suspended instance
Needs to be killed explicitly when no longer needed
Same constraint as before:ge(X, Y) :-
suspend(ge(X,Y,Susp), 0, [X->ic:max, Y->ic:min], Susp),
ge(X, Y, Susp).
:- demon ge/3. % demon declaration
ge(X, Y, Susp) :-
( var(X),var(Y) -> true % implicitly re-suspend
; kill_suspension(Susp) ), % explicit kill
get_max(X, XH),
get_min(Y, YL),
impose_min(X, YL), % impose new bounds
impose_max(Y, XH).
A “demon” does not need to be re-suspendedWhen woken, it splits into a woken and a suspended instance
Needs to be killed explicitly when no longer needed
![Page 30: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/30.jpg)
30
Variables, Attributes and Suspended Demon
X { suspend: inst constrained ic: 1..9 min max hole}
X { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
Y { suspend: inst constrained ic: 1..9 min max hole}
ge(X,Y,Susp) ge(X,Y,Susp)
![Page 31: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/31.jpg)
31
Single-propagator max-constraint
mymax(A, B, M):- get_bounds(A, MinA, MaxA),
get_bounds(B, MinB, MaxB),get_bounds(M, MinM, MaxM),
( MinA >= MaxB -> A = M
; MinB >= MaxA -> B = M; MinM > MaxB -> A = M; MinM > MaxA -> B = M;
call_priority((Max is max(MaxA, MaxB),Min is max(MinA, MinB),impose_bounds(M, Min, Max), impose_max(A, MaxM),impose_max(B, MaxM),
Vars = [A,B,M],( nonground(2, Vars, _) ->
suspend(mymax(A, B, M), 3, [Vars->ic:max,Vars->ic:min]); true)
), 2)).
![Page 32: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/32.jpg)
32
N-ary constraints
Even more implementation choices: Level of consistency Algorithm Eagerness
Trigger conditions and priority
Logical decompositione.g. alldifferent many disequality constraints
Operational decompositionOne or several propagator goals
Data-driven vs explicit fixpoint computation
![Page 33: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/33.jpg)
33
Special case: Incremental checking (1)
Value X occurs in List :among(X, [Y|Ys]) :-
( var(Y) ->
suspend(among(X, [Y|Ys]),0,Y->inst)
; X = Y ->
true
;
among(X, Ys)
).
Propertiesefficient, looks at most once at each list element
delayed goal may be different after each step
success after 1..N steps or failure after N steps
Value X occurs in List :among(X, [Y|Ys]) :-
( var(Y) ->
suspend(among(X, [Y|Ys]),0,Y->inst)
; X = Y ->
true
;
among(X, Ys)
).
Propertiesefficient, looks at most once at each list element
delayed goal may be different after each step
success after 1..N steps or failure after N steps
![Page 34: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/34.jpg)
34
Incremental checking (2)
Value X does not occur in List:not_among(X, []).not_among(X, [Y|Ys]) :-
( var(Y) -> suspend(not_among(X, [Y|Ys]),0,Y->inst); X \= Y, not_among(X, Ys)).
PropertiesSuccess after N steps or failure after 1..N stepsBut: there may be an X at the end of the list, behind a variable! Failure can be detected unnecessarily late
Value X does not occur in List:not_among(X, []).not_among(X, [Y|Ys]) :-
( var(Y) -> suspend(not_among(X, [Y|Ys]),0,Y->inst); X \= Y, not_among(X, Ys)).
PropertiesSuccess after N steps or failure after 1..N stepsBut: there may be an X at the end of the list, behind a variable! Failure can be detected unnecessarily late
![Page 35: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/35.jpg)
35
Parallel checking
Value X does not occur in List:not_among(X, []).not_among(X, [Y|Ys]) :-
( var(Y) -> suspend(X\=Y, 0, Y->inst); X \= Y),
not_among(X, Ys).
PropertiesCan expand into up to N delayed goals X\=YFailure detected as soon as possible Normally more interesting than detecting success!
Value X does not occur in List:not_among(X, []).not_among(X, [Y|Ys]) :-
( var(Y) -> suspend(X\=Y, 0, Y->inst); X \= Y),
not_among(X, Ys).
PropertiesCan expand into up to N delayed goals X\=YFailure detected as soon as possible Normally more interesting than detecting success!
![Page 36: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/36.jpg)
37
Implementing a new domain
:- module(enum). % library name
:- meta_attribute(enum, [ % attribute name and handlers
unify: unify_enum/2,
print: print_enum/2,
compare_instances: ...,
copy_term: ...]).
make_enum_variable(Var, Values) :- % constructor
Attr = enum(Values,_),
init_suspension_list(2, Attr),
add_attribute(Var, Attr).
unify_enum(Value, Attribute) :- % unify handler
check if Value is compatible with Attribute
exclude(Var{Attribute}, Value) ?- % domain access primitive
delete Value from possible values in Attribute
...
![Page 37: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/37.jpg)
38
Exercise 1
Write a constraint
atmost(+N, +List, +Value) Meaning: at most N elements of List have value
Value Behaviour: fail as soon as more than N elements are
instantiated to Value Improvement: fail as soon as not enough variables
with Value in their domain are left over
Write a constraint
atmost(+N, +List, +Value) Meaning: at most N elements of List have value
Value Behaviour: fail as soon as more than N elements are
instantiated to Value Improvement: fail as soon as not enough variables
with Value in their domain are left over
![Page 38: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/38.jpg)
39
Exercise 2
Write a constraintoffset(?X,+C,?Y)
which is like
offset(X,C,Y) :- Y #= X+C.But maintains domain consistency (propagates “holes”)
Use Suspension built-ins Domain access primitives from the ic_kernel module
![Page 39: Implementing Constraints](https://reader035.vdocument.in/reader035/viewer/2022062518/5681401e550346895dab75ec/html5/thumbnails/39.jpg)
40
Domain attribute access in lib(ic)
Getting domain representation from a variableget_domain_as_list(+Var, -ListOfValues)
get_bounds(+Var, -Min, -Max)
get_min(+Var, -Min)
get_max(+Var, -Max)
get_domain_size(+Var, -Size)
...
Updating a variable’s domainimpose_bounds(+Var, +Min, +Max)
impose_min(+Var, +Min)
impose_max(+Var, +Max)
exclude(+Var, +Value)
...
Getting domain representation from a variableget_domain_as_list(+Var, -ListOfValues)
get_bounds(+Var, -Min, -Max)
get_min(+Var, -Min)
get_max(+Var, -Max)
get_domain_size(+Var, -Size)
...
Updating a variable’s domainimpose_bounds(+Var, +Min, +Max)
impose_min(+Var, +Min)
impose_max(+Var, +Max)
exclude(+Var, +Value)
...