150 likes | 289 Views
More examples. Today’s examples are related to coursework . In the original program, the relation arrow(X,Y) represents a directed link from X to Y. The relation cango (X,Y) means that there is a path from X to Y cango (X, Y):- arrow(X, Y). cango (X, Y):- arrow(X, Z),
E N D
More examples Today’s examples are related to coursework
In the original program, the relation arrow(X,Y) represents a directed link from X to Y. The relation cango(X,Y) means that there is a path from X to Y cango(X, Y):- arrow(X, Y). cango(X, Y):- arrow(X, Z), cango(Z, Y). Once upon a time, an insect was crawling along a wire cube, …… b a d c e f g h
cango(X, Y):- arrow(X, Y). cango(X, Y):- arrow(X, Z), cango(Z, Y). ?- cango(a,h). a b c e d f d g g f h hhhhh Prolog uses ‘cango’ with a depth first search. ‘cango’ is a general program not just for this given cube. How does ‘cango’ program work? b a d c e f g h Observation: change the order of arrow, then check if the order of solutions changes
In the original program, the relation arrow(X,Y) only represents a link from X to Y, not Y to X. How do we extend it to a bi-directional link? Easy – using disjunction: next(X, Y):- arrow(X, Y). next(X, Y):- arrow(Y, X). Is ‘cango’ really a general program? b a d c e f g h cango(X, Y):- next(X, Y). cango(X, Y):- next(X, Z), cango(Z, Y).
Introduced circles into the map. There is a danger of being trapped in a circle! ?- cango(a,h). a b c e a d b c a a What happens after replacing ‘arrow’ by ‘next’? b a d c e f g h cango(X, Y):- next(X, Y). cango(X, Y):- next(X, Z), cango(Z, Y).
We must add something to avoid being trapped in a circle. Solution 1: using an extra list to store the path generated so far, only extend a new node which is not in the list Solution 2: no u-turn. it is restricted to certain type of maps where circles are only created by u-turn. Q: Is ‘cango’ a general program? A: It only works if no circle in the map. b a d c e f g h Q-block
Solution 2 (we will use this!) • For some maps, there are no circles as long as u-turn is not allowed. In this case, the easy solution is to add an extra test to disallow u-turn. next(a, b, north). next(b, a, south). ...... % PreDir is the direction before X cango(X,Y, PreDir):- next(X,Y, Dir), not_u_turn(PreDir, Dir). cango(X,Y, PreDir):- next(X,Z, Dir), not_u_turn(PreDir, Dir), cango(Z , Y, Dir).
Two ways to define not_u_turn • Define ‘u_turn’, then make use of \+ (not) : u_turn(south,north). u_turn(north,south). u_turn(west,east). u_turn(east, west). not_u_turn(X,Y):- \+( u_turn(X,Y) ). • Define ‘not_u_turn’ directly : not_u_turn(south, west). not_u_turn(south, east). ....... not_u_turn(start, _).
Move to real program, more information needed in the ‘next’ % (From,To, Direction, WhichSide, Distance) next('2q43', '2q49', south, right, 1). next('2q49', '2q43', north, left, 1). next('2q49', 'area3', south, left, 1). next('area3', '2q49', north, left, 1). next('area3', '2q46', south, left, 3). next('2q46', 'area3', north, right, 3). next('2q46', '2q47', south, left, 2). next('2q47', '2q46', north, right, 2). .......
Your ‘cango’ program should have6 parameters cango(X,Y,Path,Dir,Dist,PreDir) Path and Dir are lists which are exactly same as cango4 Dist is a list of distances PreDir indicates previous direction. You need to use it to compare with the next direction. no u-turn ! For example ?- cango(‘2q43’, ‘2q47’, P, Dir, Dist, start). P = [2q43,2q49,area3,2q46,2q47] Dir = [south,south,south,south] Dist = [1,1,3,2]
Put them all together :-[map]. % include the file map.pl test(X, Y):- cango(X, Y, Path, Dir, Dist, start), cal_route(Dir, Dist, NewDir, NewDist), write(NewDir), nl, write(NewDist), nl.
A little help on ‘cal_route’ (week5’s task) • The following program reduces a sequence of same items into to one item reduce([X],[X]). % if only one item % nothing to reduce reduce([X,X|T], R):- reduce( [X|T], R ). reduce([X,Y|T], [X|R]):- X \== Y, reduce( [Y|T], R ). ?- reduce([a,a,b,b,b,c], R). produces R = [a,b,c]
Need an extra list to store the path generated so far: cango(X,Y, CurrentPath):- next(X,Y), \+ member(Y,CurrentPath). cango(X,Y, CurrentPath):- next(X,Z), \+ member(Z,CurrentPath), cango(Z,Y, [Z|CurrentPath]). (‘\+’ means ‘not’) If we want to return a path, then add the 4th argument: cango(X,Y, P, FinalPath):- next(X,Y), \+ member(Y,P). FinalPath = [Y|P]. cango(X,Y, CP, FP):- next(X,Z), \+ member(Z,CP), cango(Z,Y, [Z|CP], FP). Solution 1 - new cango program with circle detection (not used for our assignment !)
When call this new cango, we must initialize the 3rd argument Question: What is the CurrentPath initially? Answer: it is the start point. ?- cango(a,h, [a], Path). Path = [h,d,b,a], … … Why the returned Path is reversed? In each recursion, the 3rd argument is added an element at its front: [a], [b,a], [d,b,a], and finally [h,d,b,a] This kind of list is called an accumulator
Naïve reverse rev1([H|T], R):- rev1(T, RT), append(RT,[H], R). append([], L, L). append([H|T],X,[H|L]):- append(T,X,L). More efficient reverse – the 3rd arg. is an accumulator rev2(L, RL):- % init accumulator rev2(L, RL, []). rev2([H|T], RL, CL):- rev2(T, RL, [H|CL]). rev2([], RL, CL):- % base RL=CL. How to reverse a list another example of using accumulator