;;; Simple expert system shell for MYCIN-like control           Chris Mellish
;;; For MSc

;;; To be added:
;;;
;;; combine_evidence(List,Prob)   - List is a list of probabilities obtained
;;;                                 by using different rules for inferring
;;;                                 some fact. Prob is the probability
;;;                                 expressing this "combined evidence"
;;; conjoin(Probs,Prob,Result)    - Probs is the list of probabilities that the
;;;                                 conditions in a rule are true. Prob is the
;;;                                 probability that the rule is correct. Result
;;;                                 is the resulting evidence for the conclusion.

:- library(fast_bagof).

;;; fast_bagof produces a list of all solutions to a Prolog goal                     
;;; In this case, it produces a structure
;;;     rule(Fact,Conds,Prob)
;;; for every way it can show
;;;     ?- rule(Fact,Conds,Prob)
;;; and the 3rd argument is instantiated to a list of such structures

;;; establish is used to establish the probability associated with a given
;;; proposition.

establish(Fact,Prob) :-
   known_fact(Fact,Prob).
establish(Fact,FinalProb) :-
   not(known_fact(Fact,Prob)),
   fast_bagof(rule(Fact,Conds,Prob),rule(Fact,Conds,Prob),Rules),
   evaluate_rules(Rules,Fact,Probs),
   combine_evidence(Probs,FinalProb),
   assert(known_fact(Fact,FinalProb)).

;;; Evaluate the evidence for a fact, given the list of rules that
;;; would conclude that fact. If there are no rules, ask the user

evaluate_rules([],Fact,[Prob]) :-
   ask_about(Fact,Prob).
evaluate_rules([R|Rs],Fact,Probs) :-
   eval_list([R|Rs],Probs).

   eval_list([],[]).
   eval_list([rule(_,Conds,Prob)|Rs],[P|Ps]) :-
      establish_all(Conds,Probs),
      conjoin(Probs,Prob,P),
      eval_list(Rs,Ps).

;;; Establish a whole list of probabilities for a whole list of facts     

establish_all([],[]).
establish_all([Fact|Facts],[Prob|Probs]) :-
   establish(Fact,Prob),
   establish_all(Facts,Probs).

;;; Ask the user whether a fact is true            

ask_about(Fact,Prob) :-
   write([probability,of,Fact,:]),
   read(Prob).

;;; Example rules

rule(measles,[spots_on_face,fever],0.5).
rule(measles,[loss_of_appetite],0.9).
rule(mumps,[swelling,fever],0.5).
rule(fever,[sweating,dizziness],0.9).

;;; Example goal

;;; ?- establish(measles,Prob).
