
         % A Prolog Interpreter for Concurrent, Temporal Golog


:- set_flag(print_depth,100).
:- nodbgcomp.
:- dynamic(proc/2).            % Compiler directives. Be sure   
:- set_flag(all_dynamic, on).  % that you load this file first! 

:- op(800, xfy, [&]).   % Conjunction 
:- op(850, xfy, [v]).   % Disjunction 
:- op(870, xfy, [=>]).  % Implication 
:- op(880,xfy, [<=>]).  % Equivalence 
:- op(950, xfy, [:]).   % Action sequence.
:- op(960, xfy, [#]).   % Nondeterministic action choice.

do(E1 : E2,S,S1) :- do(E1,S,S2), do(E2,S2,S1).
do(?(P),S,S) :- holds(P,S).
do(E1 # E2,S,S1) :- do(E1,S,S1) ; do(E2,S,S1).
do(if(P,E1,E2),S,S1) :- do(?(P) : E1 # ?(-P) : E2,S,S1).
do(star(E),S,S1) :- S1 = S ; do(E : star(E),S,S1).
do(while(P,E),S,S1):- do(star(?(P) : E) : ?(-P),S,S1).
do(pi(V,E),S,S1) :- sub(V,_,E,E1), do(E1,S,S1).
do(E,S,S1) :- proc(E,E1), do(E1,S,S1).
do(C,S,do(C,S)) :- concurrent_action(C), poss(C,S), start(S,T1),
                   time(C,T2), T1 =< T2.

% sub(Name,New,Term1,Term2): Term2 is Term1 with Name replaced by New. 

sub(X1,X2,T1,T2) :- var(T1), T2 = T1.
sub(X1,X2,T1,T2) :- not var(T1), T1 = X1, T2 = X2.
sub(X1,X2,T1,T2) :- not T1 = X1, T1 =..[F|L1], sub_list(X1,X2,L1,L2),
                    T2 =..[F|L2].
sub_list(X1,X2,[],[]).
sub_list(X1,X2,[T1|L1],[T2|L2]) :- sub(X1,X2,T1,T2), sub_list(X1,X2,L1,L2).

/* The holds predicate implements the revised Lloyd-Topor
   transformations on test conditions.  */


holds(P & Q,S) :- holds(P,S), holds(Q,S).
holds(P v Q,S) :- holds(P,S); holds(Q,S).
holds(P => Q,S) :- holds(-P v Q,S).
holds(P <=> Q,S) :- holds((P => Q) & (Q => P),S).
holds(-(-P),S) :- holds(P,S).
holds(-(P & Q),S) :- holds(-P v -Q,S).
holds(-(P v Q),S) :- holds(-P & -Q,S).
holds(-(P => Q),S) :- holds(-(-P v Q),S).
holds(-(P <=> Q),S) :- holds(-((P => Q) & (Q => P)),S).
holds(-all(V,P),S) :- holds(some(V,-P),S).
holds(-some(V,P),S) :- not holds(some(V,P),S).  /* Negation */
holds(-P,S) :- isAtom(P), not holds(P,S).     /* by failure */
holds(all(V,P),S) :- holds(-some(V,-P),S).
holds(some(V,P),S) :- sub(V,_,P,P1), holds(P1,S).

/* The following clause treats the holds predicate for non fluents, including
   Prolog system predicates. For this to work properly, the GOLOG programmer
   must provide, for all fluents, a clause giving the result of restoring
   situation arguments to situation-suppressed terms, for example:
         restoreSitArg(ontable(X),S,ontable(X,S)).             */

holds(A,S) :- restoreSitArg(A,S,F), F ;
              not restoreSitArg(A,S,F), isAtom(A), A.

isAtom(A) :- not (A = -W ; A = (W1 & W2) ; A = (W1 => W2) ;
    A = (W1 <=> W2) ; A = (W1 v W2) ; A = some(X,W) ; A = all(X,W)).

/* The time of a concurrent action is the time of its first simple
   action. This assumes that the concurrent action is coherent, so it
   is non-empty, and all its simple actions occur at the same time.  */

time([A | C],T) :- time(A,T).

% The start time of situation do(C,S) is the time of C. 

start(do(C,S),T) :- concurrent_action(C), time(C,T).

%  Restore suppressed situation arguments. 

restoreSitArg(start(T),S,start(S,T)).
restoreSitArg(poss(A),S,poss(A,S)).

%  Concurrent actions are Prolog lists. 

concurrent_action([]).    concurrent_action([A | R ]).

%  Coherent actions defined.  

coherent([A | R]) :- time(A,T), sameTime(R,T).
sameTime([],T).
sameTime([A | R],T) :- time(A,T), sameTime(R,T).
