Three workers, three jobs, and a duration table per job. Integer constraints
from library(clpz) link who does what to how long it takes, and keep only
assignments that finish within 12 time units.
Run it in the playground · Source
Jobs A, B, and C each get a different worker numbered 1 to 3. Job A takes 5, 3, or 4 time units depending on the worker, job B 4, 6, or 2, job C 7, 2, or 5. A side condition ties the worker numbers together, job A may not be faster than job B, and the total must be at most 12. Which assignments qualify? A second clause shows how to read back what the solver knows about a variable’s domain, its set of possible values.
clpz_example(allocation, plan([A, B, C], durations([DA, DB, DC]), Total)) :-
[A, B, C] ins 1..3,
all_distinct([A, B, C]),
scalar_product([1, 2, 3], [A, B, C], #=, 11),
element(A, [5, 3, 4], DA),
element(B, [4, 6, 2], DB),
element(C, [7, 2, 5], DC),
chain(#>=, [DA, DB]),
sum([DA, DB, DC], #=, Total),
Fast in 0..1,
Fast #<==> Total #=< 12,
Fast #= 1,
labeling([ff, down], [A, B, C, Fast]).
element(A, [5, 3, 4], DA) makes DA the A-th entry of the table.
scalar_product/4 requires A + 2B + 3C = 11. Fast #<==> Total #=< 12
reifies the deadline: Fast is 1 exactly when the total is at most 12.
clpz_example(domain, domain(Infimum, Supremum, Size, Domain)) :-
X in 2..4 \/ 7,
fd_var(X),
fd_inf(X, Infimum),
fd_sup(X, Supremum),
fd_size(X, Size),
fd_dom(X, Domain).
X may be 2, 3, 4, or 7. The fd_* predicates report the smallest and
largest value, the number of values, and the domain itself.
eyeprolog examples/clpz-resource-allocation.pl
clpz_example(allocation, plan([2, 3, 1], durations([3, 2, 7]), 12)).
clpz_example(allocation, plan([3, 1, 2], durations([4, 4, 2]), 10)).
clpz_example(domain, domain(2, 7, 4, 2..4 \/ 7)).
Two assignments meet the deadline, with totals 12 and 10. The domain of X
runs from 2 to 7 and holds 4 values.
step(clpz_example(allocation, plan([2, 3, 1], durations([3, 2, 7]), 12)),
rule(1),
['A' = 2, 'B' = 3, 'C' = 1, 'DA' = 3, 'DB' = 2, 'DC' = 7, 'Total' = 12, 'Fast' = 1],
[[2, 3, 1] ins 1..3,
…
element(2, [5, 3, 4], 3),
…
1 #<==> 12 #=< 12,
…]).
The first plan holds by the allocation rule with every value filled in:
worker 2 on job A takes 3 units (the second table entry), and the total of 12
meets the deadline, so Fast is 1.
condition('C5', re_decision, ok, 25).
obligation(builtin, stateful, fd_inf(A, 2)).
obligation(builtin, stateful, fd_dom(A, 2..4 \/ 7)).
trusted(5).
verdict(checked_with_obligations).
All allocation steps are verified, recomputed or composed. The five fd_*
steps read the solver’s internal state for a variable that is never bound, so
the checker cannot recompute them. It keeps them as obligations: the
domain answer is as good as the constraint store that produced it.
Fast #= 0. There is no answer: both assignments
that satisfy A + 2B + 3C = 11 finish within 12 units.chain(#>=, [DA, DB]) and predict whether new plans appear.X in 2..4 \/ 7 to X in 1..10, X #\= 5 and predict the four
reflected values.Learn more in The Art of EyeProlog, Chapter 24.