/* Wason Selection test in Picat. This Picat PPL model was inspired by Bayesian Adventures (Pascal Bercker): "Modeling the Wason Selection Task ..." https://www.youtube.com/watch?v=xdsSiXmkoZ0 """ Each card has a number on one side and a letter on the other side. Which card(s) must you turn over in order to test the truth of the proposition IF a card shows a vowel on one face, THEN it's an even number on the other ? The cards are A K 4 7 [We should turn A and 7.] """ The video contains a wonderful explanation of this problem using Bayesian Networks (Netica). The following rule is probably simpler to understand (and is also discussed in the video): IF P is drinking alchohol THEN P must be 18 year or older, Here are 4 cards representing people that we know are drinking something: Drinking Beer Drinking Cola Age is 20 Age is 17 Which card should be checked to check if the rule is enforced: Answer: We should turn the "cards": - "Drinking beer" (to check the age) - "Age is 17" (to check the drink) The two other case are irrelevant: - Drinking Cola: no age limit - Age is 20: They can drink whatever they like. This is exactly the same situation as the Wason test above. Below is the result of the two cases using the model. The variable rule-ok represents if the rule is enforced or not. If it's 100% true, then we know everything that's needed to know, and we don't have to turn the card. However, for the cases when rule-ok is uncertain, we have to turn the card, i.e. the first and fourth cards in both scenarios. Note: true and false represents the facts that we know something about the side of the card (alcohol drink, age) and (vowel, even number), respectively. "N/A" means that we don's know the that side of the card. [Alcohol rule: IF P is drinking alchohol THEN P must be 18 year or older.] card = [Beer,true,N/A] [card,drinking alcohol,age >= 18] min_accepted_samples = 10000 var : rule ok Probabilities: true: 0.5070000000000000 false: 0.4930000000000000 mean = 0.507 We need to turn this card. card = [Cola,false,N/A] [card,drinking alcohol,age >= 18] min_accepted_samples = 10000 var : rule ok Probabilities: true: 1.0000000000000000 mean = 1.0 We don̈́t have to turn this card. card = [20 yo,N/A,true] [card,drinking alcohol,age >= 18] min_accepted_samples = 10000 var : rule ok Probabilities: true: 1.0000000000000000 mean = 1.0 We don̈́t have to turn this card. card = [17 yo,N/A,false] [card,drinking alcohol,age >= 18] min_accepted_samples = 10000 var : rule ok Probabilities: false: 0.5014000000000000 true: 0.4986000000000000 mean = 0.4986 We need to turn this card. [Wason test: IF a card shows a vowel on one face, THEN it's an even number on the other face] card = [A,true,N/A] [card,is vowel,is even] min_accepted_samples = 10000 var : rule ok Probabilities: true: 0.5082000000000000 false: 0.4918000000000000 mean = 0.5082 We need to turn this card. card = [K,false,N/A] [card,is vowel,is even] min_accepted_samples = 10000 var : rule ok Probabilities: true: 1.0000000000000000 mean = 1.0 We don̈́t have to turn this card. card = [4,N/A,true] [card,is vowel,is even] min_accepted_samples = 10000 var : rule ok Probabilities: true: 1.0000000000000000 mean = 1.0 We don̈́t have to turn this card. card = [7,N/A,false] [card,is vowel,is even] min_accepted_samples = 10000 var : rule ok Probabilities: true: 0.5036000000000000 false: 0.4964000000000000 mean = 0.5036 We need to turn this card. Also, see * https://en.wikipedia.org/wiki/Wason_selection_task * Pascal Bercker's Medium posts on Bayesian Networks and puzzle solving https://medium.com/@pbercker Cf my Gamble model gamble_wason_selection_test.rkt This program was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import ppl_distributions, ppl_utils. import util. % import ordset. main => go. /* */ go ?=> % Alcohol rule % "N/A": We don't know the value of this % side of the card % % drinking alchohol age >= 18 Alcohol = [["Beer", true, "N/A"], % Beer ["Cola", false, "N/A"], % Cola ["20 yo","N/A", true], % 20 yo ["17 yo","N/A", false] % 17 yo ], % Wason selection test % is_vowel is_even Wason = [["A", true, "N/A"], % A ["K", false, "N/A"], % K ["4", "N/A", true], % 4 ["7", "N/A", false] % 7 ], Tests = [Alcohol,Wason], Descriptions = [ [["Alcohol rule: IF P is drinking alchohol THEN P must be 18 year or older."], ["card","drinking alcohol", "age >= 18" ]], [["Wason test: IF a card shows a vowel on one face, THEN it's an even number on the other face"], ["card","is vowel", "is even"]] ], NumCards = Tests.len, foreach(I in 1..NumCards) println(Descriptions[I,1]), foreach(Card in Tests[I]) println(card=Card), println(Descriptions[I,2]), reset_store, run_model(10_000,$model(Card),[show_probs_trunc,mean, min_accepted_samples=10_000 %,show_accepted_samples=true ]), RuleOK = get_store().get("rule ok").mean, if RuleOK == 1.0 ; RuleOK == 0.0 then println("We don̈́t have to turn this card.") else println("We need to turn this card.") end, nl, nl end end, % show_store_lengths,nl, fail, nl. go => true. boolp(V) => V == true ; V == false. model(Card) => IfPart = flip(1/2), ThenPart = flip(1/2), RuleOK = cond(IfPart == true,ThenPart,true), S1 = Card[2], % Side 1 of the card S2 = Card[3], % Side 2 of the card % We only use observe if we know the value of the side of the card, Observe = false, if boolp(S1) then observe(IfPart == S1), Observe := true end, if boolp(S2) then observe(ThenPart == S2), Observe := true end, if Observe == false ; (Observe == true, observed_ok) then add("rule ok",RuleOK), end.