% File: heuristics
% $Name:  $

%%%%%%%%%%%%%%%%%%%%%%%%%%%%  HEURISTICS  %%%%%%%%%%%%%%%%%%%%%%%%%


% In order to prune as early as possible any unsuccessful branches  
% of computation, several heuristics related to the domain are  
% also added to this module. Heuristics are "rules-of-thumb,"  
% knowledge about the domain that has been accumulated by  
% specialists and experts. This knowledge is here expressed in the  
% form of constraint rules.  
 
% H1 - Do not repeat actions already performed.  
 
:- action_of(A,R),  
   time(T1),  
   time(T2),  
   T1 != T2,  
   occurs(A,T1),  
   occurs(A,T2). 
  
    

% H3 - Do not do two different types of actions with the same effect.

:- time(T),
   time(T1),
   occurs(flip(Sw,S),T),
   controls(Sw,V),
   commands(CC,V,S),
   occurs(CC,T1).



% H4 - Don't pressurize nodes already pressurized.

:- time(T),
   link(N1,N2,V1),
   link(N1,N2,V2),
   V1 != V2,
   h(in_state(V1,open),T),
   h(in_state(V2,open),T),
   not stuck(V1,open),
   not stuck(V2,open),
   not h(in_state(V1,open),0),
   not h(in_state(V2,open),0).



% H5 - If circuitry is working properly, do not issue a computer command 
% to move a valve V to a state S1 at time T1, and later issue a computer
% command to move V to state S2 opposite to S1.

:- time(T1),
   time(T2),
   gt(T2,T1),
   commands(CC1,V,S1),
   occurs(CC1,T1),
   opposite_state(S1,S2),
   commands(CC2,V,S2),
   occurs(CC2,T2).



% H6 - Do not flip a switch to a state S and later to the opposite state.

:- time(T1),
   time(T2),
   gt(T2,T1),
   controls(Sw,V), 
   occurs(flip(Sw,S),T1),
   opposite_state(S,S1),
   occurs(flip(Sw,S1),T2).



% H7 - Do not do move a normally functioning valve V to a state S
% through a flipping action, and at a different time move V 
% to an opposite state S' by issuing a computer command.

:- time(T1),
   time(T2),
   T2 != T1,
   commands(CC,V,S1),
   occurs(CC,T1),
   opposite_state(S1,S2),
   controls(Sw,V), 
   occurs(flip(Sw,S2),T2).



% H8 - If a switch Sw controlling a valve V is in state S1
% different from the state S of V, do not flip Sw to S.

:- time(T),
   controls(Sw,V1),
   controls(Sw,V2),
   V1 != V2,
   h(in_state(V1,S1),T),
   h(in_state(V2,S1),T),
   state_of(S1,valve),
   occurs(flip(Sw,S1),T).



% H9 - A pair of valves controlled by the same computer command
% should not be moved to the state they are already in.

:- time(T),
   occurs(CC,T),
   commands(CC,V1,S),
   commands(CC,V2,S),
   h(in_state(V1,S),T),
   h(in_state(V2,S),T),
   V1 != V2.



    
% H11 - Do not flip switch Sw to gpc position at any time T unless 
% a computer command is issued for a valve controlled by Sw  
% at T+1.  
 
:- next(T,T1), 
   occurs(flip(Sw,gpc),T), 
   controls(Sw,V),
   not issued_commands(V,T1). 


% issued_commands(V,T) is true iff a computer command is   
%                     issued at time T to change the state 
%                     of valve V. 
                     
issued_commands(V,T) :- time(T),
                        commands(CC,V,S),  
                        occurs(CC,T). 

 
% H12 - Do not flip switch Sw to gpc position at time T1 and 
% perform another action on Sw at time T2 without issuing 
% a computer command between T1,T2. 
 
:- time(T1), 
   time(T2), 
   gt(T2,T1), 
   controls(Sw,V),
   state_of(S,v_switch),
   occurs(flip(Sw,gpc),T1), 
   occurs(flip(Sw,S),T2), 
   not command_between(Sw,T1,T2). 
    
 
% command_between(Sw,T1,T2) is true iff a computer command is  
%                          issued between times T1 and T2 to  
%                          move a valve controlled by switch Sw.     
 
command_between(Sw,T1,T2) :- time(T1), 
                             time(T), 
                             time(T2), 
                             lt(T1,T), 
                             lt(T,T2), 
                             controls(Sw,V), 
                             commands(CC,V,S),   
                             occurs(CC,T). 
 
% A normally functioning valve connecting nodes N1 and N2 should 
% not be open if N1 is not pressurized.

%:- time(T),
%   link(N1,N2,V),
%   not has_leak(V),
%   not stuck(V),
%   h(in_state(V,open),T),
%   tank_of(TK,R),
%   is_pressurized_by(N1,TK),
%   not h(pressurized_by(N1,TK),T).
 

% Node N belongs to the plumbing line which is pressurized by tank TK.

%is_pressurized_by(N,TK) :- time(T),
%                           link(N1,N,V),
%                           tank_of(TK,R),
%                           h(pressurized_by(N,TK),T).


%--------------------------------
% Above constraint was modified by Gelfond on 3/7/01 as follows:

% A normally functioning valve connecting nodes N1 and N2 should 
% not be open if N1 is not pressurized.

:- time(T),
   link(N1,N2,V),
   h(in_state(V,open),T),
   not h(pressurized(N1),T),
   not has_leak(V),
   not stuck(V),
   not h(in_state(V,open),0).	% Added by Gelfond 04/01/01
   
h(pressurized(N),T) :- time(T),
                       tank(TK),
                       node(N),
                       h(pressurized_by(N,TK),T).             

tank(TK) :- tank_of(TK,R).

node(N) :- link(N,N1,V).
node(N) :- link(N1,N,V).
   
%-------- end modification ----------
              

% H10 - Do not issue a computer command to a valve controlled by a 
% switch Sw when Sw is not on state GPC. 
 
:- time(T), 
   controls(Sw,V),
   commands(CC,V,S),
   occurs(CC,T), 
   not h(in_state(Sw,gpc),T). 

 
% H13 - Do not open a valve if a previous valve in the path is not open. 
 
:- time(T),  
   perf(in_state(V,open),T),
   prev(V1,V),
   not dummy_valve(V1), 
   not open_prev(V,T). 

:- time(T),
   perf(in_state(V,open),T),
   dummy_valve(V1),
   prev(V1,V),
   prev(V2,V1),
   not open_prev(V1,T).



 
% perf(in_state(V,open),T) is true iff an action to open valve V  
%                          is performed at time T. 
 
perf(in_state(V,open),T) :- time(T), 
                            controls(Sw,V), 
	                    occurs(flip(Sw,open),T). 
 
perf(in_state(V,open),T) :- time(T), 
                            commands(CC,V,open),                       
     		            occurs(CC,T).
  

% prev(V1,V2) is true iff valve V1 is located before valve V2 
%             in some path. 
 
prev(V1,V2) :- link(N1,N2,V1),  
               link(N2,N3,V2). 

 
% open_prev(V,T) is true iff there exists a valve previous to  
%                valve V in a path which is open at time T. 
 
open_prev(V,T) :- time(T), 
		  prev(V1,V), 
		  h(in_state(V1,open),T). 
 

