Monday, February 06, 2012

Analytical Reasoning With Prolog

Last year, I solved the following analytical reasoning problem by hand. Post learning Prolog, I think this is a good problem to solve using a computer! I had a interesting experience doing so.

Problem:

Facts:
1: There are 5 villas in 5 different colors 
2: In each villa lives a person with a different nationality. 
3: These 5 owners drink a certain beverage, smoke a certain brand of cigar and keep a certain pet. 
4: No owner has the same pet, smoke the same brand of cigar or drink the same drink.
Hints:
1: The British lives in a red villa. 
2: The Swede keeps dogs as pets 
3: The Dane drinks tea 
4: The green villa is on the left of the white villa (it also means they are next door to each other) 
5: The green villa owner drinks coffee 
6: The person who smokes Pall Mall rears birds 
7: The owner of the yellow villa smokes Dunhill 
8: The man living in the villa right in the center drinks milk 
9: The Norwegian lives in the first villa 
10: The man who smokes Blend lives next to the one who keeps cats 
11: The man who keeps horses lives next to the man who smokes Dunhill 
12: The owner who smokes Blue Master drinks beer 
13: The German smokes Prince 
14: The Norwegian lives next to the blue villa 
15: The man who smokes Blend has a neighbor who drinks water.

The question is: who keeps the fish?

Prolog Solution:

The following is what i could come up with after serval iterations through code.

#!/opt/local/bin/gprolog --consult-file
segment([H1,H2],[H1,H2]):-!.
segment([H1,H2],[H1,H2|_]):-!.
segment([H1,H2],[_,H4|T2]) :- segment([H1,H2],[H4|T2]).
adjacent([H1,H2],L1,L2) :- segment([H1,H2],L1),!;segment([H2,H1],L2),!.
valid_set([],_,_).
valid_set([H|T],Y,AL):- member(H,Y), \+(member(H,AL)), valid_set(T,Y,[H|AL]).
valid_values(L,Y):- valid_set(L,Y,[]).
villas :-
Solution =[
(1,N1,C1,D1,S1,P1),
(2,N2,C2,D2,S2,P2),
(3,N3,C3,D3,S3,P3),
(4,N4,C4,D4,S4,P4),
(5,N5,C5,D5,S5,P5)
],
% 9: Norwegian lives in first villa.
N1=norwegian,
% 8: Man living in the center villa drinks milk.
D3=milk,
valid_values([C1,C2,C3,C4,C5],[green,white,yellow,blue,red]),
% 4: Green villa is left of white villa.
segment([green,white],[C1,C2,C3,C4,C5]),
valid_values([N2,N3,N4,N5],[dane,german,british,swede]),
% 1: British lives in a red villa.
segment([british,red],[N1,C1,N2,C2,N3,C3,N4,C4,N5,C5]),
% 14: Norwegian lives next to blue villa.
segment([norwegian,blue],[N1,C2,N2,C3,N3,C4,N4,C5]),
valid_values([D1,D2,D4,D5],[coffee,beer,water,tea]),
% 5: Green villa owner drinks coffee.
segment([green,coffee],[C1,D1,C2,D2,C3,D3,C4,D4,C5,D5]),
% 3: Dane drinks tea.
segment([dane,tea],[N1,D1,N2,D2,N3,D3,N4,D4,N5,D5]),
valid_values([S1,S2,S3,S4,S5],[pallmall,dunhill,blend,bluemaster,prince]),
% 13: German Smokes Prince.
segment([german,prince],[N1,S1,N2,S2,N3,S3,N4,S4,N5,S5]),
% 12: Owner who smokes Bluemaster drinks beer.
segment([bluemaster,beer],[S1,D1,S2,D2,S3,D3,S4,D4,S5,D5]),
valid_values([P1,P2,P3,P4,P5],[fish,cat,birds,horse,dog]),
% 2: Swede keeps dogs as pets.
segment([swede,dog],[N1,P1,N2,P2,N3,P3,N4,P4,N5,P5]),
% 6: Person who smokes pallmall rears birds.
segment([pallmall,birds],[S1,P1,S2,P2,S3,P3,S4,P4,S5,P5]),
% 7: Owner of yellow vill smokes Dunhill.
segment([yellow,dunhill],[C1,S1,C2,S2,C3,S3,C4,S4,C5,S5]),
% 15: Man who smokes Blend has a neighbor who dinks water.
adjacent([blend,water],[S1,D2,S2,D3,S3,D4,S4,D5],[D1,S2,D2,S3,D3,S4,D4,S5]),
% 10: Man who smokes Blend lives next to the man who keeps cats.
adjacent([blend,cat],[S1,P2,S2,P3,S3,P4,S4,P5],[P1,S2,P2,S3,P3,S4,P4,S5]),
% 11: Man who keeps horses lives next to man who smokes Dunhill.
adjacent([dunhill,horse],[S1,P2,S2,P3,S3,P4,S4,P5],[P1,S2,P2,S3,P3,S4,P4,S5]),
printSol(Solution).
printSol([]).
printSol([H|T]) :- write(H),nl,printSol(T).
view raw 5villas.prolog hosted with ❤ by GitHub

Answer to Puzzle:

Following is the output of the prolog program.

1,norwegian,yellow,water,dunhill,cat
2,dane,blue,tea,blend,horse
3,british,red,milk,pallmall,birds
4,german,green,coffee,prince,fish
5,swede,white,beer,bluemaster,dog

Hence the answer is German keeps the fish.


1 comment:

Calvin said...

Wow...!! Interesting...I too am yet to try Prolog...it's next on my 'Scheme' o' things...! :)

Amazing if such inference problems could be solved using automation...thus reducing human error...and perhaps, help 'discover' deeply nested 'conclusions' about patterns, theorems, etc...