/* Envelopes and index cards in Picat. From "How to have this prolog code run in sensible time?" https://stackoverflow.com/questions/58314099/how-to-have-this-prolog-code-run-in-sensible-time """ Imagine 13 envelopes, each numbered from 1 to 13. Take 13 index cards, numbered from 528 to 540. Find a possible arrangement of cards in envelopes such that the number on each card can be divided by the containing envelope with no remainder. """ There are 4 solutions: [529,538,537,528,535,534,532,536,531,530,539,540,533] [529,538,537,532,535,534,539,536,531,530,528,540,533] [529,538,537,536,535,534,532,528,531,530,539,540,533] [529,538,537,540,535,534,532,536,531,530,539,528,533] Here are the possible domains for each envelope number (I) using all_distinct/1: 1 = [529] 2 = [538] 3 = [537] 4 = [528,532,536,540] 5 = [535] 6 = [534] 7 = [532,539] 8 = [528,536] 9 = [531] 10 = [530] 11 = [528,539] 12 = [528,540] 13 = [533] When using all_different/1 the domains are larger: 1 = [528,529,530,531,532,534,535,536,537,538,539,540] 2 = [528,530,532,534,536,538,540] 3 = [528,531,534,537,540] 4 = [528,532,536,540] 5 = [530,535,540] 6 = [528,534,540] 7 = [532,539] 8 = [528,536] 9 = [531,540] 10 = [530,540] 11 = [528,539] 12 = [528,540] 13 = [533] This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import util. import cp. main => go. % % 0s % go ?=> N = 13, IndexCards = new_list(N), IndexCards :: 528..540, all_distinct(IndexCards), % all_different(IndexCards), println("Domains:"), foreach(I in 1..N) IndexCards[I] mod I #= 0 end, foreach(I in 1..N) printf("%2d = %w\n", I, fd_dom(IndexCards[I])) end, nl, solve($[ff,split],IndexCards), println(IndexCards), nl, fail, nl. go => true. % % Another approach. % go2 => N = 13, IndexCards = 528..540, X = new_list(N), X :: 528..540, Domains = new_list(N), bind_vars(Domains,[]), foreach(I in 1..N) foreach(J in 1..N) if IndexCards[I] mod J == 0 then Domains[J] := Domains[J] ++ [IndexCards[I]] end end end, println(Domains), foreach(I in 1..N) X[I] :: Domains[I] end, nl, all_distinct(X), solve(X), println(X), nl, fail, nl. go2 => true. % % Brute force using permutation/1: very slow % go3 ?=> IndexCards = 528..540, println(size=(540-528)), permutation(IndexCards,Perm), foreach(I in 1..13) Perm[I] mod I == 0 end, println(IndexCards), fail, nl. go3 => true.