:- module(_,_). %% * CLP: a first comparison with classic Logic Programming :- use_package(clpr). % You can also try: :- use_package(clpq). % Classic LP hp(X,Y,Z) :- Z = f(X,Y). % CLP: Prolog+constraints (same in this case) hc(X,Y,Z) :- Z = f(X,Y).
% Classic Prolog using is/2 ap(X,Y,Z) :- Z is X + Y. % CLP: Prolog+constraints (note use of .=.) ac(X,Y,Z) :- Z .=. X+Y.
?- hp(3, 4, Z).
?- hp(X, Y, f(3,4)).
?- hp(X, Y, Z).
?- hc(3, 4, Z).
?- hc(X, Y, f(3,4)).
?- hc(X, Y, Z).
Not reversible with is/2:
?- ap(3, 4, Z).
?- ap(X, 4, 7).Fully reversible with constraints:
?- ac(3, 4, Z).
?- ac(X, 4, 7).
?- ac(X, Y, 7).In the last case we get a constraint back.
:- use_package(clpr). p(X, Y, Z) :- Z .=. X + Y.
?- p(3, 4, Z). Z .=. 7 ?- p(X, 4, 7). X .=. 3 4 ?- p(X, Y, 7). X .=. 7 - Y ← with clpr arithmetic is reversible!
:- module(_,_). :- use_package(clpr). % You can also try: :- use_package(clpq). % ------------------------------------------------------------------- %% * CLP and search space reduction %% Generate and test vs. constrain and generate p(11). p(3). p(7). p(16). p(15). p(14).
solution_gen_test_prolog_1(X, Y, Z) :-
p(X),
p(Y),
p(Z),
prolog_test(X, Y, Z).
prolog_test(X, Y, Z) :- Y is X + 1, Z is Y + 1.?- time(solution_gen_test_prolog_1(X, Y, Z)).-> Seems to work well (458 steps; all solutions: 475 steps).
solution_gen_test_prolog(X, Y, Z) :-
q(X),
q(Y),
q(Z),
prolog_test(X, Y, Z).?- time(solution_gen_test_prolog(X, Y, Z)).-> Now takes much longer!
solution_gen_test_clp(X, Y, Z) :-
q(X),
q(Y),
q(Z),
clp_test(X, Y, Z).
clp_test(X, Y, Z) :- Y .=. X + 1, Z .=. Y + 1.?- time(solution_gen_test_clp(X, Y, Z)).-> Actually, takes longer than generate and test in standard Prolog (constraint solving does have overhead).
solution_cons_gen_clp(X, Y, Z) :-
clp_test(X, Y, Z),
q(X),
q(Y),
q(Z).?- time(solution_cons_gen_clp(X, Y, Z)).-> Much better!
solution_cons_gen_prolog(X, Y, Z) :-
prolog_test(X, Y, Z),
q(X),
q(Y),
q(Z).?- time(solution_cons_gen_prolog(X, Y, Z)).-> Does not work!
solution_gen_and_early_test_prolog(X, Y, Z) :-
q(X),
Y is X + 1,
q(Y),
Z is Y + 1,
q(Z).?- time(solution_gen_and_early_test_prolog(X, Y, Z)).-> Works quite well! But can be harder / more work than constrain and generate in realistic cases.
%% q/1: making the search space a little larger: q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(11). q(3). q(7). q(16). q(15). q(14). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0). q(0).
% Find three consecutive numbers in the p/1 relation. :- use_package(clpr). solution(X, Y, Z) :- p(X), p(Y), p(Z), test(X, Y, Z). p(11). p(3). p(7). p(16). p(15). p(14). test(X, Y, Z) :- Y .=. X + 1, Z .=. Y + 1.
?- solution(X, Y, Z). X .=. 14, Y .=. 15, Z .=. 16 ? ; no
% Find three consecutive numbers in the p/1 relation. :- use_package(clpr). solution(X, Y, Z) :- test(X, Y, Z), p(X), p(Y), p(Z). p(11). p(3). p(7). p(16). p(15). p(14).
?- solution(X, Y, Z). {INSTANTIATION ERROR}
?- solution(X, Y, Z). X .=. 14, Y .=. 15, Z .=. 16 ? ; noIn 11 steps (and all solutions in 11 steps)!
(x₁,x₂, …, xn) . (y₁, y₂, …, yn) = x₁ . y₁ + x₂ . y₂ + … + xn . yn
We represent vectors as lists of numbers:
:- module(_,_).
:- use_package(clpr).
% You can also try: :- use_package(clpq).
% -------------------------------------------------------------------
prod([], [], Result) :-
Result .=. 0.
prod([X|Xs], [Y|Ys], Result) :-
Result .=. X * Y + Rest,
prod(Xs, Ys, Rest).Unification and constraint solving combined!?- prod([2, 3], [4, 5], K).
?- prod([2, 3], [4, Y2], 23).
?- prod([2, 7, 3], [Vx, Vy, Vz], 0).-> Any computed answer is, in general, a constraint over the variables in the query. Try also with clpq!
?- prod([Y,2,3],[4,X,6],32).
?- prod([3,1], [X,Y], 5), prod([1,8], [X,Y], 3).Equivalent to: 3x + y = 5 'and' x + 8y = 3. -> Systems of linear equations!
system([], _Vars, []).
system([Co|Coefs], Vars, [Ind|Indeps]) :-
prod(Co, Vars, Ind),
system(Coefs, Vars, Indeps).E.g., solving the previous system (3x + y = 5, x + 8y = 3):?- system([[3, 1],[1, 8]], [X, Y], [5, 3]).Note that we are using both Herbrand terms and constraints.
?- X + Y .=<. 4, Y .>=. 4, X .>=. 0.
?- sin(X) .=. cos(X).
?- X*X + 2*X + 1 .=. 0.Reason: no general solving technique is known. CLPR solves only linear (dis)equations.
?- X .=. cos(sin(Y)), Y .=. 2+Y*3.
?- prod([3, 1], [X, Y], 5), prod([1, 8], [X, Y], 3). X .=. 1.6087, Y .=. 0.173913
system([], _Vars, []). system([Co|Coefs], Vars, [Ind|Indeps]) :- prod(Co, Vars, Ind), system(Coefs, Vars, Indeps).
?- system([[3, 1],[1, 8]], [X, Y], [5, 3]). X .=. 1.6087, Y .=. 0.173913exercise! ▶
?- sin(X) .=. cos(X). sin(X) .=. cos(X)
?- X*X + 2*X + 1 .=. 0. -2*X - 1 .=. X * X
?- X .=. cos(sin(Y)), Y .=. 2+Y*3. Y .=. -1, X .=. 0.666367
?- X + Y .=<. 4, Y .>=. 4, X .>=. 0. Y .=. 4, X .=. 0
:- module(_,_).
:- use_package(clpq).
% -------------------------------------------------------------------
% Fibonacci revisited
fib_pl(0,0).
fib_pl(1,1).
fib_pl(N,R) :-
N > 1,
N1 is N-1,
N2 is N-2,
fib_pl(N1,F1),
fib_pl(N2,F2),
R is F1+F2. fib_clp(N,N) :- N .=. 0.
fib_clp(N,N) :- N .=. 1.
fib_clp(N,R) :-
N .>. 1,
F1 .>=. 0,
F2 .>=. 0,
N1 .=. N - 1,
N2 .=. N - 2,
fib_clp(N1,F1),
fib_clp(N2,F2),
R .=. F1 + F2. ?- fib_pl(11,Y).
?- fib_clp(11,Y).
?- fib_pl(X,89).-> Error
?- fib_clp(X,89).-> Works...
?- fib_pl(X,Y).-> Error (at third solution)
?- fib_clp(X,Y).-> Works!
:- use_package(clpr). fib(N,N) :- N .=. 0. fib(N,N) :- N .=. 1. fib(N,R) :- N .>. 1, F1 .>=. 0, F2 .>=. 0, N1 .=. N - 1, N2 .=. N - 2, fib(N1,F1), fib(N2,F2), R .=. F1 + F2.
?- fib(N, F). F .=. 0, N .=. 0 ; F .=. 1, N .=. 1 ; F .=. 1, N .=. 2 ; F .=. 2, N .=. 3 ;exercise! ▶
:- module(_,_).
:- use_package(clpr).
% Or, we can use clpq for exact calculations
% :- use_package(clpq).
mg(P, T, I, B, MP):-
T .=. 1,
B + MP .=. P * (1 + I).
mg(P, T, I, B, MP):-
T .>. 1,
P1 .=. P * (1 + I) - MP,
T1 .=. T - 1,
mg(P1, T1, I, B, MP). ?- mg(1000, 30, 0.03, 0, MP).
?- mg(P, 30, 0.03, 0, 20).
?- mg(1000, 30, 0.03, B, 0).
?- mg(1000, 30, 0.03, B, -50).
?- mg(1000, 30, 0.03, 0, MP).
?- mg(P, 30, 0.03, 0, 20).
?- mg(1000, 30, 0.03, B, 0).
?- mg(1000, 30, 0.03, B, -50).
:- module(_,_).
:- use_package(clpr).
%----------------------------------------
% RLC Analog Circuits
c_add(c(Re1,Im1), c(Re2,Im2), c(Re12,Im12)) :-
Re12 .=. Re1+Re2,
Im12 .=. Im1+Im2. c_mult(c(Re1, Im1), c(Re2, Im2), c(Re3, Im3)) :-
Re3 .=. Re1 * Re2 - Im1 * Im2,
Im3 .=. Re1 * Im2 + Re2 * Im1. circuit(resistor(R), V, I, _W) :-
c_mult(I, c(R, 0), V).
circuit(inductor(L), V, I, W) :-
Im .=. W * L,
c_mult(I, c(0, Im), V).
circuit(capacitor(C), V, I, W) :-
Im .=. -1 / (W * C),
c_mult(I, c(0, Im), V). % When connecting in parallel, the voltage is the same, the
% currents are added.
circuit(parallel(N1, N2), V, I, W) :-
c_add(I1, I2, I),
circuit(N1, V, I1, W),
circuit(N2, V, I2, W).
% When connecting in series the current is the same, the
% voltages are added.
circuit(series(N1, N2), V, I, W) :-
c_add(V1, V2, V),
circuit(N1, V1, I, W),
circuit(N2, V2, I, W). ?- circuit(parallel(inductor(0.073), series(capacitor(C), resistor(R))), c(4.5, 0), c(0.65, 0), 2400).
circuit(series(N1, N2), V, I, W) :- c_add(V1, V2, V), circuit(N1, V1, I, W), circuit(N2, V2, I, W).
circuit(parallel(N1, N2), V, I, W) :- c_add(I1, I2, I), circuit(N1, V, I1, W), circuit(N2, V, I2, W).
circuit(resistor(R), V, I, _W) :- c_mult(I, c(R, 0), V).
circuit(inductor(L), V, I, W) :- Im .=. W * L, c_mult(I, c(0, Im), V).
circuit(capacitor(C), V, I, W) :- Im .=. -1 / (W * C), c_mult(I, c(0, Im), V).
[h]
?- circuit(parallel(inductor(0.073),
series(capacitor(C), resistor(R))),
c(4.5, 0), c(0.65, 0), 2400).
R .=. 6.91229, C .=. 0.00152546
?- circuit(C, c(4.5, 0), c(0.65, 0), 2400).
is represented as [2, 4, 1, 3]
queens(N, Qs) :- queens_list(N, Ns), % E.g., Ns=[4,3,2,1] queens(Ns, [], Qs).
queens([], Qs, Qs). % All queens placed! queens(Unplaced, Placed, Qs) :- select(Unplaced, Q, NewUnplaced), % E.g. Q=4, NewU=[3,2,1] no_attack(Placed, Q, 1), % Fail if attack queens(NewUnplaced, [Q|Placed], Qs).% OK->Choose next q
no_attack([], _Queen, _Nb). no_attack([Y|Ys], Queen, Nb) :- Queen =\= Y + Nb, Queen =\= Y - Nb, Nb1 is Nb + 1, no_attack(Ys, Queen, Nb1).
select([X|Ys], X, Ys). select([Y|Ys], X, [Y|Zs]) :- select(Ys, X, Zs).
queens_list(0, []). queens_list(N, [N|Ns]) :- N > 0, N1 is N - 1, queens_list(N1, Ns).
----------------- | | Q | | | ----------------- | | | | Q | ----------------- | Q | | | | ----------------- | | | Q | | -----------------is represented as [2, 4, 1, 3].
:- module(_,_).
:-use_package(clpr).
%----------------------------------------
% N Queens
queens_pl(N, Qs) :-
queens_list_pl(N, Ns), % E.g., Ns=[4,3,2,1]
queens_pl_(Ns, [], Qs).
queens_pl_([], Qs, Qs). % All queens placed!
queens_pl_(Unplaced, Placed, Qs) :-
selectq(Unplaced, Q, NewUnplaced), % E.g., Q=4, NewU=[3,2,1]
no_attack_pl(Placed, Q, 1), % Fail if Q attacked
queens_pl_(NewUnplaced, [Q|Placed], Qs). % OK -> Choose next Q
no_attack_pl([], _Queen, _Nb).
no_attack_pl([Y|Ys], Queen, Nb) :-
Queen =\= Y + Nb,
Queen =\= Y - Nb,
Nb1 is Nb + 1,
no_attack_pl(Ys, Queen, Nb1).
selectq([X|Ys], X, Ys).
selectq([Y|Ys], X, [Y|Zs]) :-
selectq(Ys, X, Zs).
queens_list_pl(0, []).
queens_list_pl(N, [N|Ns]) :-
N > 0, N1 is N - 1, queens_list_pl(N1, Ns).Try, e.g., the following queries to better understand the algorithm (also, run on the debugger):?- queens_list_pl(4,L).
?- selectq([4,3,2,1], Q, NewUnplaced).Try different solutions
Solving for N queens (can ask for more solutions):
?- queens_pl(4,L).
?- queens_pl(20,L).
?- queens_pl(27,L).
?- queens_pl(30,L).
queens(N, Qs) :-
constrain_values(N, N, Qs),
place_queens(N, Qs).
constrain_values(0, _N, []).
constrain_values(I, N, [X|Xs]) :-
I .>. 0,
X .>. 0, X .=<. N, % All queens between 0 and N
I1 .=. I - 1,
constrain_values(I1, N, Xs), no_attack(Xs, X, 1).
no_attack([], _Queen, _Nb).
no_attack([Y|Ys], Queen, Nb) :-
Queen .<>. Y + Nb,
Queen .<>. Y - Nb,
Nb1 .=. Nb + 1,
no_attack(Ys, Queen, Nb1).
place_queens(0, _).
place_queens(N, Q) :-
N .>. 0,
memberq(N, Q),
N1 .=. N - 1,
place_queens(N1, Q).
memberq(X, [X|_]).
memberq(X, [_|Xs]) :- memberq(X, Xs).Solving for N queens (can ask for more solutions):?- queens(4,Qs).
?- queens(20,Qs).-> This CLP(R) solution does not speed up w.r.t. the standard Prolog one. -> This problem is more suited to finite domain constraints.
Try, e.g., the following queries to better understand the code:
?- queens(4, Qs).
?- memberq(4, [A, B, C, D]).
?- place_queens(0, L).
?- constrain_values(4, 4, Qs).
?- constrain_values(4, 4, Qs), Qs = [3,1|OQs].Bad state rejected using constraint (in)consistency:
?- constrain_values(4, 4, Qs), Qs = [3,2|OQs].
?- queens(N,L). L = [], N .=. 0 ; L = [1], N .=. 1 ; L = [2, 4, 1, 3], N .=. 4 ; L = [3, 1, 4, 2], N .=. 4 ; L = [5, 2, 4, 1, 3], N .=. 5 ; L = [5, 3, 1, 4, 2], N .=. 5 ; L = [3, 5, 2, 4, 1], N .=. 5 ; L = [2, 5, 3, 1, 4], N .=. 5 ...
?- constrain_values(4, 4, Qs). Qs = [_A,_B,_C,_D], nonzero(_E), _A.=<.4.0, _E.=.3.0+_A-_D, nonzero(_F), _A.>.0, _F.=. -3.0+_A-_D, nonzero(_G), _B.=<.4.0, _G.=.2.0+_A-_C, nonzero(_H), _B.>.0, _H.=. -2.0+_A-_C, nonzero(_I), _C.=<.4.0, _I.=.1+_A-_B, nonzero(_J), _C.>.0, _J.=. -1+_A-_B, nonzero(_K), _D.=<.4.0, _K.=.2.0+_B-_D, nonzero(_L), _D.>.0, _L.=. -2.0+_B-_D, nonzero(_M), _M.=.1+_B-_C, nonzero(_N), _N.=. -1+_B-_C, nonzero(_O), _O.=.1+_C-_D, nonzero(_P), _P.=. -1+_C-_D ?
?- constrain_values(4, 4, Qs), Qs = [3,1|_]. Qs = [_A,_B,_C,_D], nonzero(_E), _A.=.3.0, _E.=.6.0-_D, nonzero(_F), _B.=.1.0, _F.=. -_D, nonzero(_G), _C.=<.4.0, _G.=.5.0-_C, nonzero(_H), _C.>.0, _H.=.1.0-_C, nonzero(_I), _D.=<.4.0, _I.=.3.0-_D, nonzero(_J), _D.>.0, _J.=. -1.0-_D, nonzero(_K), _K.=.2.0-_C, nonzero(_L), _L.=. -_C, nonzero(_M), _M.=.1+_C-_D, nonzero(_N), _N.=. -1+_C-_D ?
?- constrain_values(4, 4, Qs), Qs = [3,2|_]. no

?- use_package(clpfd).
?- X #= A + B, A in 1..3, B in 3..7.-> The respective minimums and maximums are added -> There is no unique solution
?- X #= A - B, A in 1..3, B in 3..7.-> The min value of X is the min value of A minus the max value of B -> (Similar for the maximum values)
?- X #= A - B, A in 1..3, B in 3..7, X #>= 0.
?- domain([X, Y, Z],1,1000), X*X+Y*Y #= Z*Z, X #>= Y.
?- domain([X, Y, Z],1,1000), X*X+Y*Y #= Z*Z, X #>= Y, labeling([],[X,Y,Z]).
?- domain([X, Y, Z],1,100), X*X+Y*Y #= Z*Z, X #>= Y, minimize(labeling([],[X,Y,Z]), Y).
?- domain([X, Y, Z],1,1000), X*X+Y*Y #= Z*Z, X #>= Y, labeling([],[X,Y,Z]). X = 4, Y = 3, Z = 5, X = 8, Y = 6, Z = 10, X = 12, Y = 5, Z = 13, ...
S E N D + M O R E _________ M O N E Y
:- module(_,_).
:- use_package(clpfd).
% -------------------------------------------------------------------
% The classic SEND MORE MONEY example
smm_no_labeling(Vars) :-
Vars = [S,E,N,D,M,O,R,Y],
domain(Vars, 0, 9), % All digits 0..9
0 #< S, 0 #< M, % No leftmost zeros
all_different(Vars), % All digits different
% And the arithmetic constraints:
S*1000 + E*100 + N*10 + D +
M*1000 + O*100 + R*10 + E #=
M*10000 + O*1000 + N*100 + E*10 + Y.Try:?- smm_no_labeling([S,E,N,D,M,O,R,Y]).-> We need labeling!
smm(Vars) :-
Vars = [S,E,N,D,M,O,R,Y],
domain(Vars, 0, 9),
0 #< S, 0 #< M,
all_different(Vars),
S*1000 + E*100 + N*10 + D +
M*1000 + O*100 + R*10 + E #=
M*10000 + O*1000 + N*100 + E*10 + Y,
labeling([], Vars),
pp_smm(Vars).Try:?- smm([S,E,N,D,M,O,R,Y]).
% A simple pretty printer:
pp_smm([S,E,N,D,M,O,R,Y]) :-
format("~n ~w ~w ~w ~w~n", [S,E,N,D]),
format( " + ~w ~w ~w ~w~n", [M,O,R,E]),
format( " ---------~n", []),
format( " ~w ~w ~w ~w ~w~n",[M,O,N,E,Y]). 
The job dependencies and task lengths are given by this graph:
0*G
^ ^
/ |
/ |
4*E 1*F
^^ ^^
| \ | \
| \ | \
1*B 2*C 3*D
^ ^ ^
\ | /
\ | /
0*APlus, the whole job should be finished in 10 time units or less.:- module(_,_).
:- use_package(clpfd).
% -------------------------------------------------------------------
% A project management problem (1)
% Constraints:
pn1(A,B,C,D,E,F,G) :-
domain([A,B,C,D,E,F,G], 0, 10),
A #>= 0, G #=< 10,
B #>= A, C #>= A, D #>= A,
E #>= B + 1, E #>= C + 2,
F #>= C + 2, F #>= D + 3,
G #>= E + 4, G #>= F + 1. ?- use_package(clpfd).
?- pn1(A,B,C,D,E,F,G).-> Tasks have slack, let's minimize the final time (G):
?- minimize(pn1(A,B,C,D,E,F,G),G).-> We identify the critical path, some slack elsewhere.
And we can minimize more variables:
?- minimize(pn1(A,B,C,D,E,F,G),G), minimize(true, F), minimize(true,B).
?- pn1(A,B,C,D,E,F,G). A in 0..4, B in 0..5, C in 0..4, D in 0..6, E in 2..6, F in 3..9, G in 6..10.
?- minimize(pn1(A,B,C,D,E,F,G), G). A = 0, B in 0..1, C = 0, D in 0..2, E = 2, F in 3..5, G = 6

The job dependencies and task lengths are now given by this graph, where we assume we can accelerate or slow down task F (we make the length of F a variable X )
0*G
^ ^
/ |
/ |
4*E X*F
^^ ^^
| \ | \
| \ | \
1*B 2*C 3*D
^ ^ ^
\ | /
\ | /
0*AStill, the whole job should be finished in 10 time units or less.:- module(_,_).
:- use_package(clpfd).
% -------------------------------------------------------------------
% A project management problem (2)
pn2(A, B, C, D, E, F, G, X) :-
domain([A,B,C,D,E,F,G,X], 0, 10),
A #>= 0, G #=< 10,
B #>= A, C #>= A, D #>= A,
E #>= B + 1, E #>= C + 2,
F #>= C + 2, F #>= D + 3,
G #>= E + 4, G #>= F + X.But going faster on F has a cost, so we do not want to accelerate it more than needed! –> minimize G and maximize X:?- use_package(clpfd).
?- pn2(A, B, C, D, E, F, G, X).
?- minimize(pn2(A,B,C,D,E,F,G,X), G), maximize(true,X).
The job dependencies and task lengths are now given by this graph, where we now have two independent tasks B and D whose lengths X and Y are not fixed:
0*G
^ ^
/ |
/ |
4*E 1*F
^^ ^^
| \ | \
| \ | \
X*B 2*C Y*D
^ ^ ^
\ | /
\ | /
0*AStill, the whole job should be finished in 10 time units or less.But we can finish any of B or D in 2 time units at best -> X #>=2, Y #>=2
Plus, some shared resource disallows finishing both tasks in 2 time units: they will instead take 6 time units -> X #>=2, Y #>=2, X + Y #= 6
:- module(_,_).
:- use_package(clpfd).
% -------------------------------------------------------------------
% A project management problem (3)
pn3(A,B,C,D,E,F,G,X,Y) :-
domain([A,B,C,D,E,F,G,X,Y], 0, 10),
A #>= 0, G #=< 10,
X #>= 2, Y #>= 2, X + Y #= 6,
B #>= A, C #>= A, D #>= A,
E #>= B + X, E #>= C + 2,
F #>= C + 2, F #>= D + Y,
G #>= E + 4, G #>= F + 1. ?- use_package(clpfd).
?- minimize(pn3(A,B,C,D,E,F,G,X,Y), G).-> We must devote more resources to task B. -> All tasks but F and D are critical now.
We can use labeling for D and F:
?- minimize(pn3(A,B,C,D,E,F,G,X,Y),G), labeling([],[D,F]).Also:
?- pn3(A,B,C,D,E,F,G,X,Y), minimize(labeling([],[A,B,C,D,E,F,G,X,Y]),G).
?- minimize(pn3(A,B,C,D,E,F,G,X,Y),G), labeling([],[D,F]).
----------------- | | Q | | | ----------------- | | | | Q | ----------------- | Q | | | | ----------------- | | | Q | | -----------------is represented as [2, 4, 1, 3].
:- module(_,_).
:- use_package(clpfd).
% -------------------------------------------------------------------
% N Queens in CLP(fd)
queens_fd(N, Qs, Type) :- % Type is the labeling strategy
constrain_values(N, N, Qs),
all_different(Qs), % built-in constraint
labeling(Type,Qs).
constrain_values(0, _N, []).
constrain_values(N, Range, [X|Xs]) :-
N > 0, N1 is N - 1, X in 1 .. Range,
constrain_values(N1, Range, Xs), no_attack(Xs, X, 1).
no_attack([], _Queen, _Nb).
no_attack([Y|Ys], Queen, Nb) :-
Queen #\= Y + Nb, Queen #\= Y - Nb, Nb1 is Nb + 1,
no_attack(Ys, Queen, Nb1).Queries:?- time(queens_fd(20, Q, [ff])).
?- time(queens_pl(20,Q)).
?- time(queens_fd(100, Q, [ff])).
?- time(queens_pl(100,Q)).(Takes a long time...) -> CLP(fd) very good at finding a solution!
fd_all(N,L) :- findall(X, queens_fd(N,X,[ff]),S), length(S,L). pl_all(N,L) :- findall(X, queens_pl(N,X),S), length(S,L).
?- time(pl_all(11, L)).
?- time(fd_all(11, L)).
?- time(pl_all(12, L)).
?- time(fd_all(12, L)).
?- time(pl_all(13, L)).
?- time(fd_all(13, L)).-> CLP(fd) (at least this program) not so good for all solutions!
queens_pl(N, Qs) :-
queens_pl_list(N, Ns),
queens_pl_(Ns, [], Qs).
queens_pl_([], Qs, Qs).
queens_pl_(Unplaced, Placed, Qs) :-
selectq(Unplaced, Q, NewUnplaced),
pl_no_attack(Placed, Q, 1),
queens_pl_(NewUnplaced, [Q|Placed], Qs).
pl_no_attack([], _Queen, _Nb).
pl_no_attack([Y|Ys], Queen, Nb) :-
Queen =\= Y + Nb, Queen =\= Y - Nb, Nb1 is Nb + 1,
pl_no_attack(Ys, Queen, Nb1).
selectq([X|Ys], X, Ys).
selectq([Y|Ys], X, [Y|Zs]) :- selectq(Ys, X, Zs).
queens_pl_list(0, []).
queens_pl_list(N, [N|Ns]) :- N > 0, N1 is N - 1, queens_pl_list(N1, Ns). iso(Tree, Tree). iso(t(R, I1, D1), t(R, I2, D2)) :- iso(I1, D2), iso(D1, I2). ?- iso(t(a, b, t(X, Y, Z)), t(a, t(u, v, W), L)). L=b, X=u, Y=v, Z=W ? ; L=b, X=u, Y=W, Z=v ? ; L=b, W=t(_C,_B,_A), X=u, Y=t(_C,_A,_B), Z=v ? ; L=b, W=t(_E,t(_D,_C,_B),_A), X=u, Y=t(_E,_A,t(_D,_B,_C)), Z=v ?
?- "123".Z = Z."231", Z::0. ?- "123".Z = Z."231", Z::3. no no ?- "123".Z = Z."231", Z::1. ?- "123".Z = Z."231", Z::4. Z = "1" Z = "1231" ?- "123".Z = Z."231", Z::2. no
seq(<Y, X>). abs(Y, Y) :- Y >= 0. seq(<Y1 - X, Y, X>.U) :- abs(Y,-Y) :- Y < 0. seq(<Y, X>.U) abs(Y, Y1).
?- seq(U.V.W), U::2, V::7, W::2, U#W. fail
freeze( X, Goal) :- attach_attribute( V, frozen(V,Goal)), X = V. verify_attribute( frozen(Var,Goal), Value) :- detach_attribute( Var), Var = Value, call(Goal). combine_attributes( frozen(V1,G1), frozen(V2,G2)) :- detach_attribute( V1), detach_attribute( V2), V1 = V2, attach_attribute( V1, frozen(V1,(G1,G2))).
max(X,Y,X) :- X .>. Y. ?- max(X, Y, Z). max(X,Y,Y) :- X .=<. Y. Z .=. X, Y .<. X ;with
max(X,Y,X) :- X .>. Y, !. ?- max(X, Y, Z). max(X,Y,Y) :- X .=<. Y. Z .=. X, Y .<. X