% OOPS2 - A toy production system interpreter. It uses a forward chaining, % data driven, rule based approach for expert system development. % % Version 2, the simplest version without LEX, MEA, or conflict sets % % author Dennis Merritt % Copyright (c) Dennis Merritt, 1986 % fixed for SWI Prolog by GJN 12.2005 %%%%%%%%% To start program write main. or uncomment the last line in this file %%%%%%%%%%%%%%%%%%%%% :- write('********To start program write main.**********'). info(X):- jpl_datums_to_array(X,Q), jpl_new('miw2.Info',[Q],_). readF(File):- jpl_new('miw2.PlFileChooser',[],F), jpl_call(F,getFile,[],File). control(X,Buttons):- repeat, jpl_datums_to_array(Buttons,B), jpl_new('miw2.ControlForm',[X,B],F), jpl_call(F,getValue,[],V), change(V,Z), doit(Z), Z = exit. change(0,load). change(1,list). change(2,go). % 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 = main :- welcome, write_help. welcome:- info(['OOPS - A Toy Production System', 'This is an interpreter for files containing rules coded in the', 'OOPS format.']). write_help :- control('Commands:\n load - prompts for name of rules file enclose in single quotes\n list - lists working memory\n go - starts the inference\n exit - does what you\'d expect',['load','list','go']). % the supervisor, uses a repeat fail loop to read and process commands % from the user supervisor :- repeat, doit(X), X = exit. doit(X) :- do(X). % actions to take based on commands do(exit) :- !. do(go) :- initialize,go,!. do(load) :-load,!. do(list) :- lst,!. % lists all of working storage do(list(X)) :- lst(X),!. % lists all which match the pattern do(_) :- info(['invalid command!']),nl,write_help. % loads the rules (Prolog terms) into the Prolog database load :- readF(F), consult(F). % loads a rule file into interpreter work space % assert each of the initial conditions into working storage initialize :- initial_data(X), assert_list(X). % working storage is represented by database terms stored % under the key "fact" assert_list([]) :- !. assert_list([H|T]) :- assertz( fact(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 :- call(rule ID: LHS ==> RHS), try(LHS,RHS), info(['Rule fired ',ID]), !,go. go. % find the current conflict set. % conflict_set(CS) :- % bagof(rule ID: LHS ==> RHS, % [rule ID: LHS ==> RHS, match(LHS)],CS). % match the LHS against working storage, if it succeeds process the % actions from the RHS try(LHS,RHS) :- match(LHS), process(RHS,LHS),!. % recursively go through the LHS list, matching conditions against % working storage match([]) :- !. match([_:Prem|Rest]) :- !, (fact(Prem); test(Prem)), % a comparison test rather than a fact match(Rest). match([Prem|Rest]) :- (fact(Prem); % condition number not specified test(Prem)), match(Rest). % various tests allowed on the LHS test(not(X)) :- fact(X), !,fail. test(not(_)) :- !. test(X#Y) :- X=Y,!. test(X>Y) :- X>Y,!. test(X>=Y) :- X>=Y,!. test(X