Science
Copyright © 2023 Jiri Kriz, www.nosco.ch

11    Rule-based Shell, Explanations

Solution of Exercise 11

11.1    Rule-based Shell with Explanations

/* rules: symptoms -> diagnosis, backward chaining, explanation why, how */

:- dynamic told/2.		/* For SWI Prolog */

define_operators :-
    op( 910, fy,  not), 
    op( 920, xfy, and), 
    op( 930, xfy, or),
    op( 940, xfx, cf), 
    op( 950, xfx, then),
    op( 960, fx,  if),
    op( 970, xfx, #).

:- define_operators.

/* Inference Engine: rules, backward */

solve( P1 and P2, Trace, Proof1 and Proof2) :-           
     solve( P1, Trace, Proof1), solve( P2, Trace, Proof2).

solve( P1 or P2, Trace, Proof) :- solve( P1, Trace, Proof).
solve( P1 or P2, Trace, Proof) :- solve( P2, Trace, Proof).

solve( not P, Trace, failed( P)) :- \+ solve( P, Trace, _).
             /* sorry: negation not treated satisfactorily */

solve( P, Trace, Fact # P ) :- Fact # P.

solve( P, Trace, R # if Proof then P) :- 
    R # if P0 then P,
    solve( P0, [R | Trace], Proof).

solve( P, Trace, told( P) ) :- told( P, yes).
solve( P, Trace, told( P) ) :- askable( P), \+ told( P, _), 
                               ask( P, Trace).

ask( P, Trace) :- nl, write( P), write( ' [yes./no./why.] ? '),
                  read( A), respond( P, A, Trace).
   
respond( P, yes, Trace) :- assert( told( P, yes)), !.
respond( P, no, Trace) :- assert( told( P, no)), !, fail.

respond( P, why, []):- !, nl, write( ' you ask too many questions'),
                       ask( P, []).
respond( P, why, [H]) :- !, nl, write( H), write(' is my hypothesis'),
                       ask( P, []).
respond( P, why, [R | Trace]) :- !, 
    R # if G1 then G, 
    nl, write(' trying to apply the rule'), 
    show_rule( R # if G1 then G),
    nl, write( 'to prove the conclusion '), write( G),
    ask( P, Trace).

respond( P, _, Trace) :- write(' valid answers are: yes., no., why.'),
                         ask( P, Trace).

show_rule( R # if P0 then P) :-
    nl, write( R ), write( ' # '),
    nl, write( '   if   '), write( P0 ),
    nl, write( '   then '), write( P ).

how1( G, Fact # G) :- !,
    nl, write( G), write( ' is a fact '), write( Fact).

how1( G, told( G) ) :- !,
    nl, write( G), write( ' was told me').

how1( not G, failed( G) ) :- !,
    nl, write( not G), write( ' proved by failure of '), write( G).

how1( G, R # if _ then G) :- !,
    nl, write( G), write( ' was proved by using the rule: '), 
    R # if P then G,
    show_rule( R # if P then G).

how1( G, R # if Proof then _) :- 
    how( G, Proof).

how1( G, Proof1 and Proof2) :-
    how( G, Proof1) ; how( G, Proof2).

how( G, Proof) :- how1( G, Proof), !.
how( G, _) :- nl, write( G), write( ' was not proved').

explain( Proof) :-
    nl, nl, write( 'explanation ? [Goal./no.]: '), read( G),
    ( G \= no -> how( G, Proof), explain( Proof) ; true),
    !.

backtrack :- nl, nl, write( 'further solutions ? [yes./no.]: '), read( no).

init :- retractall( told( _, _)). 

/* Shell */

shell :-
    init,
    goal( G),
    solve( G, [G], Proof),
    nl, nl, write( 'diagnosis: '), write( G),
    explain( Proof),
    backtrack.
	 
test(G, Proof) :-
    init,
    goal( G),
    solve( G, [G], Proof).
	

Back to example 11.1

11.2    Rule-based Diagnosis

/* The shell from 11.1 must be consulted first */
	 
r1 # if   cloth_burnt 
     then temperature( too_high).

r2 # if   temperature( too_high) 
       or temperature( too_low)
     then temperature( wrong).

r3 # if   temperature( wrong)
      and thermostat( setup_correctly)
     then thermostat( faulty).

r4 # if   temperature( wrong)
      and not thermostat( setup_correctly)
     then thermostat( adjust_correctly).

r5_1 # if   no_steam
       then temperature( too_low).

r5_2 # if   no_steam 
       then steam_problem.

r6_1 # if   steam_problem 
       then no_water.

r6_2 # if   steam_problem
       then nozzle_congested.

r7 # if   ironing_poor 
     then temperature( too_low).

r8 # if   iron_cold 
      and lamp_shines
     then wait.

r9 # if   iron_cold 
      and not lamp_shines
     then no_power.

s1 # symptom( cloth_burnt).
s2 # symptom( no_steam).
s3 # symptom( ironing_poor).
s4 # symptom( iron_cold).
s5 # symptom( lamp_shines).
s6 # symptom( thermostat( setup_correctly)).

d1 # diagnosis( thermostat( faulty)).
d2 # diagnosis( thermostat( adjust_correctly)).
d3 # diagnosis( no_water).
d4 # diagnosis( nozzle_congested).
d5 # diagnosis( no_power).
d6 # diagnosis( wait).


diagnose :- 
     shell.

askable( P) :- S # symptom( P).

goal( G) :- D # diagnosis( G).


/* Testing
?- diagnose.
*/

Back to example 11.2