1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    2% FILE    : Interpreters/indigolog.pl
    3%
    4%       IndiGolog Top Level Executor (Version 5)
    5%
    6%  AUTHOR : Sebastian Sardina (prev. Hector Levesque & Maurice Pagnucco)
    7%  EMAIL  : ssardina@cs.toronto.edu
    8%  WWW    : www.cs.toronto.edu/~ssardina www.cs.toronto.edu/cogrobo
    9%  TYPE   : system independent code
   10%  TESTED : SWI Prolog 5.0.10 http://www.swi-prolog.org
   11%           ECLIPSE 5.4 http://www.icparc.ic.ac.uk/eclipse/
   12%
   13%    This file provides the implementation for the top-level part of 
   14%    the online IndiGolog executor. 
   15%
   16%   The main tool provided in this file is the following predicate:        
   17%
   18% -- indigolog(E):  E is an IndiGolog program
   19%
   20%           For more information on Golog and some of its variants, see:
   21%               http://www.cs.toronto.edu/~cogrobo/
   22%
   23%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   24%
   25%
   26%                             September, 2002
   27%
   28% This software was developed by the Cognitive Robotics Group under the
   29% direction of Hector Levesque and Ray Reiter.
   30%
   31%        Do not distribute without permission.
   32%        Include this notice in any copy made.
   33%
   34%
   35%         Copyright (c) 2002-2005 by The University of Toronto,
   36%                        Toronto, Ontario, Canada.
   37%
   38%                          All Rights Reserved
   39%
   40% Permission to use, copy, and modify, this software and its
   41% documentation for non-commercial research purpose is hereby granted
   42% without fee, provided that the above copyright notice appears in all
   43% copies and that both the copyright notice and this permission notice
   44% appear in supporting documentation, and that the name of The University
   45% of Toronto not be used in advertising or publicity pertaining to
   46% distribution of the software without specific, written prior
   47% permission.  The University of Toronto makes no representations about
   48% the suitability of this software for any purpose.  It is provided "as
   49% is" without express or implied warranty.
   50% THE UNIVERSITY OF TORONTO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
   51% SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   52% FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TORONTO BE LIABLE FOR ANY
   53% SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
   54% RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   55% CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   56% CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   57% 
   58%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   59%
   60%  This files provides:
   61%
   62% -- indigolog(+E)       
   63%       run IndiGolog program E in the main cycle
   64% -- now(-H)             
   65%       H is the current history
   66% -- pasthist(?H)        
   67%       H is a past situation w.r.t. the current one
   68% -- doingStep		  
   69%       the main cycle is computing a step
   70% -- exog_action_occurred(LExoAction) 
   71%	to report a list of exog. actions LExogAction to the top-level
   72%
   73% -- exists_pending_exog  
   74%       there are exogenous events pending to be dealt
   75% -- set_option(+O, +V)  
   76%       set option O to value V. Current options are:
   77%
   78%	+ wait_step 	number of seconds to wait between steps
   79%	+ debug_level 	level for debug messages
   80%	+ type_manager 	define the type of the environment manager (thread/signal)
   81%
   82% -- error(+M)            
   83%       an error has occurred with message M
   84% -- warn(+M)   
   85%       warn the user of event M
   86%
   87%
   88%
   89%  The following should be provided for this file:
   90%
   91% LANGUAGE CONSTRUCTS IMPLEMENTATION (transition system):
   92%
   93% -- trans(+P,+H,-P2,-H2) 
   94%       configuration (P,H) can perform a single step to configuration (P2,H2)
   95% -- final(+P,+H)        
   96%       configuration (P,H) is terminating
   97%
   98% FROM ENVIRONMENT MANAGER (eng_man.pl):
   99%
  100% -- execute_action(+A, +H, +T, -Id, -S)  
  101%	execute action A of type T at history H and resturn sens. 
  102%       	S is the sensing outcome, or "failed" if the execution failed
  103%		Id is the identification for the action from the EM
  104% -- exog_occurs(-L)
  105%	return a list L of exog. actions that have occurred (sync)
  106% -- initializeEM/0 
  107%	environment initialization
  108% -- finalizeEM/0  
  109%	environment finalization
  110% -- set_type_manager(+T)        
  111%       set the implementation type of the env manager
  112%
  113%
  114% FROM TEMPORAL PROJECTOR (evalxxx.pl):
  115%
  116% -- debug(+A, +H, -S)	    
  117%       debug routine
  118% -- pause_or_roll(+H1,-H2)  
  119%       check if the DB CAN roll forward  
  120% -- can_roll(+H1) 
  121%       check if the DB CAN roll forward
  122% -- must_roll(+H1) 
  123%       check if the DB MUST roll forward
  124% -- roll_DB(+H1) 
  125%       check if the DB MUST roll forward
  126% -- initializeDB/0
  127%       initialize projector
  128% -- finalizeDB/0
  129%       finalize projector
  130% -- handle_sensing(+A,+H,+Sr,-H2) 
  131%	change history H to H2 when action A is executed in history 
  132%	H with Sr as returning sensing value
  133% -- sensing(+A,-SL)	    : 
  134%       action A is a sensing action with possible sensing outcome list SL
  135% -- system_action(+A)      : 
  136%       action A is an action used by the system 
  137%       e.g., the projector may use action e(_,_) to store sensing outcomes
  138%
  139% FROM THE SPECIFIC DOMAIN OR APPLICATION:
  140%
  141% -- simulateSensing(+A)  
  142%       sensing outcome for action A is simulated
  143% -- type_prolog(+P)	 
  144%       name of prolog being used (ecl, swi, vanilla, etc)
  145%
  146% OTHERS TOOLS (PROLOG OR LIBRARIES):
  147%
  148% -- sleep(Sec)             : wait for Sec seconds
  149% -- turn_on_gc             : turns on the automatic garbage collector
  150% -- turn_off_gc            : turns off the automatic garbage collector
  151% -- garbage_collect        : perform garbage collection (now)
  152% -- report_message(+T, +M) : report message M of type T
  153% -- set_debug_level(+N)    : set debug level to N
  154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  155:- dynamic sensing/2,   	% There may be no sensing action
  156	indi_exog/1,		% Stores exogenous events not managed yet
  157	now/1,            	% Used to store the actual history
  158	rollednow/1,           	% Part of now/1 that was already rolled fwd
  159	wait_at_action/1, 	% Wait some seconds after each action
  160	doing_step/0,     	% A step is being calculated
  161	pause_step/0.     	% Pause the step being calculated
  162	
  163% Predicates that they have definitions here but they can defined elsewhere
  164:- multifile(set_option/1),	
  165   multifile(set_option/2),
  166   multifile(exog_action/1),	% Many modules can register exog. actions 
  167   multifile(system_action/1).  % Many modules can register system actions 
  168
  169
  170:- style_check(-discontiguous).  171% :- style_check(-singleton).
  172% :- style_check(-atom).
  173
  174
  175:- ensure_loaded(transfinal).  % Load the TRANS and FINAL definitions
  176	
  177	
  178	
  179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  180%    CONFIGURATION SECTION
  181%
  182% This tools allow the user to tune different global options
  183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  184% set_option/1/2 are used to define parameters the user can set
  185% set_option/1 is used for the help tool set_option/0
  186% set_option/2 is the actual definition of the parameter configuration
  187
  188set_option :-
  189	writeln('set_option(Option, V): 
  190		 sets Option to value V, where Options may be:'),
  191	nl,
  192	set_option(X),
  193	tab(1),
  194	writeln(X),
  195	fail.
  196set_option.
  197
  198% Set the wait-at-action to pause after the execution of each prim action
  199set_option('wait_step : pause V seconds after each prim. action execution.').
  200set_option(wait_step, N) :- wait_step(N).
  201
  202wait_step(S) :- 
  203	S==0,
  204	report_message(system(0), '** Wait-at-action disabled'),
  205	retractall(wait_at_action(_)).
  206wait_step(S) :- 
  207	number(S),
  208	report_message(system(0), ['** Wait-at-action enable to ',S, ' seconds.']), 
  209	retractall(wait_at_action(_)), 
  210	assert(wait_at_action(S)).
  211wait_step(_) :- 
  212	report_message(warning, 'Wait-at-action cannot be set!').
  213
  214
  215set_option('debug_level : set debug level to V.').
  216set_option(debug_level, N) 	:- 
  217	set_debug_level(N),
  218	report_message(system(0), ['** System debug level set to ',N]).
  219
  220
  221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  222%    SOME SYSTEM BUILT-IN EXOGENOUS ACTIONS
  223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  224
  225% BUILT-IN exogenous actions that will be mapped to system actions for the cycle
  226exog_action(debug).	% Show debugging information	
  227exog_action(halt).		% Terminate program execution by jumping to the empty program
  228exog_action(abort).		% Abort program execution by jumping to ?(false) program
  229exog_action(break).		% Pause the execution of the program
  230exog_action(reset).		% Reset agent execution from scratch
  231exog_action(start).		% Start the execution of the program
  232
  233exog_action(debug_exec).	% Show debugging information	
  234exog_action(halt_exec).		% Terminate program execution by jumping to the empty program
  235exog_action(abort_exec).		% Abort program execution by jumping to ?(false) program
  236exog_action(break_exec).	% Pause the execution of the program
  237exog_action(reset_exec).		% Reset agent execution from scratch
  238exog_action(start_exec).		% Start the execution of the program
  239
  240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  241%    MAIN LOOP
  242%
  243% The top level call is indigolog(E), where E is a program
  244% The history H is a list of actions (prim or exog), initially []
  245% Sensing reports are inserted as actions of the form e(fluent,value)
  246%
  247% indigo/2, indigo2/3, indigo3/3 implement the main architecture by 
  248%      defyining a 3-phase main cycle
  249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  250init :- 
  251%	set_option(debug_level,3),
  252	report_message(system(0),'Starting ENVIRONMENT MANAGER...'),
  253	initializeEM,    	  	% Initialization of environment
  254	report_message(system(0),'ENVIRONMENT MANAGER was started successfully.'),
  255	report_message(system(0),'Starting PROJECTOR...'),
  256	initializeDB,             	% Initialization of projector
  257	report_message(system(0),'PROJECTOR was started successfully.'),
  258	reset_indigolog_dbs.      	% Reset the DB wrt the controller
  259
  260fin  :- 
  261	report_message(system(0),'Finalizing PROJECTOR...'),
  262	finalizeDB,               	% Finalization of projector
  263	report_message(system(0),'PROJECTOR was finalized successfully.'),
  264	report_message(system(0),'Finalizing ENVIRONMENT MANAGER...'),
  265	finalizeEM,      		% Finalization of environment
  266	report_message(system(0),'ENVIRONMENT MANAGER was finalized successfully.').
  267
  268
  269% Clean all exogenous actions and set the initial now/1 situation 
  270reset_indigolog_dbs :- 
  271	retractall(doing_step),
  272	retractall(indi_exog(_)), 
  273	retractall(rollednow(_)),
  274	retractall(now(_)),
  275	update_now([]),
  276	assert(rollednow([])),
  277	assert((indi_exog(_) :- fail)),
  278	fail.
  279reset_indigolog_dbs.
  285indigolog :- indigolog(none).
  286indigolog(_) :-		% Used to require a program, now we start proc. main always (March 06)
  287	init,  !, 
  288	(proc(main, E) ->		% obtain main agent program
  289		report_message(system(0),'Starting to execute the main program'),
  290		indigo(E,[]), !
  291	;
  292		report_message(system(0),'No main program to execute')
  293	),
  294	report_message(system(0),'Program execution finished. Closing modules...'),
  295	fin, !,
  296	report_message(system(0),'Everything finished - HALTING TOP-LEVEL CONTROLLER').
  301indigo(E,H) :- 
  302	handle_rolling(H,H2), !,		% Must roll forward?
  303	handle_exog(H2,H3),   !, 		% Handle pending exog. events
  304	prepare_for_step,			% Prepare for step
  305	mayEvolve(E,H3,E4,H4,S), !,	% Compute next configuration evolution
  306	wrap_up_step,				% Finish step
  307	(S=trans -> indigo2(H3,E4,H4) ;
  308	 S=final -> report_message(program,  'Success.') ;
  309	 S=exog  -> (report_message(program, 'Restarting step.'), indigo(E,H3)) ; 
  310	 S=failed-> report_message(program,  'Program fails.') 
  311	).
  320indigo2(H,E,H)          :- 
  321	indigo(E,H).	% The case of Trans for tests
  322indigo2(H,E,[sim(_)|H]) :- !, 
  323	indigo(E,H).	% Drop simulated actions
  324indigo2(H,E,[wait|H])   :- !,	
  325	pause_or_roll(H,H1), 
  326	doWaitForExog(H1,H2),
  327	indigo(E,H2).
  328indigo2(_,E,[debug_exec|H]) :- !, 
  329	report_message(system(0), 'Request for DEBUGGING'),
  330	debug(debug, H, null),  !,
  331	delete(H,debug,H2),
  332	indigo(E,H2).
  333indigo2(_,_,[halt_exec|H]) :- !, 
  334	report_message(system(0), 'Request for TERMINATION of the program'),
  335	indigo([], H).
  336indigo2(_,_,[abort_exec|H]) :- !, 
  337	report_message(system(0), 'Request for ABORTION of the program'),
  338	indigo([?(false)], H).
  339indigo2(_,E,[break_exec|H]) :- !, 
  340	report_message(system(0), 'Request for PAUSE of the program'),
  341	writeln(E),
  342	break,		% BREAK POINT (CTRL+D to continue execution)
  343	delete(H,pause,H2),
  344	indigo(E,H2).
  345indigo2(_,_,[reset_exec|_]) :- !, 
  346	report_message(system(0), 'Request for RESETING agent execution'),
  347	finalizeDB,
  348	initializeDB,
  349	proc(main, E),		% obtain main agent program
  350	indigo(E,[]).		% restart main with empty history
  351indigo2(H,E,[stop_interrupts|H]) :- !, 
  352	indigo(E,[stop_interrupts|H]).
  353indigo2(H,E,[A|H]) :- 
  354	indixeq(A, H, H1), 
  355	indigo(E, H1).  % DOMAIN ACTION
  356
  357% This are special actions that if they are in the current history
  358% they are interpreted by the interpreter in a particular way
  359% This should be seen as meta-actions that deal with the interpreter itself
  360system_action(debug_exec).	% Special action to force debugging
  361system_action(halt_exec).	% Action to force clean termination
  362system_action(abort_exec).	% Action to force sudden nonclean termination
  363system_action(start_exec).	% Action to start execution
  364system_action(break_exec).	% Action to break the agent execution to top-level Prolog
  365system_action(reset_exec).	% Reset agent execution from scratch
  366	
  367% Wait continously until an exogenous action occurrs
  368doWaitForExog(H1,H2):- 	
  369        report_message(system(2), 'Waiting for exogenous action to happen'), 
  370        repeat, 
  371        handle_exog(H1,H2),
  372        (H2=H1 -> fail ; true).
  373
  374% Predicates to prepare everthing for the computation of the next
  375% single step. Up to now, we just disable the GC to speed up the execution
  376prepare_for_step :- turn_off_gc.              % Before computing a step
  377wrap_up_step     :- retractall(doing_step),   % After computing a step
  378		    turn_on_gc, 
  379		    garbage_collect.
  380
  381
  382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  383% mayEvolve(E1,H1,E2,H2,S): perform transition from (E1,S1) to (E2,H2) with
  384%                        result S:
  385%
  386%                            trans = (E1,H1) performs a step to (E2,H2)
  387%                            final = (E1,H1) is a terminating configuration
  388%                            exog  = an exogenous actions occurred
  389%                            failed= (E1,H1) is a dead-end configuration
  390%                            system= system action transition
  391%
  392% There are two different implementations:
  393%
  394% * for Prolog's providing event handling (e.g., ECLIPSE, SWI)
  395% * any vanilla Prolog 
  396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  397
  398% If the step is a system-action, then just propagate it
  399%mayEvolve(E1,[A|H1],E1,[A|H1], system):- type_action(A, system), !.
  400
  401mayEvolve(E1,H1,E2,H2,S):- 
  402	type_prolog(T) -> mayEvolve(E1,H1,E2,H2,S,T) ; 
  403        		  mayEvolve(E1,H1,E2,H2,S,van).
  404abortStep :-  
  405	type_prolog(T) -> abortStep(T) ; abortStep(van).
  406
  407
  408%%%%%%%%%%%%%%%%%%%%%%%%%%
  409% (1) - for Prologs with ISO exception handling. (e.g., ECLIPSE and SWI)
  410%
  411% Notice that if a catch/3 is left via an throw/1 call, all current
  412% computations and bindings are lost (e.g., the bindings on E1,H1,S,E2,H2)
  413%
  414mayEvolve(E1,H1,E2,H2,S,T):- (T=ecl ; T=swi),
  415	catch(  (assert(doing_step),	% Assert flag doing_step
  416                 (exists_pending_exog_event -> abortStep(T) ; true),
  417                 (final(E1,H1,T)       -> S=final ;
  418                  trans(E1,H1,E2,H2,T) -> S=trans ;
  419                                          S=failed),
  420                 retract(doing_step)	% Retract flag doing_step
  421%                 (repeat, \+ pause_step)
  422                ), exog_action, (retractall(doing_step), S=exog) ).
  423
  424% Abort mechanism for ECLIPSE: just throw exception
  425abortStep(ecl) :- throw(exog_action).  
  426
  427% Abort mechanism for SWI: throw exception to main thread only
  428% 	OBS: abortStep(swi) is running in the env. manager thread
  429%		so by the time throw(exog_action) is executed, it could
  430%		be the case that thread main already retracted doing_step/0
  431%		from the DB and that mayEvolve/6 is already finished. In that
  432%		case the event should not be raised
  433abortStep(swi) :- thread_signal(main, (doing_step -> throw(exog_action) ; true)).
  434
  435/* OBS: As it is, it is not working 100% because sometimes the execution
  436is aborted and the following message is written:
  437		ERROR: Unhandled exception: exog_action
  438		
  439		This happens because the "exog_action" event was rised
  440		outside the catch/3 clause!!!
  441*/
  442
  443
  444%%%%%%%%%%%%%%%%%%%%%%%%%%
  445% (2) - for "vanilla" Prolog
  446%
  447mayEvolve(E1,H1,E2,H2,S,van):- 
  448	final(E1,H1)       -> S=final ;
  449	trans(E1,H1,E2,H2) -> S=trans ;  S=failed.
  450
  451abortStep(van) :- true.  % No way of aborting a step in the vanilla version
  452
  453
  454
  455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  456% trans/5 and final/3 wrappers for the real trans/4 and final/3
  457%
  458% The last argument of trans/4 and final/3 is used to distinghuish
  459% trans and final under different plataforms: ECLPSE, SWI or vanilla Prolog
  460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  461
  462% ECLIPSE: execute trans/4 (final/2) and, then, grounds
  463% all remaining free variables using the provided fix_term/2
  464final(E,H,ecl)      :- mfinal(E,H), 
  465                       (fix_term((E,H)) -> true ; true).
  466trans(E,H,E1,H1,ecl):- mtrans(E,H,E1,H1), 
  467                       (fix_term((E1,H1)) -> true ; true).
  468
  469% SWI: final/3 and trans/5 just reduce to final/2 and trans/4
  470final(E,H,swi)      :- mfinal(E,H).
  471trans(E,H,E1,H1,swi):- mtrans(E,H,E1,H1).
  472
  473% vanilla Prolog: final/3 and trans/5 just reduce to final/2 and trans/4
  474final(E,H,van)      :- mfinal(E,H).
  475trans(E,H,E1,H1,van):- mtrans(E,H,E1,H1).
  476
  477
  478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  479%  EXECUTION OF ACTIONS
  480%
  481%  indixeq(+Act,+H,-H2) is called when action Act should be executed at
  482%    history H. H2 is the new history after the execution of Act in H
  483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  484
  485% type_action(Action, Type) : finds out the type of an action 
  486type_action(Act, sensing)    :- sensing(Act, _), !.
  487type_action(Act, system)     :- system_action(Act), !.
  488type_action(_, nonsensing).
  489
  490indixeq(Act, H, H2) :-    % EXECUTION OF SYSTEM ACTIONS: just add it to history
  491        type_action(Act, system), !,
  492        H2 = [Act|H],
  493        update_now(H2).
  494indixeq(Act, H, H2) :-    % EXECUTION OF SENSING ACTIONS
  495        type_action(Act, sensing), !,
  496        report_message(system(1), ['Sending sensing Action *',Act,'* for execution']),
  497        execute_action(Act, H, sensing, IdAct, S), !,
  498	(S=failed -> 
  499		report_message(error, ['Action *', Act, '* FAILED to execute at history: ',H]),
  500		H2 = [abort,failed(Act)|H],	% Request abortion of program
  501	        update_now(H2)
  502	;
  503                report_message(action,  
  504                	['Action *', (Act, IdAct),'* EXECUTED SUCCESSFULLY with sensing outcome: ', S]),
  505	        wait_if_neccessary,
  506		handle_sensing(Act, [Act|H], S, H2),  % ADD SENSING OUTCOME!
  507		update_now(H2)
  508	).
  509indixeq(Act, H, H2) :-         % EXECUTION OF NON-SENSING ACTIONS
  510        type_action(Act, nonsensing), !, 
  511        report_message(system(1), ['Sending nonsensing action *',Act,'* for execution']),
  512        execute_action(Act, H, nonsensing, IdAct, S), !,
  513	(S=failed -> 
  514		report_message(error, ['Action *', Act, '* could not be executed at history: ',H]),
  515		H2 = [abort,failed(Act)|H],
  516	        update_now(H2)
  517	;
  518                report_message(action, ['Action *',(Act, IdAct),'* COMPLETED SUCCESSFULLY']),
  519		wait_if_neccessary,
  520                H2 = [Act|H],
  521		update_now(H2)
  522	).
  523
  524% Simulated pause between execution of actions if requested by user
  525wait_if_neccessary :-
  526        wait_at_action(Sec), !,   % Wait Sec numbers of seconds
  527        report_message(system(2),['Waiting at step ',Sec,' seconds']), 
  528        sleep(Sec). 
  529wait_if_neccessary.
  530
  531% Updates the current history to H
  532update_now(H):- 
  533        retract(now(_)) -> assert(now(H)) ; assert(now(H)).
  534
  535action_failed(Action, H) :-
  536	report_message(error,['Action *', Action, '* could not be executed',
  537	                      ' at history: ',H]),
  538	halt.
  539
  540
  541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  542%  EXOGENOUS ACTIONS
  543%
  544%  Exogenous actions are stored in the local predicate indi_exog(Act)
  545%  until they are ready to be incorporated into the history
  546% History H2 is H1 with all pending exog actions placed at the front
  547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  548handle_exog(H1, H2) :- 
  549	save_exog,				% Collect on-demand exogenous actions
  550	exists_pending_exog_event,		% Any indi_exog/1 in the database?
  551		% 1 - Collect SYSTEM exogenous actions (e.g., debug)
  552	findall(A, (indi_exog(A), type_action(A, system)), LSysExog),
  553		% 2 - Collect NON-SYSTEM exogenous actions (e.g., domain actions)  
  554	findall(A, (indi_exog(A), \+ type_action(A, system)), LNormal),	
  555		% 3 - Append the lists to the current hitory (system list on front)
  556	append(LSysExog, LNormal, LTotal),
  557	append(LTotal, H1, H2), 
  558	update_now(H2),
  559		% 4 - Remove all indi_exog/1 clauses
  560	retractall(indi_exog(_)).
  561handle_exog(H1, H1). 	% No exogenous actions, keep same history
  562
  563
  564% Collect on-demand exogenous actions: reported  by exog_occurs/1 
  565save_exog :- exog_occurs(L) -> store_exog(L) ; true.
  566
  567store_exog([]).  
  568store_exog([A|L]) :- assertz(indi_exog(A)), store_exog(L).
  569
  570% Is there any pending exogenous event?
  571exists_pending_exog_event :- indi_exog(_).
  572
  573
  574% exog_action_occurred(L) : called to report the occurrence of a list L of 
  575% 				exogenous actions (called from env. manager)
  576% 
  577% First we add each exogenous event to the clause indi_exog/1 and
  578% in the end, if we are performing an evolution step, we abort the step.
  579exog_action_occurred([]) :- doing_step -> abortStep ; true.
  580exog_action_occurred([ExoAction|LExoAction]) :-
  581        assert(indi_exog(ExoAction)),   
  582        report_message(exogaction, ['Exog. Action *',ExoAction,'* occurred']),
  583	exog_action_occurred(LExoAction).
  584
  585
  586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  587% HANDLING OF ROLLING FORWARD
  588%
  589% handle_rolling/2: mandatory rolling forward
  590% pause_or_roll/2: optional rolling forward
  591%
  592% Based on the following tools provided by the evaluator used:
  593%
  594%	must_roll(H): we MUST roll at H
  595%	can_roll(H) : we COULD roll at H (if there is time)
  596%	roll_db(H1,H2): roll from H1 to H2
  597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  598handle_rolling(H1,H2) :- must_roll(H1), !, roll(H1, H2).
  599handle_rolling(H1,H1).
  600
  601pause_or_roll(H1,H2) :- can_roll(H1), !, roll(H1, H2).
  602pause_or_roll(H1,H1).
  603
  604roll(H1, H2) :-
  605        report_message(system(0),'Rolling down the river (progressing the database).......'), 
  606	roll_db(H1, H2), 
  607        report_message(system(0), 'done progressing the database!'), 
  608        report_message(system(3), ['New History: ', H2]), 
  609	update_now(H2), 			% Update the current history	
  610	retract(rollednow(HO)),			% Update the rollednow/1 predicate
  611	append(H1,HO,HN),			% rollednow(H): H is the full system history
  612	assert(rollednow(HN)),
  613	save_exog.	% Collect all exogenous actions
  614
  615	
  616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  617%  OTHER PREDICATES PROVIDED
  618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  619
  620% H is a past situation w.r.t. the actual situation (stored in clause now/1)
  621pasthist(H):- now(ActualH), before(H,ActualH).
  622
  623% Deal with an unknown configuration (P,H)
  624error(M):- 
  625        report_message(error, M), 
  626        report_message(error,'Execution will be aborted!'), abort.
  627
  628warn(M):- 
  629        report_message(warning, M).
  630
  631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  632% EOF: Interpreters/indigolog.pl
  633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%