% RETEFOOPS - forward chaining, frames, and Rete algorithm, also using % LEX and MEA to sort the conflict set. % % Copyright (c) Dennis Merritt, 1988 % operator definitions :-op(800,xfx,==>). % used to separate LHS and RHS of rule :-op(500,xfy,#). % used to separate attributes and values :-op(810,fx,rule). % used to define rule :-op(700,xfy,#). % used for unification instead of = :-op(700,xfy,\=). % not equal :-op(600,xfy,with). % used for frame instances in rules main :- welcome, supervisor. welcome :- write($ RETEFOOP - A Toy Production System$),nl,nl, write($This is an interpreter for files containing rules coded in the$),nl, write($FOOPS format.$),nl,nl, write($The => prompt accepts three commands:$),nl,nl, write($ load. - prompts for name of rules file$),nl, write($ enclose in single quotes$),nl, write($ compile. - compiles rules into a rete net$),nl, write($ displaynet. - displays the rete net$),nl, write($ list. - lists stuff$),nl, write($ list(X). - lists things which match X$),nl, write($ options. - allows setting of message levels$),nl, write($ go. - starts the inference$),nl, write($ exit. - does what you'd expect$),nl,nl. % the supervisor, uses a repeat fail loop to read and process commands % from the user supervisor :- repeat, write('=>'), read(X), doit(X), X = exit. doit(X) :- timer(T1), do(X), timer(T2), T is (T2 - T1) / 600, message(101,T),!. % actions to take based on commands do(exit) :- !. do(go) :- initialize, go, !. do(load) :-load,!. do(compile) :- compile,!. do(displaynet) :- display_net,!. do(list) :- lst,!. % lists all of working storage do(list(X)) :- lst(X),!. % lists all which match the pattern do(options) :- set_messtypes,!. do(_) :- message(102). % loads the rules (Prolog terms) into the Prolog database load :- write('Enter the file name in single quotes (ex. ''room.rkb''.): '), read(F), reconsult(F), % loads a rule file into interpreter work space rete_compile. % ** rete change ** compile :- rete_compile. % assert each of the initial conditions into working storage initialize :- message(120), abolish(memory,2), abolish(inst,3), setchron(1), delf(all), abolish(conflict_set,1), assert(conflict_set([])), assert(mea(no)), initial_data(X), assert_list(X), message(121), !. initialize :- message(103). % working storage is represented frame instances - frinsts and also % stored in a rete net assert_list([]) :- !. assert_list([H|T]) :- assert_ws(H), !,assert_list(T). % the main inference loop, find a rule and try it. if it fired, say so % and repeat the process. if not go back and try the next rule. when % no rules succeed, stop the inference. go :- conflict_set(CS), select_rule(CS,inst(ID,LHS,RHS)), message(104,ID), (process(ID,RHS,LHS); true), % action side might fail del_conflict_set(ID,LHS,RHS), !,go. go :- conflict_set([]), finished, !. % supplied in kb for what to do at end go :- message(119). del_conflict_set(N,TokenList,Action) :- conflict_set(CS), remove(inst(N,TokenList,Action),CS,CS2), message(105,N), retract( conflict_set(_) ), asserta( conflict_set(CS2) ). del_conflict_set(N,TokenList,Action) :- message(106,N). add_conflict_set(N,TokenList,Action) :- message(107,N), retract( conflict_set(CS) ), asserta( conflict_set([inst(N,TokenList,Action)|CS]) ). select_rule(CS,R) :- message(122,CS), mea_filter(0,CS,[],CSR), lex_sort(CSR,R). % sort the rest of the conflict set according to the lex strategy lex_sort(L,R) :- build_keys(L,LK), sort(LK,X), reverse(X,[K-R|_]). % build lists of time stamps for lex sort keys build_keys([],[]). build_keys([inst(N,TokenList,C)|T],[Key-inst(N,TokenList,C)|TR]) :- build_chlist(TokenList,ChL), sort(ChL,X), reverse(X,Key), build_keys(T,TR). % build a list of just the times of the various matched attributes % for use in rule selection build_chlist([],[]). build_chlist([_/Chron|T],[Chron|TC]) :- build_chlist(T,TC). % add the test for mea if appropriate that emphasizes the first attribute % selected. mea_filter(_,X,_,X) :- not mea(yes), !. mea_filter(_,[],X,X). mea_filter(Max,[inst(N,[A/T|Z],C)|X],Temp,ML) :- T < Max, !, mea_filter(Max,X,Temp,ML). mea_filter(Max,[inst(N,[A/T|Z],C)|X],Temp,ML) :- T = Max, !, mea_filter(Max,X,[inst(N,[A/T|Z],C)|Temp],ML). mea_filter(Max,[inst(N,[A/T|Z],C)|X],Temp,ML) :- T > Max, !, mea_filter(T,X,[inst(N,[A/T|Z],C)],ML). get_ws(Prem,Time) :- conv(Prem,Class,Name,ReqList), getf(Class,Name,ReqList,Time). assert_ws(Prem) :- message(109,Prem), conv(Prem,Class,Name,AList), addf(Class,Name,AList,TimeStamp), addrete(Class,Name,TimeStamp). update_ws(Prem) :- conv(Prem,Class,Name,UList), frinst(Class,Name,_,TS), uptrf(Class,Name,UList,TimeStamp), % note - does delrete in uptrf addrete(Class,Name,TimeStamp), !. update_ws(Prem) :- message(108,Prem). retract_ws(Prem/T) :- retract_ws(Prem). retract_ws(Prem) :- conv(Prem,Class,Name,UList), delrete(Class,Name,TimeStamp), delf(Class,Name,UList). conv(Class-Name with List, Class, Name, List). conv(Class-Name, Class, Name, []). % various tests allowed on the LHS test(not(X)) :- get_ws(X,_), !,fail. test(not(X)) :- !. test(X#Y) :- X=Y,!. test(X>Y) :- X>Y,!. test(X>=Y) :- X>=Y,!. test(X '), read(X), timer(T1), X, timer(T2), nl,nl, T is (T2 - T1) / 10, write(time-T). append([H|T], W, [H|Z]) :- append(T, W, Z). append([], W, W). member(X, [X|_]). member(X, [_|T]) :- member(X,T). reverse(L1,L2) :- revzap(L1,[],L2). revzap([X|L],L2,L3) :- revzap(L,[X|L2],L3). revzap([],L,L). % Message handling and messages message(N) :- message(N,''). message(N,Args) :- mess(N,break,Text), write(break),tab(1),write(N),write(': '),write(Text),write(Args),nl. % break. message(N,Args) :- mess(N,error,Text), write(error),tab(1),write(N),write(': '),write(Text),write(Args),nl, !, fail. message(N,Args) :- mess(N,Type,Text), mess_types(TT), member(Type,TT), write(Type),tab(1),write(N),write(': '),write(Text),write(Args),nl, !. message(_,_). mess_types([info,trace,warning,debug]). set_messtypes :- message(123,[info,warn,trace,error,debug]), mess_types(X), message(124,X), read(MT), retract( mess_types(_) ), asserta( mess_types(MT) ). mess(101,info , 'Time for command: '). % retefoops doit mess(102,error, 'Invalid Command'). % retefoops do mess(103,error, 'Initialization Error'). % retefoops initialize mess(104,trace, 'Rule Firing: '). % retefoops go mess(105,trace, 'Conflict Set Delete: '). % retefoops del_confli... mess(106,trace, 'Failed to CS Delete: '). % retefoops del_confli... mess(107,trace, 'Conflict Set Add: '). % retefoops add_confli... mess(108,error, 'Update Fails for: '). % retefoops update_ws mess(109,trace, 'Asserting: '). % retefoops add_ws mess(110,trace, 'Failing Action Part: '). % retefoops process mess(111,error, 'Retract Error, no: '). % retefoops take mess(112,debugx, 'Frame error looking for: '). % retefoops find_slot mess(113,error, 'Frame instance update error: '). % retefoops uptf mess(114,error, 'No frame to delete: '). % retefoops del_frame mess(115,error, 'No instance to delete: '). % retefoops delf mess(116,error, 'Unable to delete slot: '). % retefoops del_slot mess(117,error, 'Unable to delete facet: '). % retefoops del_facet mess(118,trace, 'Rule Fired: '). % retefoops process mess(119,error, 'Premature end to run: '). % retefoops go mess(120,info, 'Initializing'). % retefoops initialize mess(121,info, 'Initialization Complete'). % retefoops initialize mess(122,debugx, 'Conflict Set'). % retefoops select_rule mess(123,info, 'Legal Message Types: '). % retefoops set_message mess(124,info, 'Current Message Types: '). % retefoops set_message mess(201,info, 'Rule Rete Network Complete'). % retecomp rete_compil mess(202,info, 'Rule: '). % retecomp rete_comp mess(203,error, 'Rule Failed to Compile: '). % retecomp rete_comp