Prolog++ is a product by LPA Associates for object-oriented programming extensions of LPA Prolog. Most Prolog++ programs can be easily converted into SICStus Objects programs. The following is a translation of a program for fault diagnosis in LPA's Prolog++ manual, page 83. The program illustrates a top-down diagnosis method starting from general objects to more specific objects. The problem is fault diagnosis for car maintenance. The objects have the following structure:
- faults - electrical | - lights | - starting | - starter_motor | - sparking | - plugs | - distributer - fuel_system - mechanical
The general diagnosis method is defined in the object faults
,
whereas the cause-effect relationships are defined in the specific
objects e.g. the object distributor
.
This program heavily uses the sub/1
method. We have tried
to be as close as possible to the original formulation.
faults :: { super(utility) & dynamic(told/2) & /* no fault is the default */ fault(_, _) :- :fail & findall :- <: restart, :: sub(Sub), Sub :: find(Where, Fault), <: print(Where, Fault), :fail & findall & print(Where, Fault) :- :writeseqnl('Location : ', [Where]), :writeseqnl('Possible Fault : ', [Fault]), :nl & find(Where, Fault) :- self(Where), fault(FaultNum, Fault), \+ (effect(FaultNum, S), contrary(S, S1), exhibited(S1) ), \+ (effect(FaultNum, SymptomNum), \+ exhibited(SymptomNum)) & find(Where, Fault) :- sub(Sub), Sub :: find(Where, Fault) & exhibited(S) :- :: told(S, R), !, R = yes & exhibited(S) :- symptom(S,Text), ( :yesno([Text]) -> R = yes ; R = no ), :: asserta(told(S,R)), R = yes & restart :- :: retractall(told(_,_)) }. electrical :: { super(faults) }. fuel_system :: { super(faults) }. mechanical :: { super(faults) }. lights :: { super(electrical) }. sparking :: { super(electrical) }. starting :: { super(electrical) }. starter_motor :: { super(electrical) }. plugs :: { super(sparking) }. engine :: { super(mechanical) }. cylinders :: { super(engine) }. distributor :: { super(sparking) & /* faults */ fault('F1001', 'Condensation in distributor cap') & fault('F1002', 'Faulty distributor arm') & fault('F1003', 'Worn distributor brushes') & /* symptoms */ symptom('S1001', 'Starter turns, but engine does not fire') & symptom('S1002', 'Engine has difficulty starting') & symptom('S1003', 'Engine cuts out shortly after starting') & symptom('S1004', 'Engine cuts out at speed') & /* symptoms contrary to each other */ contrary('S1002', 'S1001') & contrary('S1003', 'S1001') & /* causal-effect relationship */ effect('F1001', 'S1001') & effect('F1002', 'S1001') & effect('F1002', 'S1004') & effect('F1003', 'S1002') & effect('F1003', 'S1003') }. yesno(Value) :- write(Value), nl, read(yes). writeseqnl(Prompt, L) :- write(Prompt), write_seq(L). write_seq([]). write_seq([X|L]) :- write(X), write(' '), write_seq(L), nl. faults :- faults :: findall. | ?- faults. [Starter turns, but engine does not fire] |: yes. Location : distributor Possible Fault : Condensation in distributor cap [Engine cuts out at speed] |: yes. Location : distributor Possible Fault : Faulty distributor arm | ?- faults. [Starter turns, but engine does not fire] |: no. [Engine has difficulty starting] |: yes. [Engine cuts out shortly after starting] |: yes. Location : distributor Possible Fault : Worn distributor brushes