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
yes
| ?- 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