in my previous question's best answer, I found a good example of forward chaining in Prolog. I have modified it a bit, but there is a problem with the last rule I tried to define (path). It doesn't work. With the current facts, I should be able to derive the path([a,b,c,d,e]), but it doesn't work.
Forward code:
:- op(1100, xfx, if).
:- op(1000, xfy, and).
:- op(900, xfy, or).
:- dynamic rule/1.
forward(Facts) :-
fixed_point(nil, [true], Facts). % Start with the base with only true
fixed_point(Base, Base, Base) :- !. % Reached a fixpoint
fixed_point(_, Base, Facts) :- % Base =/= Facts => not a fixpoint
setof(Fact, derived(Fact, Base), NewFacts), % Derive new facts
ord_union(NewFacts, Base, NewBase), % Add new facts to base
fixed_point(Base, NewBase, Facts). % Repeat with new base
derived(Fact, Base) :-
rule(Fact if Condition), % Match a rule
satisfy(Base, Condition). % Verify if condition is satisfied given base
satisfy(Base, Condition) :-
Condition =.. [and, Elem|Bag],!,
member(Elem, Base),
( Bag = []
-> true
; NewAtom =.. [and|Bag],
satisfy(Base, NewAtom)).
satisfy(Base, Condition) :-
Condition =.. [or, Elem|Bag],!,
( member(Elem, Base)
-> true
; ( Bag = []
-> false
; NewAtom =.. [or|Bag],
satisfy(Base, NewAtom))).
satisfy(Base, Condition) :-
member(Condition, Base),!.
satisfy(_, true):-!.
satisfy(_, false):-!,fail.
Here are rules and facts:
rule(eats_flies(fritz) if true).
rule(croaks(fritz) if true).
rule(eats_flies(frotz) if true). % ADDED IN EDIT
rule(croaks(frotz) if true). % ADDED IN EDIT
rule(sings(tweety) if true).
rule(chips(tweety) if true).
rule(has_wings(tweety) if true).
rule(croaks(krogr) if true).
rule(chips(kroger) if true).
rule(canary(X) if and(sings(X),chips(X),has_wings(X))).
rule(frog(X) if and(croaks(X),eats_flies(X))).
rule(green(X) if frog(X)).
rule(yellow(X) if canary(X)).
rule(node(a) if true).
rule(node(b) if true).
rule(node(c) if true).
rule(node(d) if true).
rule(node(e) if true).
rule(connected(a,b) if true).
rule(connected(b,c) if true).
rule(connected(c,d) if true).
rule(connected(d,e) if true).
rule(funny(c,d) if true).
rule(wonderful(X,Y) if or(nice(X,Y),funny(X,Y))).
rule(connected(X,Z) if and(connected(X,Y),connected(Y,Z))).
rule(path([Node|[]]) if node(Node)).
rule(path([Node, NextNode|Nodes]) if and(connected(Node, NextNode),path([NextNode|Nodes]))).
Critical rules:
rule(path([Node|[]]) if node(Node)).
rule(path([Node, NextNode|Nodes]) if and(connected(Node, NextNode),path([NextNode|Nodes]))).
What I get as output of the forward:
?- forward(A).
A = [true,canary(tweety),chips(kroger),chips(tweety),croaks(fritz),croaks(krogr),eats_flies(fritz),frog(fritz),green(fritz),has_wings(tweety),node(a),node(b),node(c),node(d),node(e),path([a]),sings(tweety),yellow(tweety),connected(a,b),connected(a,c),connected(b,c),connected(c,d),connected(d,e),funny(c,d),wonderful(c,d)].
EDIT:
Testing the code I found out that another problem is that if I add similar rules, such as:
rule(eats_flies(fritz) if true).
rule(croaks(fritz) if true).
rule(eats_flies(frotz) if true).
rule(croaks(frotz) if true).
The forward will only find that fritz is a frog, but not frotz.