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],
145 Queens[I] #\= Queens[I+D]+D,
146 Queens[I] #\= Queens[I+D]-D)),
147 satisfy(Queens).
148
149
150
151%! queens_distinct(+N, ?Queens)
152%
153% solves the N Queens problems using arrays and the global constraint all_distinct/1 of library(clpfd)
154
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
192 Queens[1] #=< (N+1)//2, % horizontal reflection
193
194 int_array(Dual, [N], 1..N),
195 for_all([I, J] in 1..N, Queens[I] #= J #<==> Dual[J] #= I),
196 lex_leq(Queens, Dual), % first diagonal reflection
197
198 int_array(SecondDiagonal, [N], 1..N),
199 for_all(I in 1..N, SecondDiagonal[I] #= N + 1 - Dual[N+1-I]),
200 lex_leq(Queens, SecondDiagonal),
201
202 int_array(R90, [N], 1..N),
203 for_all(I in 1..N, R90[I] #= Dual[N+1-I]),
204 lex_leq(Queens, R90), % rotation 90°
205
206 int_array(R180, [N], 1..N),
207 for_all(I in 1..N, R180[I] #= N + 1 - Queens[N+1-I]),
208 lex_leq(Queens, R180),
209
210 int_array(R270, [N], 1..N),
211 for_all(I in 1..N, R270[I] #= N + 1 - Dual[I]),
212 lex_leq(Queens, R270).
213
214
215
216%! queens_sym_distinct(+N, ?Queens)
217%
218% solves the N Queens problems with symmetry breaking using arrays and global constraint all_distinct/1.
219
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 % N-QUEENS PLACEMENT PROGRAMS USING LISTS
236
237
238%! queens_list(+N, ?Queens)
239%
240% standard program using lists for the N Queens problem.
241
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).
260
261
262%! queens_distinct_list(+N, ?Queens)
263%
264% program using lists and the global constraint all_distinct/1 of library(clpfd)
265
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).
281
282
283%! queens_sym_list(+N, ?Queens)
284%
285% list program to break symmetries in the N Queens problem.
286
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).
295
296
297%! sym_elim_list(+N, ?Queens)
298%
299% introduces symmetrical list models and posts lex_leq/2 constraints to eliminate symmetries.
300
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), % in order N+1-I
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), % in order N+1-I
321 r180(R180, 1, N, QueensReversed),
322 lex_leq(Queens, R180),
323
324 length(R270, N),
325 r180(R270, 1, N, Dual), % not a typo ! since applied here to the dual instead of the reversed primal
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).
362
363
364%! queens_sym_distinct_list(+N, ?Queens)
365%
366% list program with symmetry breaking and global constraint all_distinct/1
367
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
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:
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:
*/