471 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
| /*
 | |
| 
 | |
|     Author:        Bart Demoen, Phuong-Lan Nguyen
 | |
|     E-mail:        Bart.Demoen@cs.kuleuven.be, nguyen@uco.fr
 | |
|     WWW:           http://www.swi-prolog.org
 | |
|     Copyright (C): 2006, K.U. Leuven
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or
 | |
|     modify it under the terms of the GNU General Public License
 | |
|     as published by the Free Software Foundation; either version 2
 | |
|     of the License, or (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public
 | |
|     License along with this library; if not, write to the Free Software
 | |
|     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
|     
 | |
|     As a special exception, if you link this library with other files,
 | |
|     compiled with a Free Software compiler, to produce an executable, this
 | |
|     library does not by itself cause the resulting executable to be covered
 | |
|     by the GNU General Public License. This exception does not however
 | |
|     invalidate any other reasons why the executable file might be covered by
 | |
|     the GNU General Public License.
 | |
| */
 | |
| 
 | |
| 
 | |
| /* What is this module for ... see bottom of the file */
 | |
| 
 | |
| :- module(actionrules,[op(1200,xfx,=>),
 | |
| 		       op(1200,xfx,?=>),
 | |
| 		       op(1000,xfy,:::),
 | |
| 		       op(900,xfy,<=),
 | |
| 		       post/1,
 | |
| 		       post_event/2,
 | |
| 		       post_event_df/2,
 | |
| 		       post_event_df/3,
 | |
| 		       register_event/2
 | |
| 		       ]).
 | |
| 
 | |
| :- use_module(library(lists)).
 | |
| 
 | |
| :- dynamic ar_term/2, extra_ar_term/2.
 | |
| 
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| %  the built-ins and the preds needed in the transformation    %
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| 
 | |
| register_event(event(X,_),G) :- add_attr(X,'$$event',G).
 | |
| register_event(ins(X),G) :- add_attr(X,'$$ins',G).
 | |
| register_event(generated,_).    % ignore
 | |
| 
 | |
| add_attr(X,Mod,A) :-
 | |
| 	(get_attr(X,Mod,Old) ->
 | |
| 	    New = [A|Old]
 | |
| 	;
 | |
| 	    New = [A]
 | |
| 	),
 | |
| 	put_attr(X,Mod,New).
 | |
| 
 | |
| post(event(X,Mes)) :- !,
 | |
| 	(get_attr(X,'$$event',Gs) ->
 | |
| 	    activate_agents_rev(Gs,Mes)
 | |
| 	;
 | |
| 	    (var(X) ->
 | |
| 		true
 | |
| 	    ;
 | |
| 		throw(actionrule(event/2,illegalfirstargument))
 | |
| 	    )
 | |
| 	).
 | |
| post(ins(X)) :- !,
 | |
| 	(get_attr(X,'$$ins',Gs) ->
 | |
| 	    call_list_rev(Gs)
 | |
| 	;
 | |
| 	    (var(X) ->
 | |
| 		true
 | |
| 	    ;
 | |
| 		throw(actionrule(ins/1,illegalfirstargument))
 | |
| 	    )
 | |
| 	).
 | |
| post(Event) :-
 | |
| 	throw(actionrule(Event,illegalpost)).
 | |
| 
 | |
| post_event(X,Mes) :-
 | |
| 	get_attr(X,'$$event',Gs), !, activate_agents_rev(Gs,Mes).
 | |
| post_event(X,_) :-
 | |
| 	(var(X) ->
 | |
| 	    true
 | |
| 	;
 | |
| 	    throw(actionrule(post_event/2,illegalfirstargument))
 | |
| 	).
 | |
| 	
 | |
| post_event_df(X,Mes) :-
 | |
| 	get_attr(X,'$$event',Gs), !, activate_agents1(Gs,Mes).
 | |
| post_event_df(_,_).
 | |
| 
 | |
| post_event_df(X,Alive,Mes) :-
 | |
| 	get_attr(X,'$$event',Gs), !, activate_agents(Gs,Alive,Mes).
 | |
| post_event_df(_,_,_).
 | |
| 
 | |
| '$$ins':attr_unify_hook(AttrX,Y) :-
 | |
| 	(var(Y) ->
 | |
| 	    (get_attr(Y,'$$ins',AttrY) ->
 | |
| 		append(AttrX,AttrY,NewAttr)
 | |
| 	    ;
 | |
| 		NewAttr = AttrX
 | |
| 	    ),
 | |
| 	    put_attr(Y,ins,NewAttr)
 | |
| 	;
 | |
| 	    true
 | |
| 	),
 | |
| 	call_list_rev(AttrX).
 | |
| 
 | |
| '$$event':attr_unify_hook(_,_).
 | |
| 
 | |
| call_list_rev(Goals) :-
 | |
| 	reverse(Goals,Gs),
 | |
| 	call_list(Gs).
 | |
| 
 | |
| call_list([]).
 | |
| call_list([G|Gs]) :-
 | |
| 	call(G),
 | |
| 	call_list(Gs).
 | |
| 
 | |
| activate_agents_rev(Goals,M) :-
 | |
| 	reverse(Goals,Gs),
 | |
| 	activate_agents(Gs,M).
 | |
| 
 | |
| activate_agents([],_).
 | |
| activate_agents([G|Gs],Mes) :-
 | |
| 	G =.. [N,_|R],
 | |
| 	NewG =.. [N,Mes|R],
 | |
| 	call(NewG),
 | |
| 	activate_agents(Gs,Mes).
 | |
| 
 | |
| activate_agents([],_,_).
 | |
| activate_agents([G|Gs],Alive,Mes) :-
 | |
| 	(var(Alive) ->
 | |
| 	    G =.. [N,_|R],
 | |
| 	    NewG =.. [N,Mes|R],
 | |
| 	    call(NewG),
 | |
| 	    activate_agents(Gs,Alive,Mes)
 | |
| 	;
 | |
| 	    true
 | |
| 	).
 | |
| 
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| % ar_translate and helper predicates %
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| 
 | |
| ars2p(ARs,Det,Head,Program,Errors,TailProgram,TailErrors) :-
 | |
| 	copyskel(Head,Skel),
 | |
| 	cleanheads(ARs,NewARs,Skel),
 | |
| 	Skel =.. [N|Args],
 | |
| 	makeagentname(N,AgentName),
 | |
| 	NewSkel =.. [AgentName,Mes,Alive|Args],
 | |
| 	findmess(NewARs,Mes),
 | |
| 	genfirstclause(NewARs,Det,NewSkel,Skel,Program,Errors,TailProgram1,TailErrors1),
 | |
| 	gensecondclause(NewARs,Det,NewSkel,Alive,TailProgram1,TailErrors1,TailProgram,TailErrors).
 | |
| 
 | |
| genfirstclause(NewARs,Det,NewSkel,Skel,Program,Errors,TailProgram,TailErrors) :-
 | |
| 	Clause = (Skel :- (Closure = NewSkel), Body),
 | |
| 	makefirstbody(NewARs,Det,Closure,Body,Errors,TailErrors),
 | |
| 	Program = [Clause | TailProgram].
 | |
| 
 | |
| 
 | |
| build_conditional(det, Guard, B, (Guard -> B)).
 | |
| build_conditional(nondet, Guard, B, (Guard, B)).
 | |
| 
 | |
| makefirstbody([ar(Head,Guard,Events,B)|R],Det,Closure,Bodys,Errors,TailErrors) :-
 | |
| 	(Events == [] ->
 | |
| 	    build_conditional(Det, Guard, B, Body),
 | |
| 	    Errors = Errors1
 | |
| 	;
 | |
| 	    check_events(Events,Head,Errors,Errors1),
 | |
| 	    mkregistergoals(Events,Register,Closure),
 | |
| 	    (member(generated,Events) ->
 | |
| 	        build_conditional(Det, Guard, (Register,B), Body)
 | |
| 	    ;
 | |
| 	        build_conditional(Det, Guard, Register, Body)
 | |
| 	    )
 | |
| 	),
 | |
| 	(R == [] ->
 | |
| 	    Bodys = Body,
 | |
| 	    Errors1 = TailErrors
 | |
| 	;
 | |
| 	    Bodys = (Body ; MoreBody),
 | |
| 	    makefirstbody(R,Det,Closure,MoreBody,Errors1,TailErrors)
 | |
| 	).
 | |
| 
 | |
| gensecondclause(NewARs,Det,NewSkel,Alive,Program,Errors,TailProgram,Errors) :-
 | |
| 	Clause = (NewSkel :- (var(Alive) -> Body ; true)),
 | |
|         makesecondbody(NewARs,Det,NewSkel,Body,Alive),
 | |
| 	Program = [Clause | TailProgram].
 | |
| 
 | |
| makesecondbody([ar(_,Guard,Events,B)|R],Det,NewSkel,Bodys,Alive) :-
 | |
| 	(Events == [] ->
 | |
| 	    build_conditional(Det, Guard, (Alive = no, B), Body)
 | |
| 	;
 | |
| 	    build_conditional(Det, Guard, B, Body)
 | |
| 	),
 | |
| 	(R == [] ->
 | |
| 	    Bodys = Body
 | |
| 	;
 | |
| 	    Bodys = (Body ; MoreBody),
 | |
| 	    makesecondbody(R,Det,NewSkel,MoreBody,Alive)
 | |
| 	).
 | |
| 
 | |
| check_events([],_,E,E).
 | |
| check_events([Event|R],S,E,TailE) :-
 | |
| 	(nonvar(Event), okevent(Event) ->
 | |
| 	    E = E1
 | |
| 	;
 | |
| 	    E = [illegalevent(Event,S)|E1]
 | |
| 	),
 | |
| 	check_events(R,S,E1,TailE).
 | |
| 
 | |
| okevent(ins(X)) :- !, var(X).
 | |
| okevent(event(X,M)) :- !, var(X), var(M).
 | |
| okevent(generated).
 | |
| 
 | |
| findmess([],_).
 | |
| findmess([ar(_,_,Events,_)|R],Mes) :-
 | |
| 	findmess2(Events,Mes),
 | |
| 	findmess(R,Mes).
 | |
| 
 | |
| findmess2([],_).
 | |
| findmess2([A|R],Mes) :-
 | |
| 	(A = event(_,Mes) ->
 | |
| 	    true
 | |
| 	;
 | |
| 	    true
 | |
| 	),
 | |
| 	findmess2(R,Mes).
 | |
| 	
 | |
| copyskel(T1,T2) :-
 | |
| 	functor(T1,N,A),
 | |
| 	functor(T2,N,A).
 | |
| 
 | |
| cleanheads([],[],_).
 | |
| cleanheads([ar(Head,Conds,Events,Body)|R],[ar(NewHead,NewConds,Events,Body)|S],Skel) :-
 | |
| 	makenewhead(Head,NewHead,Unies),
 | |
| 	Skel = NewHead,
 | |
| 	append(Unies,Conds,LNewConds),
 | |
|         conds_to_goals(LNewConds, NewConds0),
 | |
|         removetrue(NewConds0, NewConds),
 | |
| 	cleanheads(R,S,Skel).
 | |
| 
 | |
| conds_to_goals([], true) :- !.
 | |
| conds_to_goals(C.LNewConds, (C,NewConds0)) :- !,
 | |
|         conds_to_goals(LNewConds, NewConds0).
 | |
| conds_to_goals(C,C).
 | |
| 
 | |
| makenewhead(Head,NewHead,Unies) :-
 | |
| 	Head =.. [_|Args],
 | |
| 	functor(Head,N,A),
 | |
| 	functor(NewHead,N,A),
 | |
| 	NewHead =.. [_|NewArgs],
 | |
| 	makeunies(Args,NewArgs,Unies).
 | |
| 
 | |
| makeunies([],_,[]).
 | |
| makeunies([X|R],[Y|S],Us) :-
 | |
| 	(var(X) ->
 | |
| 	    X = Y,
 | |
| 	    Us = Us2
 | |
| 	;
 | |
| 	    Us = [X=Y|Us2]  % this should be matching instead of unification
 | |
| 	),
 | |
| 	makeunies(R,S,Us2).
 | |
| 
 | |
| 
 | |
| get_arinfo(AR,ARInfo,Head) :-
 | |
| 	AR = (Something => Body),
 | |
| 	(Something = (Head,Rest) ->
 | |
| 	    findcondevents(Rest,Conds,Events)
 | |
| 	;
 | |
| 	    Something = Head, Conds = true, Events = []
 | |
| 	),
 | |
| 	ARInfo = ar(Head,Conds,Events,Body).
 | |
| get_arinfo(AR,ARInfo,Head) :-
 | |
| 	AR = (Something ?=> Body),
 | |
| 	(Something = (Head,Rest) ->
 | |
| 	    findcondevents(Rest,Conds,Events)
 | |
| 	;
 | |
| 	    Something = Head, Conds = true, Events = []
 | |
| 	),
 | |
| 	ARInfo = ar(Head,Conds,Events,Body).
 | |
| get_arinfo(AR,ARInfo,Head) :-
 | |
| 	AR = (Head :- Rest ::: Body),
 | |
|         Conds = Rest, Events = [],
 | |
| 	ARInfo = ar(Head,Conds,Events,Body).
 | |
| 
 | |
| findcondevents((A,B),(A,As),Ts) :- !,
 | |
| 	findcondevents(B,As,Ts).
 | |
| findcondevents({Trs},true,Ts) :- !,
 | |
| 	makeevents(Trs,Ts).
 | |
| findcondevents(A,A,[]).
 | |
| 
 | |
| makeevents((A,B),[A|R]) :- !, makeevents(B,R).
 | |
| makeevents(A,[A]).
 | |
| 
 | |
| samehead(A,B) :-
 | |
| 	functor(A,X,Y),
 | |
| 	functor(B,X,Y).
 | |
| 
 | |
| makeagentname(N,Out) :-
 | |
| 	name(N,NL),
 | |
| 	name('$$suspended_',A),
 | |
| 	append(A,NL,ANL),
 | |
| 	name(Out,ANL).
 | |
| 
 | |
| mkregistergoals([],true,_).
 | |
| mkregistergoals([X|R],Register,Skel) :-
 | |
| 	(X == generated ->
 | |
| 	    mkregistergoals(R,Register,Skel)
 | |
| 	;
 | |
| 	    Register = (register_event(X,Skel),S),
 | |
| 	    mkregistergoals(R,S,Skel)
 | |
| 	).
 | |
| 
 | |
| removetrue(true,true) :- !.
 | |
| removetrue((true,A),AA) :- !, removetrue(A,AA).
 | |
| removetrue((A,true),AA) :- !, removetrue(A,AA).
 | |
| removetrue((A,B),(AA,BB)) :- !, removetrue(A,AA), removetrue(B,BB).
 | |
| removetrue((A->B),(AA->BB)) :- !, removetrue(A,AA), removetrue(B,BB).
 | |
| removetrue((A;B),(AA;BB)) :- !, removetrue(A,AA), removetrue(B,BB).
 | |
| removetrue(X,X).
 | |
| 
 | |
| 
 | |
| ar_translate([],_,[],[]).
 | |
| ar_translate([AR|ARs],Module,Program,Errors) :-
 | |
| 	get_head(AR,ARHead),
 | |
| 	collect_ars_same_head(ARs,ARHead,ActionPredRest,RestARs),
 | |
| 	ars2p([AR|ActionPredRest],det,ARHead,Program,Errors,TailProgram,TailErrors),
 | |
|         extra_ars(AR, TailProgram, NTailProgram),
 | |
| 	ar_translate(RestARs,Module,NTailProgram,TailErrors).
 | |
| 
 | |
| nondet_ar_translate([],_,Program,Program,[]).
 | |
| nondet_ar_translate([AR|ARs],Module,Program,EndProgram,Errors) :-
 | |
| 	get_head(AR,ARHead),
 | |
| 	collect_ars_same_head(ARs,ARHead,ActionPredRest,RestARs),
 | |
| 	ars2p([AR|ActionPredRest],nondet,ARHead,Program,Errors,TailProgram,TailErrors),
 | |
| 	nondet_ar_translate(RestARs,Module,TailProgram, EndProgram,TailErrors).
 | |
| 
 | |
| collect_ars_same_head([],_,[],[]).
 | |
| collect_ars_same_head([AR1|ARs],Head,SameHeadARs,RestARs) :-
 | |
| 	get_head(AR1,Head1),
 | |
| 	(same_head(Head1,Head) ->
 | |
| 	    SameHeadARs = [AR1|SameHeadARsRest],
 | |
| 	    collect_ars_same_head(ARs,Head,SameHeadARsRest,RestARs)
 | |
| 	;
 | |
| 	    RestARs = [AR1|RestARsRest],
 | |
| 	    collect_ars_same_head(ARs,Head,SameHeadARs,RestARsRest)
 | |
| 	).
 | |
| 
 | |
| get_head(ar(Head,_Conds,_Events,_Body),Head).
 | |
| 
 | |
| same_head(T1,T2) :-
 | |
| 	functor(T1,N,A),
 | |
| 	functor(T2,N,A).
 | |
| 
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| 
 | |
| ar_expand(Term, []) :-
 | |
| 	Term = (_ => _), !,
 | |
| 	prolog_load_context(file,File),
 | |
| 	get_arinfo(Term,ARInfo,_),
 | |
| 	assert(ar_term(File,ARInfo)).
 | |
| ar_expand(Term, []) :-
 | |
| 	Term = (_ :- _ ::: _), !,
 | |
| 	prolog_load_context(file,File),
 | |
| 	get_arinfo(Term,ARInfo,_),
 | |
| 	assert(ar_term(File,ARInfo)).
 | |
| ar_expand(Term, []) :-
 | |
| 	Term = (_ ?=> _ ), !,
 | |
| 	prolog_load_context(file,File),
 | |
| 	get_arinfo(Term,ARInfo,_),
 | |
| 	assert(nondet_ar_term(File,ARInfo)).
 | |
| ar_expand(Term, []) :-
 | |
| 	Term = (Head :- Body ),
 | |
| 	prolog_load_context(file,File),
 | |
|         functor(Head, Na, Ar),
 | |
|         functor(Empty, Na, Ar),
 | |
|         ar_term(File,ar(Empty,_,_,_)), !,
 | |
| 	assert(extra_ar_term(File,ar(Head, Body))).
 | |
| ar_expand(Head, []) :-
 | |
| 	prolog_load_context(file,File),
 | |
|         functor(Head, Na, Ar),
 | |
|         functor(Empty, Na, Ar),
 | |
|         ar_term(File,ar(Empty,_,_,_)), !,
 | |
| 	assert(extra_ar_term(File,ar(Head, true))).
 | |
| 
 | |
| ar_expand(end_of_file, FinalProgram) :-
 | |
| 	prolog_load_context(file,File),
 | |
|         compile_ar(File, DetProgram),
 | |
|         compile_nondet_ar(File, FinalProgram, DetProgram),
 | |
| 	FinalProgram = [_|_].
 | |
| 
 | |
| compile_ar(File, FinalProgram) :-
 | |
| 	findall(T, retract(ar_term(File,T)), ARs),
 | |
| 	ARs \== [],
 | |
| 	prolog_load_context(module, Module),
 | |
| 	ar_translate(ARs, Module, FinalProgram, Errors),
 | |
| 	!, % just to make sure there are no choice points left
 | |
| 	% vsc: also, allow for nondet rules.
 | |
| 	(Errors == [] ->
 | |
| 	    true
 | |
| 	;
 | |
| 	    report_errors(Errors)
 | |
| 	).
 | |
| compile_ar(_File, []).
 | |
| 
 | |
| compile_nondet_ar(File, FinalProgram, StartProgram) :-
 | |
| 	findall(T, retract(nondet_ar_term(File,T)), ARs),
 | |
| 	ARs \== [],
 | |
| 	prolog_load_context(module, Module),
 | |
| 	nondet_ar_translate(ARs, Module, FinalProgram, StartProgram, Errors),
 | |
| 	!, % just to make sure there are no choice points left
 | |
| 	(Errors == [] ->
 | |
| 	    true
 | |
| 	;
 | |
| 	    report_errors(Errors)
 | |
| 	).
 | |
| compile_nondet_ar(_File, FinalProgram, FinalProgram).
 | |
| 
 | |
| 
 | |
| report_errors(Errors) :- throw(action_rule_error(Errors)). % for now
 | |
| 
 | |
| extra_ars(ar(Head,_,_,_), LF, L0) :-
 | |
|        functor(Head, N, A),
 | |
|        functor(Empty, N, A),
 | |
|        findall((Empty :- B), extra_ar_term(_,ar(Empty, B)), LF, L0).
 | |
| 
 | |
| 
 | |
| /*******************************
 | |
| *         MUST BE LAST!        *
 | |
| *******************************/
 | |
| 
 | |
| :- multifile user:term_expansion/2.
 | |
| :- dynamic   user:term_expansion/2.
 | |
| 
 | |
| user:term_expansion(In, Out) :-
 | |
| 	ar_expand(In, Out).
 | |
| 
 | |
| 
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| %  What this file is for .... %
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| 
 | |
| /*
 | |
| 
 | |
| Action Rules were defined and implemented first in the context of
 | |
| B-Prolog and the TOAM by Neng-Fa Zhou - see http://www.probp.com/
 | |
| 
 | |
| See http://www.cs.kuleuven.be/publicaties/rapporten/cw/CW456.abs.html
 | |
| for an explanation what this file is based on.
 | |
| 
 | |
| Use_module-ing this file will give you an implementation of Action Rules
 | |
| functionality related to the event patterns ins/1, generated/0 and
 | |
| event/2.
 | |
| 
 | |
| It is not a fast implementation in SWI-Prolog, because there isn't any
 | |
| low-level support.
 | |
| 
 | |
| If you need more functionality, please contact the authors.
 | |
| 
 | |
| */
 |