%% twoarmsplan.lp -- Chapter 9, Section 9.4
%% Last Modified: 2/6/14
%% Planner for blocks world domain with two robotic arms that can
%% act concurrently.
block(b0).
block(b1).
block(b2).
block(b3).
block(b4).
block(b5).
block(b6).
block(b7).
location(X) :- block(X).
location(t).
%% Fluents %%
fluent(inertial, on(B,L)) :- block(B), location(L).
fluent(defined, above(B,L)) :- block(B), location(L).
%% Actions %%
%% "Put block B on location L" is a possible action in our
%% domain provided we don't try to put a block onto itself.
action(put(B,L)) :- block(B), location(L),
B != L.
#const n = 5.
step(0..n).
%% Laws %%
%% Putting block B on location L at step I
%% causes B to be on L at step I+1:
%% put(B,L) causes on(B,L)
holds(on(B,L),I+1) :- occurs(put(B,L),I),
I < n.
%% A block cannot be in two locations at once:
%% -on(B,L2) if on(B,L1), L1 != L2
-holds(on(B,L2),I) :- holds(on(B,L1),I),
location(L2),
L1 != L2.
%% Only one block can be set directly on top of another:
%% -on(B2,B) if on(B1,B), B1 != B2
-holds(on(B2,B),I) :- holds(on(B1,B),I),
block(B),
block(B2),
B1 != B2.
%% B is above L if it is directly on top of it or on top of
%% another block that is above L:
%% above(B,L) if on (B,L)
%% above(B,L) if on(B,B1), above(B1,L)
holds(above(B2,B1),I) :- holds(on(B2,B1),I).
holds(above(B2,B1),I) :- holds(on(B2,B),I),
holds(above(B,B1),I).
%% It is impossible to move an occupied block:
%% impossible put(B,L) if on (B1,B)
-occurs(put(B,L),I) :- location(L),
holds(on(B1,B),I).
%% !! This old constraint was not needed -- overspecification
%% It is impossible to move a block onto an occupied block:
%% impossible put(B1,B) if on(B2,B).
%-occurs(put(B1,B),I) :- block(B1), block(B),
% holds(on(B2,B),I).
%% !! New restriction for concurrency
%% Actions that put B1 on B2 and simultaneously move B2 are impossible:
%% impossible put(B1,L), put(B2,B2)
-occurs(put(B1,L),I) | -occurs(put(B2,B1),I) :-
step(I),
action(put(B1,L)),
action(put(B2,B1)).
%% CWA for Defined Fluents
-holds(F,I) :- fluent(defined,F), step(I),
not holds(F,I).
%% General Inertia Axiom
holds(F,I+1) :- fluent(inertial,F),
holds(F,I),
not -holds(F,I+1),
I < n.
-holds(F,I+1) :- fluent(inertial,F),
-holds(F,I),
not holds(F,I+1),
I < n.
%% CWA for Actions
-occurs(A,I) :- action(A), step(I),
not occurs(A,I).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Simple Concurrent Planning Module
success :- goal(I),
I <= n.
:- not success.
%% The only change from the serial version is the number of actions
%% allowed to occur concurrently -- 2 in this case:
1 {occurs(Action,I): action(Action)} 2 :- step(I),
not goal(I),
I < n.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Initial Situation
%% Change at will:
%% holds(on(B,L),I): a block B is on location L at step I.
holds(on(b0,t),0).
holds(on(b3,b0),0).
holds(on(b2,b3),0).
holds(on(b1,t),0).
holds(on(b4,b1),0).
holds(on(b5,t),0).
holds(on(b6,b5),0).
holds(on(b7,b6),0).
%% If block B is not known to be on location L at step 0,
%% then we assume it is not.
-holds(on(B,L),0) :- block(B), location(L),
not holds(on(B,L),0).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Specific goal.
%% Change at will:
goal(I) :-
holds(on(b4,t),I), holds(on(b6,t),I), holds(on(b1,t),I),
holds(on(b3,b4),I), holds(on(b7,b3),I), holds(on(b2,b6),I),
holds(on(b0,b1),I), holds(on(b5,b0),I).
#show occurs/2.