14
15:- module(examplesFLOPS2024,
16 [
17 queens/2,
18 queens_distinct/2,
19 queens_sym/2,
20 sym_elim/2,
21 queens_sym_distinct/2,
22
23 queens_list/2,
24 queens_distinct_list/2,
25 queens_sym_list/2,
26 sym_elim_list/2,
27 queens_sym_distinct_list/2,
28
29 show/1,
30
31 fourier/4,
32
33 benchmark/0
34 ]).
132:- reexport(library(modeling)). 133
134 % N-QUEENS PLACEMENT MODELS USING SUBSCRIPTED VARIABLES
135
136
137%! queens(+N, ?Queens)
138%
139% solves the N Queens problems using arrays.
140
141queens(N, Queens):-
142 int_array(Queens, [N], 1..N),
143 for_all([I in 1..N-1, D in 1..N-I],
144 (Queens[I] #\= Queens[I+D], Queens[I] #\= Queens[I+D]+D, Queens[I] #\= Queens[I+D]-D)), satisfy(Queens).
155queens_distinct(N, Queens):-
156 int_array(Queens, [N], 1..N),
157
158 int_array(Indices, [N]),
159 for_all(I in 1..N, cell(Indices, I, I)),
160
161 op_rel(Queens, +, Indices, #=, QueensPlusI),
162 op_rel(Queens, -, Indices, #=, QueensMinusI),
163
164 all_distinct(QueensPlusI),
165 all_distinct(Queens),
166 all_distinct(QueensMinusI),
167
168 satisfy(Queens).
169
170
171%! queens_sym(+N, ?Queens)
172%
173% solves the N Queens problems with symmetry breaking using arrays.
174
175queens_sym(N, Queens):-
176 int_array(Queens, [N], 1..N),
177 for_all([I in 1..N-1, D in 1..N-I],
178 (Queens[I] #\= Queens[I+D],
179 Queens[I] #\= Queens[I+D]+D,
180 Queens[I] #\= Queens[I+D]-D)),
181 sym_elim(N, Queens),
182 satisfy(Queens).
183
184
185%! sym_elim(+N, ?Queens)
186%
187% introduces symmetrical array models and posts lex_leq/2 constraints to eliminate symmetries.
188
189sym_elim(N, Queens) :-
190
191 Queens[1] #< Queens[N], % vertical reflection Queens[1] #=< (N+1)//2, % horizontal reflection int_array(Dual, [N], 1..N), for_all([I, J] in 1..N, Queens[I] #= J #<==> Dual[J] #= I), lex_leq(Queens, Dual), % first diagonal reflection int_array(SecondDiagonal, [N], 1..N), for_all(I in 1..N, SecondDiagonal[I] #= N + 1 - Dual[N+1-I]), lex_leq(Queens, SecondDiagonal), int_array(R90, [N], 1..N), for_all(I in 1..N, R90[I] #= Dual[N+1-I]), lex_leq(Queens, R90), % rotation 90° int_array(R180, [N], 1..N), for_all(I in 1..N, R180[I] #= N + 1 - Queens[N+1-I]), lex_leq(Queens, R180), int_array(R270, [N], 1..N), for_all(I in 1..N, R270[I] #= N + 1 - Dual[I]), lex_leq(Queens, R270).
220queens_sym_distinct(N, Queens):-
221 int_array(Queens, [N], 1..N),
222 int_array(Indices, [N]),
223 for_all(I in 1..N, cell(Indices, I, I)),
224 op_rel(Queens, +, Indices, #=, QueensPlusI),
225 op_rel(Queens, -, Indices, #=, QueensMinusI),
226 all_distinct(QueensPlusI),
227 all_distinct(Queens),
228 all_distinct(QueensMinusI),
229
230 sym_elim(N, Queens),
231
232 satisfy(Queens).
233
234
235
242queens_list(N, Queens):-
243 length(Queens, N),
244 Queens ins 1..N,
245 safe(Queens),
246 labeling([ff], Queens).
247
248safe([]).
249safe([QI | Tail]) :-
250 noattack(Tail, QI, 1),
251 safe(Tail).
252
253noattack([], _, _).
254noattack([QJ | Tail], QI, D) :-
255 QI #\= QJ,
256 QI #\= QJ + D,
257 QI #\= QJ - D,
258 D1 #= D + 1,
259 noattack(Tail, QI, D1).
266queens_distinct_list(N, Queens):-
267 length(Queens, N),
268 Queens ins 1..N,
269
270 length(Indices, N),
271 for_all(I in 1..N, nth1(I, Indices, I)),
272
273 op_rel(Queens, +, Indices, #=, QueensPlusI),
274 op_rel(Queens, -, Indices, #=, QueensMinusI),
275
276 all_distinct(QueensPlusI),
277 all_distinct(Queens),
278 all_distinct(QueensMinusI),
279
280 labeling([ff], Queens).
287queens_sym_list(N, Queens) :-
288 length(Queens, N),
289 Queens ins 1..N,
290 safe(Queens),
291
292 sym_elim_list(N, Queens),
293
294 labeling([ff], Queens).
301sym_elim_list(N, Queens) :-
302 last(Queens, Last),
303 Queens = [First | _],
304 First #< Last,
305 First #=< (N+1) // 2,
306
307 dual(N, Queens, Dual),
308 lex_leq(Queens, Dual),
309
310 length(CounterDiagonal, N),
311 reverse(Dual, DualReversed), 312 counterdiag(CounterDiagonal, 1, N, DualReversed),
313 lex_leq(Queens, CounterDiagonal),
314
315 length(R90, N),
316 r90(R90, 1, N, DualReversed),
317 lex_leq(Queens, R90),
318
319 length(R180, N),
320 reverse(Queens, QueensReversed), 321 r180(R180, 1, N, QueensReversed),
322 lex_leq(Queens, R180),
323
324 length(R270, N),
325 r180(R270, 1, N, Dual), 326 lex_leq(Queens, R270).
327
328
329dual(N, Queens, Dual):-
330 length(Dual, N),
331 forall_IJ(Queens, 1, Dual).
332
333forall_IJ([], _, _).
334forall_IJ([QI |Qs], I, Dual):-
335 forall_J(Dual, 1, QI, I),
336 I1 #= I+1,
337 forall_IJ(Qs, I1, Dual).
338
339forall_J([], _, _, _).
340forall_J([RJ | R], J, QI, I):-
341 (QI#=J) #<==> (RJ#=I),
342 J1 #= J+1,
343 forall_J(R, J1, QI, I).
344
345counterdiag([], _, _, _).
346counterdiag([CI | CounterDiagonal], I, N, [DI | Dual]):-
347 CI #= N+1-DI,
348 I1 is I+1,
349 counterdiag(CounterDiagonal, I1, N, Dual).
350
351r90([], _, _, _).
352r90([RI | R90], I, N, [DI | Dual]):-
353 RI #= DI,
354 I1 is I+1,
355 r90(R90, I1, N, Dual).
356
357r180([], _, _, _).
358r180([RI | R90], I, N, [DI | Dual]):-
359 RI #= N+1-DI,
360 I1 is I+1,
361 r180(R90, I1, N, Dual).
368queens_sym_distinct_list(N, Queens) :-
369 length(Queens, N),
370 Queens ins 1..N,
371
372 length(Indices, N),
373 for_all(I in 1..N, nth1(I, Indices, I)),
374
375 op_rel(Queens, +, Indices, #=, QueensPlusI),
376 op_rel(Queens, -, Indices, #=, QueensMinusI),
377
378 all_distinct(QueensPlusI),
379 all_distinct(Queens),
380 all_distinct(QueensMinusI),
381
382 sym_elim_list(N, Queens),
383
384 labeling([ff], Queens).
385
386
387
394show(Queens):-
395 (array(Queens)
396 ->
397 show_array(Queens)
398 ;
399 show_list(Queens)).
400
401show_array(Queens):-
402 array(Queens, [N]),
403 for_all([I, J] in 1..N,
404 let([QJ = Queens[J],
405 Q = if(QJ = I, 'Q', '.'),
406 B = if(J = N, '\n', ' ')],
407 format("~w~w",[Q,B]))),
408 nl.
409
410show_list(Queens):-
411 length(Queens, N),
412 for_all([I, J] in 1..N,
413 exists(QJ,
414 (nth1(J, Queens, QJ),
415 let([Q = if(QJ = I, 'Q', '.'),
416 B = if(J = N, '\n', ' ')],
417 format("~w~w",[Q,B]))))),
418 nl.
419
420
421 450
451:- set_prolog_flag(optimise, true).
456benchmark :-
457 queens(100, _), !, 458 459 test(queens(100, _)),
460 test(queens_list(100, _)),
461 test(queens_distinct(100, _)),
462 test(queens_distinct_list(100, _)),
463 464 test((queens(8, _), fail)),
465 test((queens_list(8, _), fail)),
466 test((queens_distinct(8, _), fail)),
467 test((queens_distinct_list(8, _), fail)),
468 469 test((queens_sym(8, _), fail)),
470 test((queens_sym_list(8, _), fail)),
471 test((queens_sym_distinct(8, _), fail)),
472 test((queens_sym_distinct_list(8, _), fail)),
473 474 test(fourier(2, _, _, 1)).
475
476
477test(Goal):-
478 writeln(Goal),
479 (time(Goal) -> true ; true).
480
481
482
483
484 % FOURIER'S EXAMPLE OVER THE REAL NUMBERS
485
486
487%! fourier(?P, ?X, ?Y, ?F)
488%
489% Placing a weight P at coordinates X Y on an isocel triangle table with 3 legs at coordinates (0,0), (20, 0) and (0, 20)
490% and with a maximum force F exerted on each leg.
491
492fourier(P, X, Y, F):-
493 float_array(Force_Leg, [3], 0..F),
494 {Force_Leg
Examples of models presented at FLOPS 2024 to show the absence of computational overhead
Examples of use of SWI-Prolog pack modeling published in
Generation of constraints by comprehension on subscripted variables, in the spirit of MiniZinc modeling language:
queens(N, Queens):- int_array(Queens, [N], 1..N), for_all([I in 1..N-1, D in 1..N-I], (Queens[I] #\= Queens[I+D], Queens[I] #\= Queens[I+D]+D, Queens[I] #\= Queens[I+D]-D)), satisfy(Queens). show_array(Queens):- array(Queens, [N]), for_all([I, J] in 1..N, let([QJ = Queens[J], Q = if(QJ = I, 'Q', '.'), B = if(J = N, '\n', ' ')], format("~w~w",[Q,B]))), nl. ?- queens(8,Queens), show_array(Queens). Q . . . . . . . . . . . . . Q . . . . . Q . . . . . . . . . . Q . Q . . . . . . . . . Q . . . . . . . . . Q . . . . Q . . . . . Queens = array(1, 5, 8, 6, 3, 7, 2, 4) .For some reason the computation times in SWI-prolog 9.2.6 seem 30% higher than in version 9.2.2 but still with no significant difference between the use of arrays or lists in these examples.
Symbolic answer constraints not only ground solutions:
fourier(P, X, Y, F):- float_array(Force_Leg, [3], 0..F), {Force_Leg[1]+Force_Leg[2]+Force_Leg[3] = P, X*P = 20*Force_Leg[2], Y*P = 20*Force_Leg[3]}. ?- fourier(3, X, Y, 1). X = Y, Y = 6.666666666666667. ?- fourier(3.1, X, Y, 1). false. ?- fourier(2, X, Y, 1). {Y=20.0-10.0*_A-10.0*_B, X=10.0*_B, _=2.0-_A-_B, _A+_B>=1.0, _B=<1.0, _A=<1.0}.*/