The specification and implementation of a distributed medical expert system

\label{des/know/xps} Designing an object oriented system involves modeling the problem domain by using objects. For many objects in the system there will indeed be an observable entity in the problem domain whose functionality is reflected in the object. But, in order to be able to design a working system, it will be unavoidable to introduce objects that can only be considered the counterpart of some inferred entities in the problem domain, entities that must be assumed to exist in order to explain some phenomenon or functional behavior. When designing a system, it is important to be able to separate those two kinds of objects, since our assumptions with regard to such behavior may change. In modeling medical diagnosis, an example of the introduction of such artificial objects is provided by the objects implementing the reasoning capability of the diagnosticians. It seems valid to assume that a doctor comes to a conclusion concerning a certain disease by applying knowledge to facts. The assumptions with respect to how this takes place are embodied in the reasoning component that consists of the objects infer and facts. The knowledge that is needed to make inferences on the other hand is assumed to belong to the area of medical practice itself. The reasoning component, nevertheless, is dependent on the format of the knowledge. An expert system may be characterized as a system having the capability of a human expert. A medical expert system has medical expertise. In the design of our (toy) medical expert system a distinction is made between the reasoning component and a component modeling the behavior of the various actors and entities in medical practice. The medical knowledge presented here is purely fictional. The knowledge we do have of this area comes from  [Lu86].

The reasoning component

The reasoning component of a traditional expert system consists of two parts: a store of facts that, in the case of medical diagnosis, initially contains the observed symptoms and a so-called inference engine that deduces new facts by using knowledge rules embodying the expertise. See  [Ha85],  [Lu86]. Knowledge rules of the form [] conditions -> conclusion are used by the system to add new facts when the given facts satisfy the conditions of the rule. The strategy by which new facts are derived may be characterized as backward reasoning. It proceeds by taking the conclusion of a rule, for example as a possible diagnosis, and checking the conditions of the rule. A condition is satisfied when it is either a fact, or it may be derived as a fact by applying some of the other rules.

Facts

Facts are stored in the object declared below. \lprog{facts}{ .ds facts.pl } The object facts has a non-logical variable data containing an initially empty list of facts. When creating an active instance of facts the instance variable data is initialized to the given facts. The object may then be asked whether a particular fact holds, or it may be asked to add a new fact.

Inference engine

The inference engine operates on a collection of facts, by applying knowledge contained in rules. A derivation is successful if the item that must be derived either holds as a fact or is derivable by recursively applying a knowledge rule. \lprog{infer}{ .ds infer.pl } The object infer as presented is of an abstract nature. It has the non-logical variables knowledge and facts to store respectively knowledge and facts. However, these variables can only be given a value by an object inheriting the capabilities of infer.

Modeling medical practice

The actors (or in the terminology of  [Booch86], the agents) that play a role in our conception of medical practice are doctors, having general knowledge of diseases, and specialists, having knowledge of special diseases. We also have a clinic to assign doctors and specialists to patients for consultation. Our medical knowledge is structured as an inheritance tree. At the top of this tree we find the most general knowledge concerning diseases. This knowledge is refined for specific diseases going down the tree. C.f.  [GC81].

Doctor

A doctor inherits the reasoning capacity needed to derive a diagnosis from the object infer. In other words, a doctor is a straightforward modification of an inference engine. C.f.  [WZ88]. A doctor possesses knowledge about diseases as represented by the object disease described below. This knowledge is also used to suggest the possible diagnoses the doctor will look for. \lprog{doctor}{ .ds doctor.pl } Before being able to accept the request for a diagnosis, the non-logical variable knowledge, inherited from infer, must be initialized to disease. The non-logical variable facts is updated when starting to search for a diagnosis. All possible diagnoses a doctor knows of will be tried.

Disease

An object oriented modeling technique has also been applied in the hier\-archical representation of knowledge about diseases. Our knowledge of diseases is structured as an inheritance tree. At the root of the tree we have the object disease, that represents the most general knowledge of diseases. This knowledge is laid down in rules that enable to assess whether a patient has the symptoms of someone who is ill. \lprog{disease}{ .ds disease.pl } Note that disease is both a constant, indicating a diagnosis, and an object, representing domain knowledge. Apart from the rules that contain the knowledge needed to establish a diagnosis, the object contains also a list of possible diagnoses, which for the generic case simply states that a patient may have a disease. These diagnoses function as hypotheses when searching for the actual diagnosis. The rules inform us that a patient has a disease if he has fever, that is a high temperature. In addition, the knowledge concerning a disease contains an indication of its possible causes. Such knowledge is included to allow specialists to give advice about the further examinations. Other diseases are specializations of the generic object disease. The objects representing specific diseases share by inheritance the more general knowledge. This knowledge is, for each disease, augmented with a number of rules embodying the specific knowledge concerning that disease. Each specific disease contains also a list of possible diagnoses in order to direct the search for a diagnosis. This list overwrites the list of diagnoses pertaining to the more general case. As an example of refining the generic object disease to a particular case consider the declaration for a liver disease. \lprog{liver}{ .ds liver.pl } Notice that, in accordance with our discussion of inheritance, the values of the variables diagnoses and causes are determined by the object containing the knowledge of a liver disease. Before going to a specialist, let us see what a doctor can do. .ds xps1.g The diagnosis delivered will be disease, since the doctor is not assumed to know anything about liver diseases. The patient needs a (liver disease) specialist for a more refined diagnosis. Before continuing we enlarge our body of knowledge. \lprog{lungs}{ .ds lungs.pl } The knowledge added contains some fictional rules concerning lung diseases. A lung disease allows for two possible diagnoses, which may give rise to backtracking during the consultation. Also we add some knowledge refining the knowledge about liver diseases. \lprog{hepatic}{ .ds intrahepatic.pl .ds extrahepatic.pl } Neither for lung diseases nor for the intrahepatic and extrahepatic variants of liver diseases are any causes known.

Specialist

The hierarchical structure of medical knowledge suggests to distribute the search for possible diagnoses over a number of specialists. In the practice of doctors, sending patients to specialists is a natural phenomenon. A specialist is a doctor having specific knowledge of a certain class of diseases. Apart from giving a diagnosis, a specialist also gives advice for further examination. This definition of a specialist enables to search, following the hierarchy of possible diseases, for the most specific diagnosis, taking the most general disease as a starting point. \lprog{specialist}{ .ds specialist.pl } The non-logical variable knowledge, inherited from infer (by being a doctor), is assigned the object representing a particular class of diseases. The constructor for a specialist further enforces that advice may be asked for only if a diagnosis has been given.

Clinic

The distributed nature of our diagnostic system comes to light in the definition of a clinic, that handles the distribution of tasks among the specialists. A clinic receives patients and assigns to each patient a doctor. This doctor is a specialist knowing all about diseases in general. When the specialist comes to the conclusion that the patient has a disease, he gives advice for further examinations. The advice given by a specialist is used to consult other specialists, having more specific knowledge of the diseases listed in the advice. An examination results in listing all the diagnoses that apply to the case. The advice given by a specialist consists of a list of possible causes. For each possible cause a specialist is created to examine the patient. Exploring the possible causes may occur in parallel, as indicated by the use of the parallel and-operator introduced in the previous section. The specialists created to explore the possible causes of a disease may be allocated to some processor by using the allocation primitives mentioned in section \ref{lang:new}. The result of exploring the possible causes is a possibly empty list of diagnoses. \lprog{clinic}{ .ds clinic.pl } Below I present the worst case that I can imagine. .ds xps2.g The reader is invited to compute the appropriate diagnoses by hand.