====== Archive eFLP 2011: Prolog Tutorial 1: Basic Prolog ====== ===== Initial code ===== [[http://pastebin.com/fpPtR2kn|Pasebin code with latest changes]] connected(bond_street, oxford_circus, central). connected(oxford_circus, tottenham_court_road, central). connected(bond_street, green_park, jubilee). % Isn't there a missing connection? % Yes, indeed! From 'green_park' to 'charing_cross'... connected(green_park, piccadilly_circus, piccadilly). connected(piccadilly_circus, leicester_square, piccadilly). connected(green_park, oxford_circus, victoria). connected(oxford_circus, piccadilly_circus, bakerloo). connected(piccadilly_circus, charing_cross, bakerloo). connected(tottenham_court_road, leicester_square, northern). connected(leicester_square, charing_cross, northern). ===== Objectives ===== - **Install Prolog** - **Learn the syntax:** Add the missing underground link into the initial code.((Solution from [[http://pastebin.com/w6MXjdnC|pastebin]]: connected(green_park, charing_cross, jubilee).)) - **Basic predicates:** Define the ''nearby/2'' predicate = stations on the same line, distant at most 2 stops.((Solution from [[http://pastebin.com/e97TxFxd|pastebin]]: nearby(X,Y) :- connected(X,Y,_). nearby(X,Z) :- connected(X,Y,L), connected(Y,Z,L).)) - **Recursion:** Define ''reachable/2'' = stations reachable via any number of intermediate stops, not necessarily on the same line.((Solution from [[http://pastebin.com/N2uun7Fz|pastebin]]: reachable(X,Y) :- connected(X,Y,_). reachable(X,Y) :- connected(X,Z,_), reachable(Z,Y).)) You may have to add ''connected('Mustek', 'Muzeum', 'A').'' fact for testing purposes. - **Debug trace:** Try debugging the code to see the order of execution. [[https://docs.google.com/present/edit?id=0AUhT50rgdR0KZGNrOTNxODRfOTYyaG1rMmNjdw|Tutorial slides]] (({{flp_tutorial_1.pdf|Archived version in a PDF file}})) ====== Prolog Tutorial 2: Lists ====== ===== Initial code ===== [[http://pastebin.com/VKN1Yksq|Pasebin code with latest changes]] connected(bond_street, oxford_circus, central). connected(oxford_circus, tottenham_court_road, central). connected(bond_street, green_park, jubilee). connected(green_park, charing_cross, jubilee). connected(green_park, piccadilly_circus, piccadilly). connected(piccadilly_circus, leicester_square, piccadilly). connected(green_park, oxford_circus, victoria). connected(oxford_circus, piccadilly_circus, bakerloo). connected(piccadilly_circus, charing_cross, bakerloo). connected(tottenham_court_road, leicester_square, northern). connected(leicester_square, charing_cross, northern). reachable(X,Y) :- connected(X,Y,_). reachable(X,Y) :- connected(X,Z,_), reachable(Z,Y). ===== Objectives ===== - **Understand the unification algorithm** - **Recall the list representation:** Relate LISP's ''cons'' and ''nil'' to Prolog's //dot// and ''[]'' functions - **Learn how to construct lists:** Define predicate ''journey/3'' which returns a list of visited stations on a journey.((Firstly print the list to STDOUT ([[http://pastebin.com/0waXKGCb|pastebin]]):reachable(X,Y) :- connected(X,Y,_). reachable(X,Y) :- connected(X,Z,_), write(X), nl, reachable(Z,Y). The add the third argument which creates a list ([[http://pastebin.com/0waXKGCb|pastebin]]): reachable(X,Y, [Y]) :- connected(X,Y,_). reachable(X,Y, [Z|List]) :- connected(X,Z,_), reachable(Z,Y, List). You can include the very first station on the journey ([[http://pastebin.com/2dBT1xh1|pastebin]]): reachable(X,Y, [X,Y]) :- connected(X,Y,_). reachable(X,Y, [X|List]) :- connected(X,Z,_), reachable(Z,Y, List).)) - **Parse lists:** Define your own implementation of the ''member/2'' predicate.((Solution from [[http://pastebin.com/cvFNXL1V|pastebin]]:my_member(X, [X|_]). my_member(X, [_|T]) :- my_member(X, T).)) - **Limitations of Prolog lists:** Understand how ''append/3'' works and implement your own ''my_append/3'' predicate. [[https://docs.google.com/present/edit?id=0AUhT50rgdR0KZGNrOTNxODRfMTAwZnJ2N3A1Z3c|Tutorial slides]](({{flp_tutorial_2.pdf|Archived version in a PDF file}})) ====== Prolog Tutorial 3: Code efficiency ====== - **Arithmetics:** Learn the difference between ''X = 1 + 1'' and ''X is 1 + 1''. - **Programming challenge:** As an experienced Prolog programmer, define factorial. - **Benefits of tail recursion:** - Compare and contrast [[http://pastebin.com/iqNJBKBu|two exemplary implementations]].((Archived version: factorial_1(1,1). factorial_1(N,F):- N > 1, NN is N - 1, factorial_1(NN,FF), F is N * FF. factorial_2(1,F,F). factorial_2(N,T,F):- N > 1, TT is N * T, NN is N - 1, factorial_2(NN,TT,F). )) - Evaluate efficiency of both implementations by computing 10000!: ''time(factorial(10000,_))'' - **Understand the //cut//:** Play with the [[http://pastebin.com/bGM9FnCF|supplied code]]. ((Archived version: q(b). q(c). p(a). p(X) :- q(X), !. p(d). )) - **Use //cut// in your code:** With and without the cut, define ''max/3'' = maximum of two numbers.((Solution ([[http://pastebin.com/HRu33y9e|pastebin]]):max1(A,B,A) :- A >= B. max1(A,B,B) :- A < B. max2(A,B,A) :- A >= B, !. max2(A,B,B).)) [[https://docs.google.com/present/edit?id=0AUhT50rgdR0KZGNrOTNxODRfMTAxdnhjZjRrMjc|Tutorial slides]](({{flp_tutorial_3.pdf|Archived version in a PDF}})) **Check you understand:** Compare the ''factorial_1'' predicate with ''factorial_3'' that uses the //cut//. What difference in behaviour can you spot? factorial_3(1,1):- !. factorial_3(N,F):- NN is N - 1, factorial_3(NN,FF), F is N * FF. ====== Prolog Tutorial 4: Searching a graph ====== ===== Initial code ===== h(a,b). h(a,c). h(a,d). h(b,e). h(b,f). h(b,g). h(c,h). h(c,i). h(d,j). h(d,k). h(d,l). h(e,m). h(e,n). h(f,n). h(g,p). h(g,q). h(g,r). h(i,i). h(i,s). h(i,t). h(j,t). h(k,u). h(k,v). h(l,w). h(l,x). h(n,y). h(t,z). h(t,z). h(p,a). goal(f). goal(r). goal(u). ===== Objectives ===== - Implement a basic depth-first-search (DFS) algorithm.((Solution: dfs1(X,X,[]) :- goal(X). dfs1(X,G,[X|P]) :- h(X,Y), X\=Y, dfs1(Y,G, P).)) - Avoid infinite looping by creating a //closed list//.((Solution: dfs2(X,X,Path,Path) :- goal(X). dfs2(X,G,Closed,Path) :- h(X,Y), \+ member(Y,Closed), dfs2(Y,G, [Y|Closed], Path).)) - Implement a bredth-first-search (BFS) algorithm. ((Solution: dfs3(X,[X|_],Path,Path) :- goal(X). dfs3(G,[X|Open],Closed,Path) :- findall(Y, h(X,Y), Successors), append(Successors, Open, NewOpen), dfs3(G, NewOpen, [X|Closed], Path).)) [[http://pastebin.com/tDkfJQuK|Pastebin code with solutions]] ====== Prolog Tutorial 5: Searching a state-space ====== ===== Initial code ===== % Obstacles - find path from initial to goal position on 8x8 board % Possible moves: up, down, left, right % Position of obstacles defined by obstacle/1 step(1, 0, r). step(0, 1, u). step(-1, 0, l). step(0, -1, d). obstacle(pos(2,1)). obstacle(pos(2,2)). obstacle(pos(3,3)). obstacle(pos(4,3)). obstacle(pos(3,4)). correct(pos(X,Y)) :- X > 0, Y > 0, X =< 8, Y =< 8, not(obstacle(pos(X,Y))). ===== Objectives ===== - **Implement a BFS:**((Solution ([[http://pastebin.com/WwQMPrmd|pastebin]]): search([state(pos(X,Y),D,F,Moves)|_], pos(X,Y), solution(MovesRev,F)) :- reverse(Moves, MovesRev). search([State|Open], Goal, Solution) :- expandstate(State, Goal, Successors), insertstates(Successors, Open, NewOpen), search(NewOpen, Goal, Solution). expandstate(State, Goal, Successors) :- findall(Successor, move(State, Goal, Successor), Successors). move(state(pos(X,Y),D,_,Moves), pos(XGoal,YGoal), state(pos(X2,Y2),D2,F2,[Dir|Moves])) :- step(DX, DY, Dir), X2 is X + DX, Y2 is Y + DY, correct(pos(X2,Y2)), D2 is D + 1, F2 is D2 + abs(X2-XGoal) + abs(Y2-YGoal). step(1, 0, r). step(0, 1, u). step(-1, 0, l). step(0, -1, d). obstacle(pos(2,1)). obstacle(pos(2,2)). obstacle(pos(3,3)). obstacle(pos(4,3)). obstacle(pos(3,4)). correct(pos(X,Y)) :- X > 0, Y > 0, X =< 8, Y =< 8, not(obstacle(pos(X,Y))). insertstates([], L, L). insertstates([H|T], L, L2) :- insertstate(H, L, L1), insertstates(T, L1, L2). insertstate(X, [], [X]). insertstate(X, [H|T], [X,H|T]) :- gef(H, X), !. insertstate(X, [H|T], [H|T2]) :- insertstate(X, T, T2). gef(state(_,_,F1,_), state(_,_,F2,_)) :- F1 >= F2. %------------------------------------------------ insertsorted(X, [], [X]). insertsorted(X, [H|T], [X,H|T]) :- H >= X, !. insertsorted(X, [H|T], [H|T2]) :- insertsorted(X, T, T2). )) Find a path from initial to goal position on 8x8 board s.t:% Using compound term state: state(pos(X,Y),D,F,Moves) % search(InitState, GoalPosition, Solution) ?- search([state(pos(1,1),0,0,[])], pos(4,1), S). ====== Prolog Tutorial 6: Constraint logic programming ====== ===== Initial code ===== [[http://pastebin.com/BxA4PV21|Pastebin code with latest changes]] % alldiff([A,B,C,D,...]): All A,B,C,D,... are mutually different. alldiff([X|Tail]) :- ... % Plots the given matrix. plot([]). plot([[]|T]) :- nl, plot(T). plot([[X|T1]|T2]) :- write(X), plot([T1|T2]). % Numbers 1..4 are assigned to all variables in the given list. numbers([]). numbers([X|Tail]) :- member(X,[1,2,3,4]), numbers(Tail). % Solves the SUDOKU and gives the answer. sudoku([[A1,B1,C1,D1],[A2,B2,C2,D2],[A3,B3,C3,D3],[A4,B4,C4,D4]]) :- % Phase 1: Assign 1..4 to variables A1..D4 randomly. % predicate numbers(...) may help! % Phase 2: Check, whether the solution is a valid SUDOKU. % predicate alldiff(...) may help! ===== Objectives ===== - **Study the theory:** [[http://en.wikipedia.org/wiki/Sudoku|Sudoku on Wikipedia]]. - **Train your skills:** Define a helper predicate ''alldiff/1''. - **Naïve Sudoku:** Implement a naïve implementation of Sudoku generator and solver in a //generate-and-test// fashion. Measure computation time. - **Optimize:** Push the //test// conditions up inbetween the //generate// calls to increase the efficiency. Measure the computation time. - **CSP:** Return to the naïve implementation and convert it into a CSP problem. Measure the computation time.