% File: ECMI01.FF_FF % Author: Peter Hammond, IC, 1982. Rewritten by Peter Ross % Updated: 30 Nov 1983 % Purpose: a very simple 'expert system' % FAULTFINDER: a general fault finding system. See below for a brief account. % % The rewrite was for various reasons: % - the original was in Waterloo Prolog % - EMAS Prolog does not offer 'ancestor(_)' or any fast-moving % kludge of it in Prolog % - the i/o needed tidying. % % Desirable improvements: % - probabilistic reasoning % - a better interface for questioning the user % - a mechanism for 'how' questions % - a 'help' mechanism % These commands load the system. To load a specific fault description % file, use ffload/1 giving a filename or a list of filenames. % Once that has been done, start the fault-finding process by the goal % find_fault/0. ?- write( 'Loading takes about 10 seconds when there are very few users. Hang about... and when you get the prompt back, remember to load a specific description file, using ffload(File). '). ?- reconsult('ECMI01.FF_UTILS'). % the set of utilities ?- reconsult('ECMI01.FF_LOAD'). % the database loader ?- reconsult('ECMI01.FF_MAIN'). % the top level of the general bit ?- reconsult('ECMI01.FF_RULES'). % the fault-finding stuff ?- reconsult('ECMI01.FF_EXPLAIN'). % the explanation sub-system % The details: faults are divided, for simplicity, into three kinds - % general, specific and separable. Specific faults are ones that can be % cured by some action. General and separable faults are ones that are % cured by curing their causes, causes being more specific faults. Separable % faults are ones that have an associated test; the causes depends on the % result of the test. Each fault is identified, in a fault description file, % by a terse identifier, e.g. ghnwp for "gas heater not working properly". % Each fault also has a number of properties, which depend on its type. % Whatever the type, each fault has at least these, set out as shown: % % {id}: name = '{full name for use in the dialogue with the user}' % & type = {the type of this fault} % & preconditions = {either 'none' or 'not({id})'} % & question = '{Question to determine if this fault exists}' % & confirmed if {the reply that imples the fault exists} % % General faults also have, in addition to these five, % % & causes = {id1} or {id2} or ... or {idN} . % % Specific faults also have, in addtion to the five above, % % & action = '{Statement of an action to fix the fault}' . % % Separable faults also have, in addition to the five above, % % & action = '{Statement of a action to make a test}' % & test = '{Question to determine which causes to pursue}' % & causes = [{id1} or .. or {idM} if {answer1}, .... ] . % % Questions should NOT include the question mark. There needs to be a % declaration of the top-level fault: % % top_fault = {id} . % % Every fault considered is, at any time, in one of various possible states: % exists, may_exist, cannot_exist, corrected, cannot_be_corrected % and at the end, every fault investigated must be in one of the last three % of these. % % The general method used by FAULTFINDER is to track down the state of a % fault by (a) checking that the precondition of it holds (it may be that % a fault cannot happen because some prior fault prevents it), (b) finding % out the apparent state of it, either by checking the knowledge gained in % the course of the investigation or by asking the user, and then (c) if % necessary (i.e. if the apparent state is 'exists' or 'may_exist') deducing % the actual state. This means finding out the state of each of the causing % faults until one is found that can be corrected, correcting it and asking % the user if the higher fault it might have caused has gone away. % % Whenever the system asks the user a question, a valid reply is "w" - % that is, "why is that relevant?". The system will give a (very brief) % reply and ask again. Replying "w" again leads to an explanation of the % previous reply by the system, and so on.