Download presentation
Presentation is loading. Please wait.
Published byClaire Short Modified over 9 years ago
1
Implementing Constraints
2
2 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 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
3
3 Constraint Satisfaction Problems (CSP) Much of the literature talks about “CSPs” This usually refers to binary CSPs: A fixed set of variables X 1,…X n Every variable has a finite domain D i arbitrary domain, does not have to be ordered Binary (2-variable) constraints only c ij (X i,X j ) constraint defined as sets of consistent value pairs Any CSP can be transformed to binary CSP We don’t normally do that Instead generalise binary techniques
4
4 Static properties of a CSP network Node consistency v D i : c i (v) Not very interesting Arc consistency v D i w D j : c ij (v,w) Most relevant Path consistency v D i w D j u D k : c ik (v,u),c kj (u,w) Usually too expensive …
5
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.
6
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
7
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
8
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 }; endif endfor; counter[(i,j),a] <- total; if counter[(i,j),a]=0 then delete a from Di; Q }; endif; endfor; return Q; end INITIALIZE
9
9 AC-4 - fixpoint computation procedure AC-4 Q <- INITIALIZE; while not Q empty select and delete any pair from Q; counter[(i,j),a] <- counter[(i,j),a] - 1; for each from Sj,b do if counter[(i,j),a]=0 & a is still in Di then delete a from Di; Q }; endif endfor endwhile end AC-4 Maintains support counters for each domain element Queue contains information about the deleted domain value
10
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?
11
11 Consistency during search Generate and test Instantiate all problem variables, then check all constraints Standard backtracking Check 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)
12
12 Other forms of consistency Interval (bounds) consistency Useful for ordered domains We don’t look at every domain value Only make sure that smallest and largest domain value are consistent Depending on the constraint semantics, bounds consistency implies arc consistency, or not Used in many ECLiPSe libraries lib(fd) - integer domain lib(ic) - integer and real number domain lib(ic_sets) - integer set domain lib(ic_symbolic) - ordered symbolic domain …
13
Implementing Constraints with Suspensions and Atrributes
14
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
15
15 Basic Programming Support Suspending the execution of goals delay-clause or suspend/3,4 Corresponds to the queue in AC-3! Data/Event-driven waking on change attaching 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 goals delay-clause or suspend/3,4 Corresponds to the queue in AC-3! Data/Event-driven waking on change attaching 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
16
16 Resolvent in ECLiPSe q 1, …, q m, schedule (wake) p 1, …, p n. Delayed Goals suspend (delay) s1s1 s4s4 slsl s2s2 s3s3 r 1, …, r k, Prio 1Prio 2 …Prio 12
17
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). 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
18
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= Type :: [1,2,3] ; N= Type :: [1,2] ; N= 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= Type :: [1,2,3] ; N= Type :: [1,2] ; N= Type = 1 ; fail ).
19
19 Constraint via Propagation Goals XY c XY c_fwd c_bwd XY c_prop Alternatively implemented as
20
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= Type :: [1,2,3] ; N= Type :: [1,2] ; N= 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= Type :: [1,2,3] ; N= Type :: [1,2] ; N= Type = 1 ; fail ).
21
21 Explicitly Suspending Goals Providing more flexibility than delay-clauses Creation make_suspension(+Goal, +Priority, -Suspension) Attaching to attributed variable insert_suspension(+Vars, +Suspension, +Index, +AttributeName) Combined create & attach suspend(+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 variable insert_suspension(+Vars, +Suspension, +Index, +AttributeName) Combined create & attach suspend(+Goal, +Priority, +Condition) suspend(+Goal, +Priority, +Condition, -Suspension) Delayed goal viewer shows suspended goals
22
22 Triggering of suspensions When goals (constraints) are suspended, they are usually attached to variables with trigger conditions: X->inst when X becomes instantiated (most specific) X->constrained when X becomes constrained in any way (most general) X->ic:min, X->ic:max, X->ic:hole, X->type when 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->inst when X becomes instantiated (most specific) X->constrained when X becomes constrained in any way (most general) X->ic:min, X->ic:max, X->ic:hole, X->type when the lower bound / upper bound / other value in the domain of X changes Other trigger conditions are defined by the various solvers
23
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:
24
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 >= Y Bounds-consistent greater-equal:
25
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)
26
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
27
27 ge_bwd(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 }
28
28 Repeated waking on domain updates E.g. propagating bounds 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 new bounds impose_max(Y, XH). Properties variables remain variables arbitrary number of steps (limited only by domain size) Potential performance problem: re-suspending identical goal over and over again! E.g. propagating bounds 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 new bounds impose_max(Y, XH). Properties variables remain variables arbitrary number of steps (limited only by domain size) Potential performance problem: re-suspending identical goal over and over again! X >= Y
29
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-suspended When 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-suspended When woken, it splits into a woken and a suspended instance Needs to be killed explicitly when no longer needed
30
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)
31
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) ).
32
32 N-ary constraints Even more implementation choices: Level of consistency Algorithm Eagerness Trigger conditions and priority Logical decomposition e.g. alldifferent many disequality constraints Operational decomposition One or several propagator goals Data-driven vs explicit fixpoint computation
33
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) ). Properties efficient, 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) ). Properties efficient, 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
34
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) ). Properties Success after N steps or failure after 1..N steps But: 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) ). Properties Success after N steps or failure after 1..N steps But: there may be an X at the end of the list, behind a variable! Failure can be detected unnecessarily late
35
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). Properties Can expand into up to N delayed goals X\=Y Failure 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). Properties Can expand into up to N delayed goals X\=Y Failure detected as soon as possible Normally more interesting than detecting success!
36
36 Implementing a new domain: Attributed Variables _ X: suspend: suspend(Inst,Bound,Constr)... myattr:... ic: ic(…,WLo,WHi,WHole) X: _23 X: Value slot Attributes X X{ic : …, myattr : …}
37
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...
38
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
39
39 Exercise 2 Write a constraint offset(?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
40
40 Domain attribute access in lib(ic) Getting domain representation from a variable get_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 domain impose_bounds(+Var, +Min, +Max) impose_min(+Var, +Min) impose_max(+Var, +Max) exclude(+Var, +Value)... Getting domain representation from a variable get_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 domain impose_bounds(+Var, +Min, +Max) impose_min(+Var, +Min) impose_max(+Var, +Max) exclude(+Var, +Value)...
41
41 Matching A rule-based implementation of boolean AND and(1, B, C) ?- !, B = C. and(0, _, C) ?- !, C = 0. and(A, 1, C) ?- !, A = C. and(_, 0, C) ?- !, C = 0. and(A, A, C) ?- !, C = A. and(A, B, 1) ?- !, A = 1, B = 1. and(A, B, C) ?- suspend(and(A, B, C), 3, [vars(A,B,C)->constrained]). A rule-based implementation of boolean AND and(1, B, C) ?- !, B = C. and(0, _, C) ?- !, C = 0. and(A, 1, C) ?- !, A = C. and(_, 0, C) ?- !, C = 0. and(A, A, C) ?- !, C = A. and(A, B, 1) ?- !, A = 1, B = 1. and(A, B, C) ?- suspend(and(A, B, C), 3, [vars(A,B,C)->constrained]). matching
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.