31
Model based programming in a medical context By Troels Arvin <[email protected]> Supervisor: Tarik Hadzic <[email protected]> November 9, 2004 Revision :1.28 Contents 1 Introduction 2 2 ConfigIt’s tool and virtual tables 3 2.1 ConfigIt Developer, PML, and related tools ............ 3 2.2 Virtual tables ............................ 4 3 Problem domain 5 3.1 Indications, contraindications, contramedications, and allergies . . 5 3.2 ACT codes ............................. 5 3.3 Diagnosis .............................. 6 3.4 Lactation, pregnancy, children ................... 7 3.5 Unhandled issues and excessive constraints ............ 7 4 Implementation description and discussion 9 4.1 Intended purpose and use ...................... 9 4.2 Use case 1: A child with an infection ................ 9 4.3 Use case 2: A user without a treatable disease ........... 14 4.4 Use case 3: Hypertension conflicts with hypotension ....... 14 4.5 “The bug” .............................. 16 4.6 Long compilation times ....................... 16 5 Conclusions 19 References 20 A Appendix: Example medication description 21 B Appendix: Example ICD-10 tables 22 C Appendix: Code 23

Model based programming in a medical context - troels.arvin.dktroels.arvin.dk/itu/mbp/mbp-troels_arvin.pdf · This report describes the process of using model based programming in

  • Upload
    dinhnga

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

Model based programming in a medical context

By Troels Arvin <[email protected]>Supervisor: Tarik Hadzic <[email protected]>

November 9, 2004Revision : 1.28

Contents

1 Introduction 2

2 ConfigIt’s tool and virtual tables 32.1 ConfigIt Developer, PML, and related tools . . . . . . . . . . . . 32.2 Virtual tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

3 Problem domain 53.1 Indications, contraindications, contramedications, and allergies . . 53.2 ACT codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53.3 Diagnosis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63.4 Lactation, pregnancy, children . . . . . . . . . . . . . . . . . . . 73.5 Unhandled issues and excessive constraints . . . . . . . . . . . . 7

4 Implementation description and discussion 94.1 Intended purpose and use . . . . . . . . . . . . . . . . . . . . . . 94.2 Use case 1: A child with an infection . . . . . . . . . . . . . . . . 94.3 Use case 2: A user without a treatable disease . . . . . . . . . . . 144.4 Use case 3: Hypertension conflicts with hypotension . . . . . . . 144.5 “The bug” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164.6 Long compilation times . . . . . . . . . . . . . . . . . . . . . . . 16

5 Conclusions 19

References 20

A Appendix: Example medication description 21

B Appendix: Example ICD-10 tables 22

C Appendix: Code 23

1 Introduction

This report describes the process of using model based programming in a medicalcontext. The report is the end-result of a four-week project at ITU in May of 2004named Model based programming, Spring 2004.

Model based programming is a loosely defined concept, usually referring to theuse of UML diagrams and graphical user interface tools for code generation. In thisproject, however, the term should be interpreted as the use of declarative, logicalexpressions for modelling and interacting in a problem domain. The logical ex-pressions are composed in a domain specific language used in ConfigIt Software’sConfigIt Developer tool[1].

The main objective of this project is to learn how to use a logical programminglanguage to express a problem domain.

The problem domain in my project is prescription of medication. Having amedical bachelor degree in medicine, I thought it would be interesting to combinemy interests in medical an computer science topics. The model that I have imple-mented is rather simple, though; hopefully, I have managed to describe the problemdomain well enough, so that anyone is able to recognize the chosen rules reflectedin my program.

I envision that model based on technologies like the ones used in this projectmight be used to create decision support systems for health care professionals, andperhaps as part of healthcare analytical work. In order to maintain that vision, Ihave made a few choices that might seem to complicate the implementation, butwhich would probably have to be made in an imaginary real-World implementa-tion.

The report starts by describing the ConfigIt Developer tool and then proceedsto a description of the medical issues. Subsequently, I present three use cases anddiscuss the related programming choises and experiences I’ve had, citing selectedcode. Finally, I conclude by summarizing what I believe to have learned in theproject.

Appendix C on page 23 contains the code which resulted from my work. Thecode is also available online at http://troels.arvin.dk/itu/mbp/ along with an elec-tronic version of this report.

2

2 ConfigIt’s tool and virtual tables

2.1 ConfigIt Developer, PML, and related tools

ConfigIt Developer’s language for model specification is a purely declarative do-main specific language, called PML1. PML is written in plain text files in any editorand subsequently compiled by the pmc compiler into a virtual table which containsall possible model solutions in a compressed form. The virtual table may then bequeried by a model viewer which is responsible for filtering out illegal solutionsbased on input from the user. ConfigIt distributes a default viewer program calledthe Product Model Viewer which I employ as the user front-end in my project.

A purely declarative programming language compiling into a table of possiblesolutions which is then used in a viewer may not qualify as a “program” in somepeople’s ears. Anyhow, in this report, I will refer to my program as the PML modelspecification presented in the model viewer.

PML features constants, typed variables, records (structures), arrays, rules, andmacros.

A variable is what’s exposed to the user2, i.e. how the user enters informationinto the model. The type system is limited in order to enforce range restricted vari-ables. I.e., there isn’t a general integer type, but instead a variable may be of type[0..10] meaning integers from 0 through 103. Neither does a general string typeexist, but a variable may be declared as an enumeration of string literals:variable firstname: [Peter, Michael, John];.

Records (structures) may be used as a notational convenience:

variable person: {firstname: [Peter, Paul, Sean];lastname: [Johnson, Clinton];age: [0..120];

};

Fixed size (0-based) arrays may be used for collections/sets.Rules define variable inter-dependencies. The rule syntax resembles first order

logic, augmented with basic arithmetic operators. A—rather stupid—rule mightstate that all persons named Peter must be children:

rule if person.firstname=Peter then person.age<18;

Such a rule might be embedded in the person structure, sort of creating a class(collection of state and logic) in an object oriented language:

variable person: {firstname: [Peter, Paul, Sean];lastname: [Johnson, Clinton];

1I suppose that PML is short for Product Modelling Language. “PM”—i.e. an acronym leavingout “Language”—is the language name used in the latest documentation[8]. An earlier document[7]uses “PML”; PML has less connotations in my vocabulary, so I will stick to that acronym in thisreport.

2Variables may be declared private, however, meaning that they will be hidden from the user.3Range intervals must start at 0.

3

age: [0..120];

ruleif firstname=Peter then age<18;

};

2.2 Virtual tables

The compiler’s job is to translate the specification into a virtual table containing allpossible solutions/states in the model. In a course lecture, we were hinted that thecompiler translates the model specification into a reduced ordered binary decisiondiagram (ROBDD)[9], often allowing a model with a vast amount of solutions tobe represented in a very compact form.

There is no guarantee that the compiler is able to translate a model into a virtualtable[7] in acceptable time: The compiler may practically work forever on a modelin some cases. This is because PML has enough expressive power to form NP-complete (or harder) problems. Thus, for some models, the only way to construct atable of solutions is to simply test all possible solutions, resulting in running timeswhich rise (“explode”) exponentially with the model size. The good news is thatif the compiler is able to complete a virtual table, then queries in the table willsubsequently be quick, or at least with predictable running times.

Another good news is that with regard to the size of the virtual table, it doesn’tmatter exactly how the rules are formulated, as long as they are valid for the prob-lem domain: Any semantically equivalent variant construct of and, or, not, etc.,will translate to the same table. Note, however, that it still matters how rules areformulated: Sometimes, syntactic paraphrasing of a rule will mean the differencebetween days and seconds of compile time.

4

3 Problem domain

3.1 Indications, contraindications, contramedications, and allergies

When choosing a medication for a medical state (normally: a disease), a physicianmust take a set of qualifying and disqualifying circumstances into consideration,along with other parameters. If a medication is considered proper treatment of adisease, then it’s said that the medication is indicated for the disease. If, on theother hand, the medication must not be given to a patient with a given health state,then the medication is said to be contraindicated.

A medication is always associated with at least one indication, i.e. a healthstate for which it is considered proper treatment. In other words: A medicationmay never be prescribed for no reason. A medication may also be associated witha set of contraindications which are health states where the medication must notbe prescribed.

A medication may be incompatible with another medication. In this report, Ihave chosen the term contramedication for this: A medication may have a set ofcontramedications, meaning that it cannot be used if the patient is also prescribedone of the contramedications. I believe that the term ‘contramedication’ is not usedin the medical world, but it’s handy in this report.

Furthermore, a patient may be allergic to a medication. This phenomenon maybe seen as an individualized contraindication.

3.2 ACT codes

Medications based on the same active components may be produced by severaldifferent companies under different brand names. Therefore, the medical com-munity has established the Anatomical Therapeutic Chemical (ACT) classificationsystem[2]. All officially registered medications are assigned an ACT code4 by theWorld Health Organization, such as C-09-C-A-01 (often used without dashes, likein the rest of this report). The code consists of five parts:

• One letter signifying the anatomical main group, i.e. the part of the bodythat the medication is mainly used for.

• Two digits signifying the main therapeutic subgroup, i.e. what kind of illnessthe medication is for.

• One letter representing the pharmacological subgroup, i.e. the type of medi-cation.

• One letter designating the chemical subgroup.

• Two digits representing the exact main chemical substance.

4A medication may actually have several ACT codes if it may be used for several, significantlydifferent purposes, but that is not considered in this project.

5

Thus, two differently named medications (produced by different companies)may have the same ACT code, because they are used for the same purpose andhave the same main active chemical component(s). However, the two medicationsmay still be produced differently, e.g. use different helper-substances (such aspreservatives or coating materials). Hence, I assume that a person might be allergicto one—but not both—of two medications with the same ACT code.

Another assumption that I have made, is that medications with the same ACTcode will have identical indications, contraindications, and contramedications. Me-dical professionals might object to this, but I find the assumption somewhat sound,and it allows for certain code simplifications.

The main source of medication information in this report is the 1997 edition ofLægemiddelkataloget[3] (literally: ’Medication Catalogue’)5 . An example entry(for the “Aldomet” product) is printed in Appendix A on page 21.

Lægemiddelkataloget is widely used by Danish physicians. It is comprehensiveand actually somewhat readable; the flip side is that the contained information isnot allways as stringent and structured as a programmer likes. E.g., rather broadterms like ’heart disease’ may be stated as a contraindication.

As I envision that a model based decision support engine could be integratedwith other medical information systems, such lack of stringency could hinder safeinformation integration. Consequently, I have tried to map health states to codes ina discrete diagnosis classification system. This leads to the next section:

3.3 Diagnosis

The World Health Organization maintains the International Statistical Classifi-cation of Diseases and Related Health Problems, currently in its tenth revision,commonly referred to as ICD-10[4]. In this report, I have used a Norwegan web-interface[5] to search the ICD-10 for diagnosis codes6 (so the translation of Nor-wegan diagnosis names may not be entirely correct).

An example ICD-10 code could be I10, representing Essential hypertension,i.e. hypertension that is not caused by a known factor such as heart failure orhypertension-causing medication. Appendix B on page 22 prints an example fromthe ICD-10 tables.

In my code, I have tried to stay with ICD-10 defined diagnoses only.That proved impossible, however: An anesthesic (like Halotan) is used when

there is a need to bring the patient into a state of unconsciousness; it is never usedas a treatment of a disease. Hence, I have introduced a few non-ICD-10 basedhealth states, like “Need for universal anesthesia”.

Another challenge with the ICD-10 system is that ICD-10 diagnoses actuallyform a tree. Example: I42 (Cardiomyopathy) can be seen as a category of codes,

5It was too late until I found out that an up-to-date, online version of Lægemiddelkataloget isactually available at http://www.lk-online.dk/.

6I later discovered another source, namely a set of draft PDFs at the home page of the US NationalCenter for Health Statistics[6].

6

such I42.0 (Dilated cardiomyopathy), I42.1 (Obstructive hypertrophic cardiomy-opathy), and I42.2 (Other hypertrophic cardiomyopathy). As some medicationsmight have a whole group (like I42) as an indication, it would be relevant to some-how represent such hierarchical characteristics in the code. I didn’t do this, due totime constraints; instead, I included all diagnosis codes of a category if the wholecategory was to be included as indications/contraindications.

3.4 Lactation, pregnancy, children

Generally, physicians are cautious when exposing medications to infants and, espe-cially, embryos. There are several reasons for this, including:

• For practical and ethical reasons, it is difficult to perform clinical trial studiesinvolving infants. Hence, knowledge about health effects of medications oninfants is scarce.

• Body growth—especially embryo development—is a delicate matter, so fearof malicious side effects of medications is greater when treating infants.

• An infant’s detoxfication system (including the liver) may not be as capableas that of a grown person.

Consequently, it is common that special recommendations exist for a medi-cation when used for children7 . Also, pregnant and lactating women may passmedications on to their embryo or child. In my code, I therefore make special rulesin case of use for children, lactating women, and pregnant women.

A obvious constraint exists: A child can never be pregnant or breast feeding8 .

3.5 Unhandled issues and excessive constraints

The text of the medication descriptions is sometimes vague: Some of the con-traindications are expressed as warnings, or complex dose guidelines might exist.In such cases, I have chosen to ignore warnings. Thus, an end user is expected tobe a trained medical professional who will look into the medication details afterhaving chosen between available, qualifying medications.

In the real World, it may be the case that a patient has a certain diagnosisfor which known medications exist, but the patient is not prescribed any of thesemedications. This may be for many reasons, like the patient refusing to take themedication, or the physician thinking that the diagnosis is not of a ‘magnitude’ atwhich treatment is strictly necessary. In my model, this is not accepted: If one ormore medications for a diagnosis exist, then the patient must be prescribed at leastone of them. Another case of my model being more strict than reality is that mymodel enforces at least one diagnosis; if the patient doesn’t have a diagnosis, then

7I have refrained from defining what a child is, as there doesn’t seem to be a generally acceptedmedical definition. I do, however, assume that a child cannot be pregnant.

8But a pregnant woman might actually be lacting.

7

why use the model at all? Such—perhaps—overly strict constraints are enforced inorder to make the system catch states that might result from erroneous use. Anothermotivation is that I want a system to be as tight as possible, anticipating that thiswould make the model perform better if used as part of an analytical tool.

8

4 Implementation description and discussion

4.1 Intended purpose and use

My intention was to create a tool which presents the available, valid medications,based on a patient’s diagnoses and on various information known about the patient.The ConfigIt Product Model Viewer seemed fine for this, so I haven’t spent timeimplementing a user interface in another context.

It’s obvious that my model is tiny; this is because I spent a lot of time fightingstrange model behaviour due to a subtle bug which will be described later. Thesmall size of the model is problematic: A model with more diagnoses and medica-tions would probably have revealed interesting modelling challenges which havenot been encountered in this project.

In the next sections, I will provide examples of use and comment on whichrules come into play.

4.2 Use case 1: A child with an infection

In my first use case, we assume that a physician has examined a child and reacheda diagnosis of pneumonia. First, he enters that the patient is a child, see Figure 1.This state change immediately has consequences: A child may neither be breastfeeding nor pregnant, and this is reflected in the model viewer by auto selection offalse for the values of the pregnant and lactating fields.

The PML code behind this is rather simple, and—hopefully—self-explanatoryrule:

if is_child then not (pregnant or lactating);

is_child, pregnant and lactating are variables defined earlier in the code:

variablepregnant: boolean;lactating: boolean;is_child: boolean;

Next, the user selects the most proper diagnosis from those available (see Fig-ure 2): Bacterial infection of unspecified site. This is done by selecting one ofthe diagnosis[] fields and double-clicking on the diagnosis. Even before doubleclicking, the model viewer has disallowed the selection of two hypertension sub-diagnoses. This is because the model doesn’t contain any child-friendly medicationfor thoses diagnoses.

Let’s assume that the child also needs to go through an operation which promptsuniversal anaesthetization9 . The user selects Need for universal anesthesia. Nowit’s time to select medication, see Figure 3, p. 11. The only choices are Escumycin,

9Universal anaesthetization brings the patient into total unconsciousness, not just localized lossof sensation.

9

Figure 1: Child status set to true; has consequences for the pregnant and lactatingstates.

Figure 2: Diagnosis selection. Note that some diagnoses are not selectable (redcrosses).

10

Figure 3: Selection of medications. Only two medications are available. “Nomedication” not selectable.

and Halotan Halocarbon (bottom of the list); selecting Escumycin as the first pre-scription auto-selects Halotan as the second selection.

Why are only Escumycin and Halotan selectable? – That’s because of this rule:

// All prescriptions must be there for a reason:// They must match an indication in a prescription.forall p in [0..NUM_PRESCRIPTIONS-1]: (

if prescriptions[p].act_code<>no_medicationthen exist i in [0..NUM_INDICATIONS-1]: (prescriptions[p].indications[i]<>no_diagnosisand exist d in [0..NUM_DIAGNOSIS-1]: (

prescriptions[p].indications[i]=diagnosis[d])

));

NUM_PRESCRIPTIONS is a constant defined in the very beginning of thecode, specifying the size of the prescriptions array; that array signifies how manymedications a patient may be prescribed. A constant is used because PML’s arrayshave a fixed size and it’s nice to be able to quickly change the value. The rule usesa universal quantifier (forall) to ensure that the following is true for all the patient’sprescriptions: If a “non-empty” medication is selected, then a medication with anindication matching at least one of the patients’ diagnoses must exist.

11

The reason why Halotan is auto-selected is this complementary rule:

// If a relevant medication exists for the diagnosis,// then the patient must be prescribed at least one of these.// In other words: We can not have a diagnosis for which// an indicated medication is known, but where the// medication is not among the chosen prescriptions.forall d in [0..NUM_DIAGNOSIS-1]: (

if diagnosis[d]<>no_diagnosisthen (if exist m in [0..NUM_ACTIVE_MEDICATIONS-1]: (

exist i in [0..NUM_INDICATIONS-1]: (active_medications[m].indications[i]=diagnosis[d]

))then exist p in [0..NUM_PRESCRIPTIONS-1]: (

// redundant (compiler hint):prescriptions[p].act_code<>no_medicationandexist i in [0..NUM_INDICATIONS-1]: (

prescriptions[p].indications[i]=diagnosis[d])

))

);

The rule’s semantics is indicated in the code comment. The code above con-sists of a compiler hint (see “// redundant (compiler hint)”). Compiler hints areused throughout the code to cut down on compilation times. At one point, I hadserious trouble with never-ending compilations, and compiler hints were sprinkledall over the place, before realizing the true source of the trouble (described later). Isubsequently cleaned up the code, and while I have not rigoriuosly measured com-pilation time differences, I believe that only relevant hints are left (i.e. those withnoticeable effect on compile time). The code also makes use of an array calledactive_medications. This array has manually been filled with only those medica-tions that are included because of their indications—not those which only exist tobe able to express medication incompatibilities. By the way, this is how an array is‘filled’ in PML:

active_medications[1].act_code=C07AA05;active_medications[2].act_code=C07AA16;active_medications[3].act_code=C09AA02;active_medications[4].act_code=C09AA03;active_medications[5].act_code=C09CA01;active_medications[6].act_code=J01FA01;active_medications[7].act_code=N01AB01;active_medications[8].act_code=N05BA12;

Effectively: A rule is added saying that the array’s element should always be asindicated. Note, that an implicit conjugation is inserted between individual rules.

The code presented above uses notation likeprescriptions[p].indications[i]=diagnosis[d]

To understand this, the medication_t record type needs to be explained. The en-tire medication_t is in the code appendix. The medication_t record specification

12

is declared as a type, due to the type keyword preceeding it earlier in the code.The record type starts with these lines which introduces the type as a record with apublic variable, name of medication_name_t type (defined elsewhere in the code):

medication_t: {name: medication_name_t;

Next, a number of private variables are added to the type:

private act_code: act_code_t;private indications: array NUM_INDICATIONS of diagnosis_t;private contra_indications: array NUM_CONTRA_INDICATIONS of diagnosis_t;private contra_medications: array NUM_CONTRA_MEDICATIONS of act_code_t;private ok_for_kids: boolean;private ok_for_preg: boolean;private ok_for_lact: boolean;

The act_code_t (medication code) and diagnosis_t types are defined elsewhere(enumerations of strings).

Subsequently, a set of rules are introduced into the record type:

...#define mk_medication(n,a) (if name=n then act_code=a)mk_medication(Alacor,C09AA02);mk_medication(Aldomet,C02AB01);mk_medication(Alprox,N05BA12);...

The code above employs a C-style macro. The lines are effectively stating:

if name=Alacor then act_code=C09AA02 andif name=Aldomet then act_code=C02AB01 andif name=Alprox then act_code=N05BA12...

This way, medication names—as seen by the user—are mapped to ACT codesused internally by the logical rules in the program: The user is never exposed tohard-to-remember ACT codes.

Further on, the medication_t type’s rule set is equipped with ‘knowledge’ aboutindications, contraindications, etc, see the code delimited by “BEGIN medication

specification” and “END medication specification”. An excerpt follows.

13

// BEGIN medication specifications( // Aldomet

act_code=C02AB01 andindications[0]="Essential hypertension" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]="Alcoholic liver disease" andcontra_indications[1]="Toxic liver disease" andcontra_indications[2]="Hepatic failure, not elsewhere classified" andcontra_indications[3]="Chronic hepatitis, not elsewhere classified" andcontra_indications[4]="Fibrosis and cirrhosis of liver" andcontra_indications[5]="Other inflammatory liver diseases" andcontra_indications[6]="Other diseases of liver" andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_lact=true andok_for_preg=true

) or (...

// END medication specifications

The rules are straight forward, except for the lines assigning no_diagnosis orno_medication to array elements. It turned out, that without such assignments, theempty array elements would cause monstrous compile times, see section 4.6 onpage 16.

4.3 Use case 2: A user without a treatable disease

In this little use case, a patient is examined, and it’s determined that the patient hasno diagnoses, except for bad breath, see Figure 4 on page 15. Even in such a stupidexample, a few rules come into play:

• A patient must have at least one diagnosis: Note that the no_diagnosis op-tion is not available in the selection list for second diagnosis because it hasalready been chosen in the first dianosis field.

• All prescriptions must be done based on indications: Since the model con-tains no medications which are indicated for no_diagnosis or bad breath, theviewer auto-selects “No medication” for the prescriptions.

The code for these rules has already been shown.

4.4 Use case 3: Hypertension conflicts with hypotension

Sort of for fun, I have introduced what could be called “ad-hoc domain knowledge”into the model: If a patient has hypertension, then by definition, he cannot alsohave hypotension.

This is illustrated with a simple use case: The physician has indicated that thepatient has hypertension. Now, for the next diagnosis, the viewer has disallowedselection of hypertension, see Figure 5 on page 15.

14

Figure 4: Bad breath selected as the only “diagnosis” other than no_diagnosis.

Figure 5: Hypotension not selectable because hypertension is already selected.

15

The code responsible for this domain constraint is a follows:

// A person cannot both have hyper- and hypo- tension.not exist i in [0..NUM_DIAGNOSIS-1]: (

exist j in [0..NUM_DIAGNOSIS-1]: ((

diagnosis[i]="Essential hypertension" ordiagnosis[i]="Essential hypertension with lung stasis" ordiagnosis[i]="Essential hypertension without lung stasis"

) and diagnosis[j]="Hypotension")

);

4.5 “The bug”

It is often claimed that declarative programming is less error-prone than imperativeprogramming, since declarative programming environments tend to relieve the pro-grammer of the worries about side effects and implementation/deployment details,so that the resulting code is concise and focused on the involved algorithmics andinvariants.

I believe that this is true. However, my experience with PML was that if an er-ror is introduced, then it may be difficult to spot, and with more devastating results.A lot of the work on this project went into trying to grasp some strange modelbehaviours which eventually turned out to be due to this following programmingbug.

This code excerpt is from the medication_t record type’s medication specifications:

...) or ( // Escumycin

act_code=J01FA01 and // <-- FORGOTTEN LINEindications[0]="Bacterial infection of unspecified site" and

...

I had forgotten a rule connecting medications with ACT code J01FA01 (a classof antibiotics) with a certain set of indications/contramedications. I haven’t ana-lyzed the logical consequence of this, but the model viewer kept presenting strangemodels which seemed to break rules which I then—needlessly—tried to refactor.

4.6 Long compilation times

As mentioned on page 14, my code contains a lot of seemingly redundant state-ments likeindications[1]=no_diagnosis

The reason for this is that otherwise compilation times were unacceptable, due tofactors which are not entirely clear to me, although they seem to be related to howPML’s arrays are handled by the compiler.

16

Annotated example code excerpt, from the rule set of the medication_t record type:

) or (act_code=no_medication andindications[0]=no_diagnosis andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis and // aindications[4]=no_diagnosis and // bcontra_indications[0]=no_diagnosis andcontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis and // ccontra_indications[6]=no_diagnosis and // dcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication

)

In the following compilation benchmarks, I have added the “-v” flag to the pmccompiler. This brings the compiler into a verbose mode where the compiler notifiesabout the different stages it goes through, and—most importantly—seems to printout the amount of memory used to hold the model. An example compile sessionwith this flag:

Loading filters from configit_filter.dllStatic semantically checking project ’medications.pm’Expanding database declarationsChecking rulesInitializing virtual tableBuilding virtual tableBuilding variable domain rulesBuilding product model rulesGarbage collection #1: 2895/4096 KBGarbage collection #2: 2108/4096 KBGarbage collection #3: 2261/4096 KBGarbage collection #4: 1124/4096 KBGarbage collection #5: 0/4096 KBGarbage collection #6: 1651/8192 KBConjoining rulesGarbage collection #7: 4111/12288 KBWarning: Rules block value ’Hismanal’ for variable ’prescriptions[0].name’Warning: Rules block value ’Prepulsid’ for variable ’prescriptions[0].name’Warning: Rules block value ’Teldanex’ for variable ’prescriptions[0].name’Warning: Rules block value ’Hismanal’ for variable ’prescriptions[1].name’Warning: Rules block value ’Prepulsid’ for variable ’prescriptions[1].name’Warning: Rules block value ’Teldanex’ for variable ’prescriptions[1].name’Warning: Rules block value ’Hismanal’ for variable ’allergic\_to[0].name’Warning: Rules block value ’Prepulsid’ for variable ’allergic\_to[0].name’Warning: Rules block value ’Teldanex’ for variable ’allergic\_to[0].name’Warning: Rules block value ’Hismanal’ for variable ’allergic\_to[1].name’Warning: Rules block value ’Prepulsid’ for variable ’allergic\_to[1].name’Warning: Rules block value ’Teldanex’ for variable ’allergic\_to[1].name’Success: medications.vt (50.5 Kb) successfully generatedVirtual table contains -1 solutions

(The compiler concludes by stating that “-1” solutions exist; this must be a

17

compiler bug, as the model certainly seemed to contain all expected solutions, andthe Product Model Viewer reports 2828888 possible solutions.)

My interpretation of the output is that the compiler’s highest use of memory forthe model was approximately 12MB of memory. This interpretation was verifiedby monitering the resident set size of the compiler process.

I executed the compiler via the GNU time tool[10], recording the CPU timespent in user space during the execution of pmc. Compilation was done on a PCfeaturing a 1.8GHz Pentium 4 processor and 340MB of RAM. The following ob-servations were made:

• In general: During compilation, most time was spent in the compiler’s ruleconjunction phase. Memory use seemed to be somewhat proportional tocompile times. Memory use would rise in the initial phase of a compilation,and then reach a steady state.

• When making no changes to the code, compilation time was 24s, and themaximal memory consumption was 12MB.

• When removing the code line marked “b”, compilation time went to 305s,and memory consumption rose to 40MB.

• When removing both lines a and b, compilation took 298s, and memoryconsumption peaked at 41MB.

• When removing lines a, b, and d, compile time was 336s; memory consump-tion: 53MB.

• When removing lines a, b, c, and d, compile time was 336s; memory con-sumption: 53MB.

• When removing all the above lines except for act_code=no_medication, com-pilation never seemed to end, and memory consumption rose to a level whichmade the computer thrash, i.e. spend nearly all time waiting for disk paging.

In other words: If a rule does not explicitly assign values to all array elements,then compile time rises. Leaving out additional elements of an incomplete arraydoesn’t add to the increased compile time.

The numbers suggest that if the compiler sees an array which might be incom-plete, then it handles the array in a significantly less efficient way. My guess isthat if an array is incompletely defined, then it is implicitly turned into a two-levelnested array where values are stored along with a flag telling if the array elementhas been set or not.10 I believe it’s plausible that adding an array dimension makesthe solution space widen drastically—a combinatorical explosion.

10This correponds to an early version of the code where most of the arrays consisted an optionaltypes, see the ConfigIt Developer manual[8]; in the early version, I experienced ever-lasting compilesessions, as well.

18

5 Conclusions

In my work with PML and the product viewer, my most pleasing experiences wereformulating the logical rules—employing quantifiers, negations, etc. to expressthe domain knowledge. Identifying relevant domain knowledge and constraintswas also a rewarding task. As such, I think that I have reached the most importantgoal of this project, namely learning how to use a logical programming languageto express a problem domain.

I chose to try to map diagnoses to ICD-10 defined terms, and I used a mappingof medication names to the discrete set of ACT codes. That way, I forced myselfto consider at least some of the challenges which would occur if a model like theone described were to be integrated into a larger medical information system.

Unfortunately, I spent hours and hours debugging and trying new, esoteric waysto try to make the compiler succeed, or to make the model behave as expected.Such experiences aren’t uncommon when learning a new programming environ-ment, however. The most important impact was that the final size of the model israther limited. A more elaborate model would probably have revealed additional,interesting findings.

Resulting model query times were fully acceptable, proving the value of virtualtabulation of a precompiled solution space. —But even after spending a lot of timetweaking the code to make it compile well, compilation times were still ratherhigh, considering the small size of the model. Hence, I wouldn’t take on the taskof implementing a real-World system based on the described technologies, unlessmore complete prototyping were successfully done in advance.

19

References

[1] ConfigIt Software, http://ConfigIt.dk/

[2] World Health Organization Collaborating Centre in Oslo: About theATC/DDD system, http://www.whocc.no/atcddd/

[3] Dansk Lægemiddel Information: Lægemiddel kataloget (1997)

[4] World Health Organization’s ICD-10 entry page athttp://www.who.int/whosis/icd10/

[5] KITH & Sosial- og helsedirektoratet: Elektronisk søkeverktøy ICD-10,http://www.odont.uio.no/allmennodontologi-voksen/ICD10SOK/icd10.htm

[6] Home page of the US National Center for Health Statistics,http://www.cdc.gov/nchs/about/otheract/icd9/icd10cm.htm

[7] Møller J, Andersen H R, Hulgaard H: Product Configuration over the Inter-net, paper for the 6th INFORMS Conference on Information Systems andTechnology (CIST-2001). Available as http://configit.dk/docs/cist2001.pdf

[8] ConfigIt Software: Developing Product Models. Manual distributed with theConfigIt Developer software package; not publicly available.

[9] Henrik Reif Andersen: An Introduction to Binary Decision Diagrams, lecturenotes (1997). Available at http://www.itu.dk/people/hra/notes-index.html

[10] Free Software Foundation: http://www.gnu.org/software/time/

20

A Appendix: Example medication description

Quoting from [3]:

Aldomet R© MSD, Methyldopa C02AB01Antihypertensivum.Omtalt i afsnittet Antihypertensiva, methyldopa.Dispenseres i form aftabletter a 250 mg (mrk. MSD 401 - ALDOMET) eller 500 mg (mrk. MSD 516- ALDOMET) methyldopa. Tilsat farve: Jernoxider og jernhydroxider E172 (tabl.250 mg og 500 mg) og Quinolingult E104 (tabl. 250 mg og 500 mg).Farmakokinetik. Se Antihypertensiva, methyldopa.Indikationer. Ss. reg. ind.: "Arteriel hypertension".DoseringsforslagInitialt 250 mg 2 gange dgl., øges under hensyn til opnået virkning med nogledages mellemrum med 250 mg ad gangen til maksimalt 500 mg 4 gange dgl. 80-90% af den antihypertensive effekt opnås med 1 g i døgnet.Graviditet. Kan anvendes, se Antihypertensiva, methyldopa.Amning. Udskilles kun i ringe grad i modermælk.Kontraindikationer. Leverlidelser, fæokromocytom.Forsigtighedsregler. Bør anvendes med forsigtighed ved nedsat nyrefunktion.Bivirkninger. Sedation. Sjældnere depression, dyspepsi og diarré. Drug fever ses.Se endvidere Antihypertensiva, methyldopa.Forgiftning. Se Antihypertensiva, methyldopa.Interaktioner. Se Antihypertensiva, methyldopa.Udlv BPakninger og priser...

21

B Appendix: Example ICD-10 tables

Excerpt from [6]:

Hypertensive diseases (I10-I15)Use additional code to identify:

exposure to environmental tobacco smoke (Z58.83)indent history of tobacco use (Z86.43)indent occupational exposure to environmental tobacco smoke (Z57.31)tobacco dependence (F17.-)tobacco use (Z72.0)

Excludes1:hypertensive disease complicating pregnancy, childbirth and the puerperium (O10-O11, O13-O16)neonatal hypertension (P29.2)pulmonary hypertension (I27.0)

I10 Essential (primary) hypertensionIncludes:

high blood pressurehypertension (arterial) (benign) (essential) (malignant) (primary) (systemic)

Excludes1:hypertensive disease complicating pregnancy, childbirth and the puerperium (O10-O11, O13-O16)

Excludes2:essential (primary) hypertension involving vessels of brain (I60-I69)essential (primary) hypertension involving vessels of eye (H35.0)

22

C Appendix: Code

The produced code follows (from a file named medications.pm):

/** Objective:* Given personal information and diagnosis, offer intelligent medication* form which excludes irrelevant and illegal prescriptions.** Warnings and precautions are ignored (the user should check* detailed medication description after having used this tool* to decide possible prescriptions).*/

/*Assumptions:- Medications with the same ACT code are similar enoughto have similar indications, contra-indications, and"contra-medications" (medical incompatibilities).

- However, medications with the same ACT code may bejust different enough to have different allergy profilesfor a given person.

Code strangeness:- The code if full of seemingly useless "indications[1]=no_diagnosis"subrules. However, without them, the ConfigIt compilerseems to run forever.

Room for improvement:- Co-indications, see comments in ruleset for Escumycin.- "History of" semantics, see comment in ruleset for Halotan.- Specific medications should somehow be specializations ofmedication types.

- Groups of ICD codes.

- Perhaps: "Should not" semantics.*/

constantNUM_INDICATIONS: 5;NUM_CONTRA_INDICATIONS: 7;NUM_CONTRA_MEDICATIONS: 3;NUM_DIAGNOSIS: 2;NUM_ALLERGIES: 2;NUM_PRESCRIPTIONS: 2;

// An ’active’ medication means a medication which is not// only here to express a medication conflict. These medications// have registered indications.NUM_ACTIVE_MEDICATIONS: 9;

type// Code after comment is ICD code.// ICD is the disease code specified by WHO’s International Statistical// Classification of Diseases and Related Health Problems.// I’ve tried sticking to ICD-specified health states; that makes// this application a bit clumbsy, but I think that something// like that would be interesting in a real-World setting where// integration with other information systems would probably be// more safe if based on a fixed set of possible diagnosis.// Problems with the approach:// - some medications give broad contra-indications which

23

// are not really accounted for well here// - some relevant medical states like "need of universal// anesthesia" (for an operation curing another health// state) don’t exist in ICD10.// Room for improvement: Really use ICD10 codes internally,// exposing only the names in the user interface context;// would require another set of rules mapping codes and// labels. I did that initially, then switched, and didn’t// have time to revert.// Sorted by ICD code, then lexicographically.diagnosis_t : ["Bacterial infection of unspecified site", // A49Thyrotoxicosis, // E05"Alcohol abuse with intoxication", // F10.12"Other anxiety disorders", // F41"Essential tremor", // G25.0"Reumatic mitralstenosis with insufficy or regurgitation", // I05.2"Essential hypertension", //I10"Essential hypertension with lung stasis", // I11.0"Essential hypertension without lung stasis", // I11.1"Non-reumatic mitralstenosis", // I34.2"Aortastenosis with insufficiency", // I35.2"Obstructive hypertrofic cardiomyopathy", // I42.1"Other hypertrofic cardiomyopathy", // I42.2"Atrioventricular block, second degree", // I44.1"Atrioventricular block, total", // I44.2"Hypotension", // I95"Other cronical obstructive lung disease", // J44Asthma, // J45"Alcoholic liver disease", // K70"Toxic liver disease", // K71"Hepatic failure, not elsewhere classified", // K72"Chronic hepatitis, not elsewhere classified", // K73"Fibrosis and cirrhosis of liver", // K74"Other inflammatory liver diseases", // K75"Other diseases of liver", //K76"Fever, unspecified", // R50.9"Cardiogenic shock", // R57.0"Angioneurotic oedama", // T78.3"Allergy status to penicillin", // Z88.0"Need for universal anesthesia", // to make Halotan an option"Bad breath", // dummy, for testsno_diagnosis

];

// Medication type ID, as defined in the// Anatomical Therapeutic Chemical (ACT) Classification System.act_code_t: [A03FA02, // PrepulsidC02AB01, // AldometC07AA05, // Frekven, Propranet, Propranolol DAK, Propranolol NMC07AA16, // ArtexalC09AA02, // AlacorC09AA03, // LisinoprilC09CA01, // CozaarJ01FA01, // For test purposis: an antibiotic, EscumycinN01AB01, // Halotan Halocarbon, Halothane TrofieldN05BA12, // AlproxR06AX11, // HismanalR06AX12, // Teldanexno_medication

];

24

// Some medications may have different brand names. Later,// ACT codes are mapped to brand names.medication_name_t: [Artexal,Alacor,Aldomet,Alprox,Cozaar,Escumycin,Frekven,Lisinopril,"Halotan Halocarbon",Hismanal,Prepulsid,Propranet,"Propranolol DAK","Propranolol NM",Teldanex,"No medication"

];

medication_t: {name: medication_name_t;

private act_code: act_code_t;private indications: array NUM_INDICATIONS of diagnosis_t;private contra_indications: array NUM_CONTRA_INDICATIONS of diagnosis_t;private contra_medications: array NUM_CONTRA_MEDICATIONS of act_code_t;private ok_for_kids: boolean;private ok_for_preg: boolean;private ok_for_lact: boolean;

rule

// Ordered by name#define mk_medication(n,a) (if name=n then act_code=a)mk_medication(Alacor,C09AA02);mk_medication(Aldomet,C02AB01);mk_medication(Alprox,N05BA12);mk_medication(Artexal,C07AA16);mk_medication(Cozaar,C09CA01);mk_medication(Escumycin,J01FA01);mk_medication(Frekven,C07AA05);mk_medication("Halotan Halocarbon",N01AB01);mk_medication(Hismanal,R06AX11);mk_medication(Lisinopril,C09AA03);mk_medication(Prepulsid,A03FA02);mk_medication(Propranet,C07AA05);mk_medication("Propranolol DAK",C07AA05);mk_medication("Propranolol NM",C07AA05);mk_medication(Teldanex,R06AX12);mk_medication("No medication",no_medication);

// Medical properties. Ordered by ACT code.// BEGIN medication specifications( // Aldomet

act_code=C02AB01 andindications[0]="Essential hypertension" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis and

25

indications[4]=no_diagnosis andcontra_indications[0]="Alcoholic liver disease" andcontra_indications[1]="Toxic liver disease" andcontra_indications[2]="Hepatic failure, not elsewhere classified" andcontra_indications[3]="Chronic hepatitis, not elsewhere classified" andcontra_indications[4]="Fibrosis and cirrhosis of liver" andcontra_indications[5]="Other inflammatory liver diseases" andcontra_indications[6]="Other diseases of liver" and// Missing contraindication: "fæokromocytom"(?).contra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_lact=true andok_for_preg=true

) or ( // Propranet, et alact_code=C07AA05 andindications[0]="Essential hypertension" andindications[1]=Thyrotoxicosis andindications[2]="Essential tremor" andindications[3]=no_diagnosis andindications[4]=no_diagnosis and// not-expressed indications:// - artytmier// - protylactic treatment of angina pectoris/migræne//contra_indications[0]=Hypotension andcontra_indications[1]=Asthma andcontra_indications[2]="Other cronical obstructive lung disease" andcontra_indications[3]="Cardiogenic shock" andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=N01AB01 andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication//Missing:// - bradicardia// - untreated heart insufficiency// - blocks

) or ( // Artexalact_code=C07AA16 andindications[0]="Essential hypertension" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]="Obstructive hypertrofic cardiomyopathy" andcontra_indications[1]="Other hypertrofic cardiomyopathy" andcontra_indications[2]=Hypotension andcontra_indications[3]="Other cronical obstructive lung disease" andcontra_indications[4]="Reumatic mitralstenosis with insufficy or regurgitation" andcontra_indications[5]="Non-reumatic mitralstenosis" andcontra_indications[6]="Aortastenosis with insufficiency" andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_preg=false andok_for_lact=false

) or ( // Alacoract_code=C09AA02 andindications[0]="Essential hypertension" andindications[1]="Essential hypertension with lung stasis" and

26

indications[2]="Essential hypertension without lung stasis" andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]="Angioneurotic oedama" andcontra_indications[1]="Reumatic mitralstenosis with insufficy or regurgitation" andcontra_indications[2]="Aortastenosis with insufficiency" andcontra_indications[3]="Obstructive hypertrofic cardiomyopathy" andcontra_indications[4]="Other hypertrofic cardiomyopathy" andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_kids=false andok_for_preg=false andok_for_lact=false// missing contra-indications:// - Bilateral nyrearteriestenose eller unilateral// nyrearteriestenose hos patienter med kun én nyre.// - Prior side effects of medication type.

) or ( // Lisinoprilact_code=C09AA03 andindications[0]="Essential hypertension" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]="Non-reumatic mitralstenosis" andcontra_indications[1]="Aortastenosis with insufficiency" andcontra_indications[2]="Obstructive hypertrofic cardiomyopathy" andcontra_indications[3]="Angioneurotic oedama" andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_kids=false andok_for_preg=false andok_for_lact=false

) or ( // Cozaaract_code=C09CA01 andindications[0]="Essential hypertension" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]=no_diagnosis andcontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication andok_for_preg=false// WOULD-BE-NICE:// warning about lactation// warning: No knowledge about treatment of children

) or ( // Escumycin

27

act_code=J01FA01 andindications[0]="Bacterial infection of unspecified site" and// Room for improvement: Make ’co-indications’ possible, i.e.// penicillin allergy doesn’t mean by itself that Escumycin must// be used. Would be nice:// co_indications[1]="Allergy status to penicillin"indications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]=no_diagnosis andcontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=R06AX11 andcontra_medications[1]=A03FA02 andcontra_medications[2]=R06AX12 andok_for_lact=true andok_for_preg=true andok_for_kids=true

) or ( // Halothane, an anesthesicact_code=N01AB01 andindications[0]="Need for universal anesthesia" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]=no_diagnosis andcontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication// Missing contraindications:// _History_ of hyperthermia due to halogenated// anesthesia.

) or ( // Alproxact_code=N05BA12 andindications[0]="Other anxiety disorders" andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]="Alcohol abuse with intoxication" and// Todo: Find diagnosis for toxic state due to tranqualizercontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication

) or (

28

act_code=no_medication andindications[0]=no_diagnosis andindications[1]=no_diagnosis andindications[2]=no_diagnosis andindications[3]=no_diagnosis andindications[4]=no_diagnosis andcontra_indications[0]=no_diagnosis andcontra_indications[1]=no_diagnosis andcontra_indications[2]=no_diagnosis andcontra_indications[3]=no_diagnosis andcontra_indications[4]=no_diagnosis andcontra_indications[5]=no_diagnosis andcontra_indications[6]=no_diagnosis andcontra_medications[0]=no_medication andcontra_medications[1]=no_medication andcontra_medications[2]=no_medication

);// END medication specifications

};

variablepregnant: boolean;lactating: boolean;is_child: boolean;diagnosis: array NUM_DIAGNOSIS of diagnosis_t;prescriptions: array NUM_PRESCRIPTIONS of medication_t;allergic_to: array NUM_ALLERGIES of medication_t;

private active_medications: array NUM_ACTIVE_MEDICATIONS of medication_t;

rule// Seems redundant, but the ConfigIt tool doesn’t seem to allow me to// run through known medication_t.act_code values.// For meaning of this: See comment for NUM_ACTIVE_MEDICATION_NAMES// in start of file.active_medications[0].act_code=C02AB01;active_medications[1].act_code=C07AA05;active_medications[2].act_code=C07AA16;active_medications[3].act_code=C09AA02;active_medications[4].act_code=C09AA03;active_medications[5].act_code=C09CA01;active_medications[6].act_code=J01FA01;active_medications[7].act_code=N01AB01;active_medications[8].act_code=N05BA12;// The number of above rules should match NUM_ACTIVE_MEDICATIONS.

// If a medication is not to be used by kids, then the person// must not be a child.if is_child then not exist p in [0..NUM_PRESCRIPTIONS-1]: (not prescriptions[p].ok_for_kids

);

// If a medication is not to be used by breast-feeding women,// then the person must not be breast-feeding.if lactating then not exist p in [0..NUM_PRESCRIPTIONS-1]: (not prescriptions[p].ok_for_lact

);

// If a medication is not to be used by pregnant women,// then the person must not be pregnant.if pregnant then not exist p in [0..NUM_PRESCRIPTIONS-1]: (not prescriptions[p].ok_for_preg

29

);

// A child cannot be breast feeding or be pregnantif is_child then not (pregnant or lactating);

// Note: A woman may actually be both pregnant and breast feeding.

// A person cannot both have hyper- and hypo- tension.not exist i in [0..NUM_DIAGNOSIS-1]: (exist j in [0..NUM_DIAGNOSIS-1]: (

(diagnosis[i]="Essential hypertension" ordiagnosis[i]="Essential hypertension with lung stasis" ordiagnosis[i]="Essential hypertension without lung stasis"

) and diagnosis[j]="Hypotension")

);

// All prescriptions must be there for a reason:// They must match an indication in a prescription.forall p in [0..NUM_PRESCRIPTIONS-1]: (if prescriptions[p].act_code<>no_medicationthen exist i in [0..NUM_INDICATIONS-1]: (

prescriptions[p].indications[i]<>no_diagnosisand exist d in [0..NUM_DIAGNOSIS-1]: (

prescriptions[p].indications[i]=diagnosis[d])

));

// No prescription’s contraindications// may match an existing diagnosis.not exist p in [0..NUM_PRESCRIPTIONS-1]: (exist c in [0..NUM_CONTRA_INDICATIONS-1]: (

prescriptions[p].contra_indications[c]<>no_diagnosisandexist d in [0..NUM_DIAGNOSIS-1]: (

prescriptions[p].contra_indications[c]=diagnosis[d])

));

// A person cannot have several diagnosis of the same value.// Implicitly: A person must have at least one diagnosis.not exist d in [0..NUM_DIAGNOSIS-1]: (exist dd in [0..NUM_DIAGNOSIS-1]: (

diagnosis[d]=diagnosis[dd]and d<>dd

));

// If a relevant medication exists for the diagnosis,// then the patient must be prescribed at least one of these.// In other words: We can not have a diagnosis for which// an indicated medication is known, but where the// medication is not among the chosen prescriptions.forall d in [0..NUM_DIAGNOSIS-1]: (if diagnosis[d]<>no_diagnosisthen (

if exist m in [0..NUM_ACTIVE_MEDICATIONS-1]: (exist i in [0..NUM_INDICATIONS-1]: (

30

active_medications[m].indications[i]=diagnosis[d])

)then exist p in [0..NUM_PRESCRIPTIONS-1]: (

// redundant (compiler hint):prescriptions[p].act_code<>no_medication

and

exist i in [0..NUM_INDICATIONS-1]: (prescriptions[p].indications[i]=diagnosis[d]

))

));

// A person cannot take the same medication brand twice,// and a prescription may not be one which the patient// is allergic to.not exist p in [0..NUM_PRESCRIPTIONS-1]: (prescriptions[p].act_code<>no_medicationand (

exist pp in [0..NUM_PRESCRIPTIONS-1]: (prescriptions[p].name=prescriptions[pp].nameandp<>pp

) or exist a in [0..NUM_ALLERGIES-1]: (prescriptions[p].name=allergic_to[a].name

))

);

// A patient cannot be allergic to the same medication brand twice.not exist a in [0..NUM_ALLERGIES-1]: (allergic_to[a].act_code<>no_medicationandexist aa in [0..NUM_ALLERGIES-1]: (

allergic_to[a].name=allergic_to[aa].nameanda<>aa

));

// Make sure that a all prescriptions doesn’t conflict with// another medication (medication incompatibility).forall p in [0..NUM_PRESCRIPTIONS-1]: (if prescriptions[p].act_code<>no_medicationthen

not exist pp in [0..NUM_PRESCRIPTIONS-1]: (exist c in [0..NUM_CONTRA_MEDICATIONS-1]: (prescriptions[pp].contra_medications[c]=

prescriptions[p].act_code)

));

/* vim: set expandtab softtabstop=2 tabstop=2 shiftwidth=2: *//* $Id: medications.pm,v 1.6 2004/06/21 19:57:55 troels Exp $ */

31