Introduction

The exam will be taken in August. After a period of thinking, trying to some write-ups should be helpful for retaking the exam. Goal: finishing Prolog on Wednesday (14th July 2021).

Body

Chapter 4

Chapter 4 has a variety of examples, it will be helpful if they are gone through.

1. Graph Introduction

The first example is an introduction to the graph. The goal is to:

  1. using the depth-first mechanism to find whether there is a path from a to e
  2. using the breadth-first mechanism to find whether there is a path from a to c

7acfa2a6004011564f314d8b46e7ef5

Program code is shown as below:

% database for graph
link(a,b).
link(a,c).
link(b,d).
link(c,d).
link(c,f).
link(d,e).
link(d,f).
link(f,a).

% using the depth-first mechanism to find whether there is a path from a to e
% base case
path(N1,N1).
% recursive case
path(N1,N3) :-
    link(N1,N2),
    path(N2,N3).

% using the breadth-first mechanism to find whether there is a path from a to c
% first, we need to transfer 'depth-first' to 'breadth-first' via conc(Path,_,_) or a new method list(Path)
% then, change path(N1,N2) to path(N1,N2,Path) for using our new method list(Path)
% new method list(Path)
list1([]).
list1([_|L]) :-
    list1(L).
% improved path/3 for recording path
path(N1,N1,[N1]).
path(N1,N3,[N1|T]) :-
    link(N1,N2),
    path(N2,N3,T).

Question terminal is shown as below:

?- path(a,e).
true

?- path(a,c).
** Excution aborted **

?- list1(Path), path(a,c,Path).
Path = [a,c]

2. Robot Task Planning

The second example is trying to use the robot to clean the room:

  1. finding a way to represent the state of the robot, rubbish, basket
  2. determining the actions: pickup, drop, push(Pos1,Pos2), go(Pos1,Pos2)
  3. planning the time schedule and give the answer

51d40a3a12b3a0c5d83af46e037af81

Program code is shown as below:

% first, the state will be represented by state(Pos1,Pos2,Pos3), saying that Pos1 is the position of the robot, Pos2 is the position of the basket, Pos3 is the position of the rubbish
% rubbish has its special state: floor(Pos1) is on the floor, held means it is carried by the robot, in_basket means it is in the basket

% second, actions will be represented as followed
% it is the idea from textbook, much simpler and clearer
% pickup, pick up rubbish from floor, more simpler
action1(state(Pos1,Pos2,floor(Pos1)),
        pickup,
        state(Pos1,Pos2,picked)).
% drop, drop rubbish into basket
action1(state(Pos1,Pos1,picked),
        drop,
        state(Pos1,Pos1,in_basket)).
% push(Pos1,Pos2), push basket from position Pos1 to Pos2
action1(state(Pos1,Pos1,Pos2),
        push(Pos1,NewPos1),
        state(NewPos1,NewPos1,Pos2)).
% go(Pos1,Pos2), go from Pos1 to Pos2
action1(state(Pos1,Pos2,Pos3),
        go(Pos1,NewPos1),
        state(NewPos1,Pos2,Pos3)).

% after determination of actions, plan/3 is also important for recording current state, goal state and schedules
% base case, for the end of the recursion
plan(GoalState,GoalState,[]).
% recursive case, for running the ai determination; otherwise, will not work
plan(CurrentState,GoalState, [Action|RPath]) :-
    action1(CurrentState,Action,NewState),
    plan(NewState,GoalState, RPath).

Question terminal is shown as below:

% Depth-first
?- plan(state(door,corner2,floor(middle)),state(_,_,in_basket),Plan).
Plan = [go(door, middle), pickup, go(middle, corner2), drop]
Plan = [go(door, middle), pickup, go(middle, corner2), drop, push(corner2, _1422)]
Plan = [go(door, middle), pickup, go(middle, corner2), drop, push(corner2, _1422), push(_1422, _1434)]

?- list1(Plan), plan(state(door,corner2,floor(middle)),state(_,_,in_basket),Plan).
Plan = [go(door, middle), pickup, go(middle, corner2), drop]
Plan = [go(door, corner2), push(corner2, middle), pickup, drop]
Plan = [go(door, middle), pickup, go(middle, corner2), drop, push(corner2, _1422)]

3. Trip planning

The third example is trying to try to plan a trip according to a sight-seeing plan and the timetable of boat transfers:

  1. building the database of timetable
  2. building some actions and helpers
  3. planning the time schedule and give the answer

73d16f6a9df9140dd84839cb4dc1822

Program code is shown as below:

% define operators
:- op(200,xfx,and).
:- op(100,xfx, at).
:- op(50,xfx,:).


% database
timetable([riva at 8:00, limone at 8:35, malcesine at 8:55]).
timetable([riva at 9:10, torbole at 9:25, limone at 9:55, malcesine at 10:15]).
timetable([riva at 9:45, torbole at 10:00, limone at 10:30, malcesine at 10:50]).
timetable([riva at 11:45, torbole at 12:00, limone at 12:30, malcesine at 12:50]).
timetable([riva at 13:10, limone at 13:32, malcesine at 13:45]).
timetable([riva at 14:05, limone at 14:40, malcesine at 15:00]).
timetable([riva at 15:00, limone at 15:36, malcesine at 15:57, campione at 16:13]).
timetable([riva at 16:20, torbole at 16:35, limone at 17:05, malcesine at 17:25]).
timetable([riva at 18:05, torbole at 18:20, limone at 18:50, malcesine at 19:10]).

timetable([malcesine at 9:00, limone at 9:20, torbole at 9:50, riva at 10:05]).
timetable([malcesine at 10:25, limone at 10:50, torbole at 11:20, riva at 11:35]).
timetable([malcesine at 11:25, limone at 11:45, riva at 12:20]).
timetable([campione at 12:25, malcesine at 13:12, limone at 13:34, riva at 14:10]).
timetable([malcesine at 13:45, limone at 13:59, riva at 14:20]).
timetable([malcesine at 15:05, limone at 15:25, riva at 16:00]).
timetable([malcesine at 16:30, limone at 16:50, torbole at 17:20, riva at 17:35]).
timetable([malcesine at 18:15, limone at 18:35, torbole at 19:05, riva at 19:20]).
timetable([malcesine at 19:15, limone at 19:35, torbole at 20:05, riva at 20:20]).

% sublist, helper
% actually we can use member/2 since we only need 2 phases
sublist(S,L) :-
    append(_,L2,L),
    append(S,_,L2).

% breadth-first helper
list3([]).
list3([_|T]) :-
    list3(T).

% sail/2, directly sail
sail(PlaceTime1, PlaceTime2) :-
    timetable(Route),
    sublist([PlaceTime1,PlaceTime2], Route).
    
% time difference
hour(H) :-
    H >= 0,
    H =< 24.
minute(MM) :-
    MM >= 0,
    MM =< 60.
time_diff(HH1:MM1, HH2:MM2, D) :-
    hour(HH1),
    hour(HH2),
    minute(MM1),
    minute(MM2),
    D is (HH2-HH1)*60 + MM2-MM1.

% before/2
before(Time1,Time2) :-
    time_diff(Time1,Time2,D),
    D >= 0.
    
% textbook - idea
% main
% but still have problem of instantiation
schedule33(Current, Destination, Plan) :-
    list3(Plan),
    plan33(Current, Destination, Plan).
% base case
plan33(Destination, Destination, []).
% recursive case
plan33(Place at Time, Destination, [depart(Place,Time), arrive(NewPlace,NewTime)|Plan]) :-
    sail(Place at Time, NewPlace at NewTime),
    before(Time,NewTime),
    plan33(NewPlace at NewTime, Destination, Plan).
plan33(Place at Time, Destination, [stay(Place,Time,NewTime)|Plan]) :-
    sail(Place at NewTime, _),
    before(Time,NewTime),
    plan33(Place at NewTime, Destination, Plan).

% textbook - answer
% difference?
% but do not have problem of instantiation when using the same helpers, why???
schedule333(Start, Destination, [depart(Start),arrive(Next)|Rest]) :-
    list3(Rest),
    sail(Start,Next),
    rest_schedule(Next,Destination,Rest).
rest_schedule(Place,Place,[]).
rest_schedule(CurrentPlace,Destination,[arrive(Next)|Rest]) :-
    sail(CurrentPlace,Next),
    rest_schedule(Next,Destination,Rest).
rest_schedule(Place at Time1, Destination,[stay(Place,Time1,Time2)|Rest]) :-
    sail(Place at Time2,_),
    before(Time1,Time2),
    schedule(Place at Time2,Destination,Rest).

% Terminals Questions
% statistics(runtime,_), sail(riva at Start,_), before(17:00,Start), 
% schedule333(riva at Start, riva at End, Plan), member(arrive(malcesine at _), Plan), 
% statistics(runtime,[_,RunTime]).

Question terminal is shown as below:

?- schedule333(riva at 9:10,malcesine at FinalTime, Plan).
FinalTime = 10:15,
Plan = [depart riva at 9:10, arrive torbole at 9:25, arrive limone at 9:55, arrive malcesine at 10:15]
FinalTime = 15:57,
Plan = [depart riva at 9:10, arrive torbole at 9:25, arrive limone at 9:55, arrive malcesine at 10:15, stay(malcesine, 10:15, 15:57)]
...

?- schedule333(campione at Start, campione at End, Plan), member(stay(riva,T1,T2),Plan), time_diff(T1,T2,D), D>=45.
D = 50,
End = 16:13,
Plan = [depart campione at 12:25, arrive malcesine at 13:12, arrive limone at 13:34, arrive riva at 14:10, stay(riva, 14:10, 15:0), depart riva at 15:0 and arrive limone at 15:36, depart limone at 15:36 and arrive malcesine at 15:57, depart malcesine at 15:57 and arrive campione at 16:13],
Start = 12:25,
T1 = 14:10,
T2 = 15:0

4. Cryptarithmetic Problems

The fourth example is trying to solve a cryptarithmetic problems (as below), we can find that prolog is very easy to find an answer via AI/computer:

  1. building the database
  2. building some actions and helpers
  3. run

d62836592a22d36267947655dac1727

Program code is shown as below:

% primitive
cal1([X1,X2,X3,X4,X5,X6],[Y1,Y2,Y3,Y4,Y5,Y6],[Z1,Z2,Z3,Z4,Z5,Z6]) :-
    X = X1*100000+X2*10000+X3*1000+X4*100+X5*10+X6,
    Y = Y1*100000+Y2*10000+Y3*1000+Y4*100+Y5*10+Y6,
    Z = Z1*100000+Z2*10000+Z3*1000+Z4*100+Z5*10+Z6,
    Z =:= X + Y.

% improved
cal2(L1,L2,L3) :-
    list_number(L1,N1),
    list_number(L2,N2),
    list_number(L3,N3),
    N3 =:= N1 + N2.

% same digits
assign1([]).
assign1([H|T]) :-
    % built-in predicate
    select(H,[0,1,2,3,4,5,6,7,8,9],_),
    assign1(T).

% cannot be same digits
assign2(_,[]).
assign2(L,[H|T]) :-
    select(H,L,L1),
    assign2(L1,T).

% transfering list to number
list_number(List,Number) :-
    length(List,Length),
    list_number_helper(List,Formula,Length),
    Number is Formula.
% helper
list_number_helper([],0,_).
list_number_helper([H|T],F,P) :-
    % 1. when giving number at outside, base case should be uninstantiated
    % list_number_helper([1,3,2],F,3)
    % list_number_helper([],0,_).
    % here, **3** and **_**
    % 2. when obtaining number at outside, base case should be instantiated
    % here, **F** and **0**
    P1 = P-1,
    F = H*10**P1 + F1,
    list_number_helper(T,F1,P1).

run(L1,L2,L3,Alphabets) :-
    assign2([0,1,2,3,4,5,6,7,8,9],Alphabets),
    cal2(L1,L2,L3).

From this exercise, we can knowing that:

  1. when giving number at outside, base case should be uninstantiated
  2. when obtaining number at outside, base case should be instantiated

Question terminal is shown as below:

?- run([D,O,N,A,L,D],[G,E,R,A,L,D],[R,O,B,E,R,T],[D,O,N,A,L,G,E,R,B,T]).
A = 4,
B = 3,
D = 5,
E = 9,
G = 1,
L = 8,
N = 6,
O = 2,
R = 7,
T = 0

Upadtes

  1. 于2021年7月14日1:37,完成对4.1-4.4的更新。

Acknowledgements

  1. Reference from the book Prolog Programming for Artificial Intelligence: Fourth Edition.
  2. Provided web system from SWISH: Sean's note for Prolog

Q.E.D.


立志做一个有趣的碳水化合物