/* Tacos in Picat. From https://github.com/guregu/php/blob/master/www/public_html/tacos.html """ So I made this girl quit her job today. I went to a local Mexican restaurant that has $1 tacos for 'Taco Tuesday.' It's a Chipotle style line where you choose hard or soft taco, chicken or beef, and you can add up to three "toppings" from the following: lettuce, salsa, corn, rice and beans, sour cream, or spicy sour cream. I think there were a few others but they are of no use to this story. So I walk up to the start of the line and she asks me what I want. I say: "Hi. I'll have six tacos. Three hard and three soft. Three with chicken, and three with beef, but not so that all the chicken or beef are on the same style taco. I'll have any three toppings between lettuce, salsa, rice and beans, sour cream and spicy sour cream such that salsa and any style of sour cream is on all of them and that no two tacos have the exact same contents." She looks at my face for a few seconds with a blank stare before saying, "Fuck this" and just walks to the back where the customer can't see, and then like 15 seconds later walks down the hallway and out the door and gets into her car. Then some guy comes out from the back, who I assume is the manager, with a concerned look on his face, apologizes and takes my order. Other employees were really confused. Tacos were okay. """ Here are all 24 solutions for the original Prolog program (go0/0): hard chicken [salsa,sour_cream,lettuce] hard chicken [salsa,sour_cream,corn] hard chicken [salsa,sour_cream,rice_beans] hard chicken [salsa,spicy_sour_cream,lettuce] hard chicken [salsa,spicy_sour_cream,corn] hard chicken [salsa,spicy_sour_cream,rice_beans] hard beef [salsa,sour_cream,lettuce] hard beef [salsa,sour_cream,corn] hard beef [salsa,sour_cream,rice_beans] hard beef [salsa,spicy_sour_cream,lettuce] hard beef [salsa,spicy_sour_cream,corn] hard beef [salsa,spicy_sour_cream,rice_beans] soft chicken [salsa,sour_cream,lettuce] soft chicken [salsa,sour_cream,corn] soft chicken [salsa,sour_cream,rice_beans] soft chicken [salsa,spicy_sour_cream,lettuce] soft chicken [salsa,spicy_sour_cream,corn] soft chicken [salsa,spicy_sour_cream,rice_beans] soft beef [salsa,sour_cream,lettuce] soft beef [salsa,sour_cream,corn] soft beef [salsa,sour_cream,rice_beans] soft beef [salsa,spicy_sour_cream,lettuce] soft beef [salsa,spicy_sour_cream,corn] soft beef [salsa,spicy_sour_cream,rice_beans] However, I miss the constraints: 6 tacos and three with different ingredients. In go2/0 we fix this by constraint modelling. - With lex2/1 symmetry breaking, there are 720 different configurations - Without lex2/1: 518400 different configurations Here are the first three solutons (with lex2/1): Tacos: [hard,chicken,salsa,lettuce,sour_cream] [hard,chicken,salsa,lettuce,spicy_sour_cream] [hard,beef,salsa,corn,sour_cream] [soft,chicken,salsa,corn,spicy_sour_cream] [soft,chicken,salsa,rice_beans,sour_cream] [soft,beef,salsa,rice_beans,spicy_sour_cream] Tacos: [hard,chicken,salsa,lettuce,sour_cream] [hard,chicken,salsa,lettuce,spicy_sour_cream] [hard,beef,salsa,corn,sour_cream] [soft,chicken,salsa,corn,spicy_sour_cream] [soft,chicken,salsa,rice_beans,spicy_sour_cream] [soft,beef,salsa,rice_beans,sour_cream] Tacos: [hard,chicken,salsa,lettuce,sour_cream] [hard,chicken,salsa,lettuce,spicy_sour_cream] [hard,beef,salsa,corn,sour_cream] [soft,chicken,salsa,corn,spicy_sour_cream] [soft,beef,salsa,rice_beans,sour_cream] [soft,beef,salsa,rice_beans,spicy_sour_cream] Numerically, the frst 3 solutions look like this, which more clearly shows the lex2/1 symmetry: [1,1,1,1,1] [1,1,1,1,2] [1,2,1,2,1] [2,1,1,2,2] [2,1,1,3,1] [2,2,1,3,2] [1,1,1,1,1] [1,1,1,1,2] [1,2,1,2,1] [2,1,1,2,2] [2,1,1,3,2] [2,2,1,3,1] [1,1,1,1,1] [1,1,1,1,2] [1,2,1,2,1] [2,1,1,2,2] [2,2,1,3,1] [2,2,1,3,2] This program was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import cp. main => go. go => tacos(Tacos), member($taco(Shell, Meat, Toppings), Tacos), printf("%w %w %w\n", Shell, Meat, Toppings), fail, nl. % CP go2 => N = 6, % number of tacos ingredients(Ingredients), M = Ingredients.len, % number of ingredients % "I'll have six tacos." X = new_array(N,M), foreach(T in 1..N) % The possible ingredients foreach(J in 1..M) X[T,J] :: 1..Ingredients[J].len end end, % "Three hard and three soft." Hard = 1, Soft = 2, global_cardinality([X[T,1] : T in 1..N], $[Hard-3,Soft-3]), % "Three with chicken, and three with beef," Chicken = 1, Beef = 2, global_cardinality([X[T,1] : T in 1..N], $[Chicken-3,Beef-3]), % "but not so that all the chicken % or beef are on the same style taco." % (Ensure that we got all combinations of Shell and Meat) AllComb = [[Hard,Chicken],[Hard,Beef],[Soft,Chicken],[Soft,Beef]], foreach([Shell,Meat] in AllComb) sum([X[T,1] #= Shell #/\ X[T,2] #= Meat : T in 1..N]) #> 0 end, % "I'll have any three toppings between lettuce, salsa, rice and beans, % sour cream and spicy sour cream such that salsa and any style of sour cream is on all of them % and that no two tacos have the exact same contents." % (Ensure that topping and sour_cream are different) foreach(T1 in 1..N, T2 in T1+1..N) sum([X[T1,J] #!= X[T2,J] : J in 4..5]) #> 0 end, % Symmetry breaking: lexicographical order of the tacos % (for the integer values). lex2(X), solve(X), println("Tacos:"), % foreach(Row in X) println(Row.to_list) end, foreach(T in 1..N) println([Ingredients[J,X[T,J]] : J in 1..M]) end, nl, fail, nl. % % lex2(X): ensure that the rows are sorted in % lexicographical order. % lex2(X) => foreach(I in 2..X.length) lex_lt(X[I-1], X[I]) end. ingredients(Ingredients) :- Ingredients = [ [hard,soft], [chicken,beef], [salsa], [lettuce, corn, rice_beans], [sour_cream, spicy_sour_cream] ]. % % This is the original Prolog program: % shell(hard). shell(soft). meat(chicken). meat(beef). topping(lettuce). topping(corn). topping(rice_beans). sour_cream(sour_cream). sour_cream(spicy_sour_cream). taco(Shell, Meat, [salsa, Cream, Other]) :- shell(Shell), meat(Meat), sour_cream(Cream), topping(Other). tacos(Tacos) :- % setof($taco(X, Y, Z), $taco(X, Y, Z), Tacos). Tacos = findall($taco(X, Y, Z), $taco(X, Y, Z)). % hakank: Picat does not support setof