📄 retepred.pro
字号:
% rete - the predicates which implement the Rete pattern matching algorithm.
% It should be modified some day
% to use pointers to working memory in the memory predicates rather
% than the full tokens - this would save a lot of space.
% retecomp - compile rules into a rete network
:-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
rete_compile :-
abolish(root,3),
abolish(bi,4),
abolish(tes,4),
abolish(rul,3),
abolish(varg,1),
abolish(nid,1),
asserta(nid(0)),
rete_compil.
% display_net.
display_net :-
display_roots,nl,
display_bis,nl,
display_teses,nl,
display_ruls.
display_roots :-
root(N,A,B),
write( root(N,A,B) ),nl,
fail.
display_roots.
display_bis :-
bi(A,B,C,D),
write( bi(A) ),nl,
write_list([left|B]),
write_list([right|C]),
write(D),nl,nl,
fail.
display_bis.
display_teses :-
tes(A,B,C,D),
write( tes(A) ),nl,
write_list([left|B]),
write_list([right|C]),nl,
write(D),nl,nl,
fail.
display_teses.
display_ruls :-
rul(A,B,C),
write( rul(A) ),nl,
write_list([left|B]),
write_list([right|C]),nl,
fail.
display_ruls.
write_list([]).
write_list([H|T]) :-
write(H),nl,
wr_lis(T).
wr_lis([]).
wr_lis([H|T]) :-
tab(5),write(H),nl,
wr_lis(T).
% compile each rule into the rete net
rete_compil :-
rule N# LHS ==> RHS,
rete_comp(N,LHS,RHS),
fail.
rete_compil :-
message(201).
% compile an individual rule into the net
rete_comp(N,[H|T],RHS) :-
term(H,Hw),
check_root(RN,Hw,HList),
retcom(root(RN),[Hw/_],HList,T,N,RHS),
message(202,N), !.
rete_comp(N,_,_) :-
message(203,N).
% the main compile loop
% PNID - the id of the previous node
% OutTok - list of tokens from previous node
% PrevList - transfer list from previous node
% [H|T] - list of remaining clauses in rule
% N - The rule ID, for building the rule at the end
% RHS - the rhs of the rule for building the rule at the end
retcom(PNID,OutTok,PrevList,[],N,RHS) :-
build_rule(OutTok,PrevList,N,RHS),
update_node(PNID,PrevList,rule-N),
!.
retcom(PNID,PrevNode,PrevList,[H|T],N,RHS) :-
term(H,Hw),
check_root(RN,Hw,HList),
check_node(PrevNode,PrevList,[Hw/_],HList,NID,OutTok,NList),
update_node(PNID,PrevList,NID-l),
update_root(RN,HList,NID-r),
!,
retcom(NID,OutTok,NList,T,N,RHS).
retcom(PNID,PrevNode,PrevList,[H|T],N,RHS) :- %some kind of tester call
check_tnode(PrevNode,PrevList,[H/0],HList,NID,OutTok,NList),
update_node(PNID,PrevList,test-NID),
!,
retcom(test-NID,OutTok,NList,T,N,RHS).
term(Class-Name with List,Class-Name with List).
term(Class-Name, Class-Name with []).
check_root(NID,Term,[]) :-
not(root(_,Term,_)),
gen_nid(NID),
assertz( root(NID,Term,[]) ), !.
check_root(N,Term,List) :-
asserta(temp(Term)),
retract(temp(T1)),
root(N,Term,List),
root(N,T2,_),
comp_devar(T1,T2), !.
check_root(NID,Term,[]) :-
gen_nid(NID),
assertz( root(NID,Term,[]) ).
% if this node was already on the list do nothing, otherwise add it
% to the list
update_root(RN,HList,NID) :-
member(NID,HList), !.
update_root(RN,HList,NID) :-
retract( root(RN,H,HList) ),
asserta( root(RN,H,[NID|HList]) ).
update_node(root(RN),HList,NID) :-
update_root(RN,HList,NID), !.
update_node(X,PrevList,NID) :-
member(NID,PrevList), !.
update_node(test-N,PrevList,NID) :-
retract( tes(N,L,T,_) ),
asserta( tes(N,L,T,[NID|PrevList]) ), !.
update_node(PNID,PrevList,NID) :-
retract( bi(PNID,L,R,_) ),
asserta( bi(PNID,L,R,[NID|PrevList]) ).
% check to see if there is a node which already fits, otherwise
% create a new one
% PNode - token list from previous node
% PList - list of successor nodes from previous node
% H - new token being added
% HList - successor nodes from root for token H
% NID - returned ID of the node
% OutTok - returned tokenlist from the node
% NList - returned list of successor nodes from the node
% first case - there isn't a matching rule using Prolog's match, so
% build a new one
check_node(PNode,PList,H,HList,NID,OutTok,[]) :-
not (bi(_,PNode,H,_)),
append(PNode,H,OutTok),
gen_nid(NID),
assertz( bi(NID,PNode,H,[]) ),
!.
% second case - there was a matching rule using Prolog's match, so
% match again using generated constants instead of variables. If
% this matches then we have a match, otherwise we had a match
% where variables don't line up and its no good. (asserts and
% retracts allow different variables to have same information and
% prevent binding of variables in one from affecting the other)
check_node(PNode,PList,H,HList,NID,OutTok,NList) :-
append(PNode,H,OutTok),
asserta(temp(OutTok)),
retract(temp(Tot1)),
bi(NID,PNode,H,NList),
bi(NID,T2,T3,_),
append(T2,T3,Tot2),
comp_devar(Tot1,Tot2),
!.
% third case - the variables didn't line up from the second rule, so
% make a new node.
check_node(PNode,PList,H,HList,NID,OutTok,[]) :-
append(PNode,H,OutTok),
gen_nid(NID),
assertz( bi(NID,PNode,H,[]) ).
% check for test node - similar to check for regular node
check_tnode(PNode,PList,H,HList,NID,OutTok,[]) :-
not (tes(_,PNode,H,_)),
append(PNode,H,OutTok),
gen_nid(NID),
assertz( tes(NID,PNode,H,[]) ),
!.
% second case - there was a matching rule using Prolog's match, so
% match again using generated constants instead of variables. If
% this matches then we have a match, otherwise we had a match
% where variables don't line up and its no good. (asserts and
% retracts allow different variables to have same information and
% prevent binding of variables in one from affecting the other)
check_tnode(PNode,PList,H,HList,NID,OutTok,NList) :-
append(PNode,H,OutTok),
asserta(temp(OutTok)),
retract(temp(Tot1)),
tes(NID,PNode,H,NList),
tes(NID,T2,T3,_),
append(T2,T3,Tot2),
comp_devar(Tot1,Tot2),
!.
% third case - the variables didn't line up from the second rule, so
% make a new node.
check_tnode(PNode,PList,H,HList,NID,OutTok,[]) :-
append(PNode,H,OutTok),
gen_nid(NID),
assertz( tes(NID,PNode,H,[]) ).
build_rule(OutTok,PrevList,N,RHS) :-
assertz( rul(N,OutTok,RHS) ).
gen_nid(NID) :-
retract( nid(N) ),
NID is N+1,
asserta( nid(NID) ).
% the hard part, undo Prolog's pattern matching so variables match just
% variables and not constants. de-var replaces all the variables with
% generated constants - this ensures only variables will match variables.
comp_devar(T1,T2) :-
de_vari(T1),
de_vari(T2),
T1=T2.
de_vari([]).
de_vari([H|T]) :-
de_var(H),
de_vari(T).
de_vari(X) :- de_var(X).
de_var(X/_) :- de_var(X).
de_var(X-Y with List) :-
init_vargen,
de_v(X-Y),
de_vl(List), !.
de_var(X-Y) :-
init_vargen,
de_v(X-Y), !.
de_vl([]).
de_vl([H|T]) :-
de_v(H),
de_vl(T).
de_v(X-Y) :-
d_v(X),
d_v(Y).
d_v(V) :-
var(V),
var_gen(V), !.
d_v(_).
init_vargen :-
abolish(varg,1),
asserta(varg(1)).
var_gen(V) :-
retract(varg(N)),
NN is N+1,
asserta(varg(NN)),
string_integer(NS,N),
string_list(NS,NL),
append("#VAR_",NL,X),
name(V,X).
% predicates to update the rete network
% add a token to the rete net. a token is of the form C-N with [S-V,...]
% ReqList gets bound with the values from the term added to the database.
addrete(Class,Name,TimeStamp) :-
root(ID,Class-Name with ReqList, NextList),
ffsend(Class,Name,ReqList,TimeStamp,NextList),
fail.
addrete(_,_,_).
% fullfill the request list from the token, and send the instantiated
% token through the net.
ffsend(Class,Name,ReqList,TimeStamp,NextList) :-
getf(Class,Name,ReqList),
send(tok(add,[(Class-Name with ReqList)/TimeStamp]), NextList),
!.
delrete(Class,Name,TimeStamp) :-
root(ID,Class-Name with ReqList, NextList),
delr(Class,Name,ReqList,TimeStamp),
fail.
delrete(_,_,_).
delr(Class,Name,ReqList,TimeStamp) :-
getf(Class,Name,ReqList),
!, send(tok(del,[(Class-Name with ReqList)/TimeStamp]), NextList).
delr(Class,Name,ReqList,TimeStamp).
% send the new token to each of the succesor nodes
send(_,[]).
send(Tokens, [Node|Rest]) :-
sen(Node, Tokens),
send(Tokens, Rest).
% add or delete the new token from the appropriate memory, build new
% tokens from left or right and send them to successor nodes.
sen(rule-N,tok(AD,TokenList)) :-
rul(N,TokenList,Actions),
(AD = add, add_conflict_set(N,TokenList,Actions);
AD = del, del_conflict_set(N,TokenList,Actions)),
!.
sen(Node-l,tok(AD,TokenList)) :-
bi(Node,TokenList,Right,NextList),
(AD = add, asserta( memory(Node-l,TokenList) );
AD = del, retract( memory(Node-l,TokenList) )),
!,matchRight(Node,AD,TokenList,Right,NextList).
sen(Node-r,tok(AD,TokenList)) :-
bi(Node,Left,TokenList,NextList),
(AD = add, asserta( memory(Node-r,TokenList) );
AD = del, retract( memory(Node-r,TokenList) )),
!,matchLeft(Node,AD,TokenList,Left,NextList).
sen(test-N,tok(AD,TokenList)) :-
tes(N,TokenList,[Test/0],NextList),
test(Test),
append(TokenList,[Test/0],NewToks),
!,send(tok(AD,NewToks),NextList).
matchRight(Node,AD,TokenList,Right,NextList) :-
memory(Node-r,Right),
append(TokenList,Right,NewToks),
send(tok(AD,NewToks),NextList),
fail.
matchRight(_,_,_,_,_).
matchLeft(Node,AD,TokenList,Left,NextList) :-
memory(Node-l,Left),
append(Left,TokenList,NewToks),
send(tok(AD,NewToks),NextList),
fail.
matchLeft(_,_,_,_,_).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -