Ensures Timely and Correct Vaccinations
with Amzi! and Delphi
Data LLC provides a Windows software product called Office Practicum for
pediatrician's offices. It keeps medical records for patients and performs
all of the "data" and "processing" functions you might
One of the items it tracks for a patient is vaccination history. It turns
out that one of the problems for a pediatrician is following all of the
complex rules and regulations for vaccinations, and scheduling children
for future appointments based on their vaccination needs.
Customers asked Visual Data to provide a feature in Office Practicum
that would tell what vaccinations were up-to-date for a child on a visit,
and which were due. It should also be able to provide reports on each
child analyzing their vaccination histories, making sure they were in
compliance with regulations for schools and summer camps. This took Visual
Data into the realm of encoding logical knowledge. The knowledge about
vaccinations is published in papers made available by the CDC. Each vaccine
has one or more schedules of doses, based on the particular type of vaccine,
and each has numerous exception rules that describe conditions when a
vaccination may or may not be given.
There are a number of interesting observations to be made about this
Data and Process First, then Logic
The first relates to the Stanford comment about AI in medicine, which
was that AI had not advanced due to the lack of data. They observed that
AI is really the encoding of logical relationships, but, without entities
for the logical knowledge to reason over, there is no practical value
in automating the logic. The vaccination program illustrates this.
People in the past have worked on AI systems to automate vaccination
logic, but the patient data on vaccination history was not readily available.
It had to be typed in by hand as input to the system in order to get a
vaccination schedule. However, any medical practitioner experienced in
vaccinations could figure out the schedule directly from the data in about
the same time without having to engage a computer in the process. So there
wasn't much point.
Office Practicum provides enough help in the day-to-day business of running
a pediatricians office to make the data collection on patient histories
comes naturally. Because that data is in the computer, and because the
office is already using the computer for other aspects of managing the
patient, it now makes sense to automate the logical knowledge for vaccination
scheduling. In fact, it was the customers who started to ask for this
feature, after using the software. They noted that all the vaccination
information was in the computer, so why couldn't it automatically generate
the vaccination schedules.
Procedural Code Works, but is Impractical
Data first attacked the problem by attempting to encode the vaccination
logic using procedural code. In their case the application is developed
in Borland's Delphi, and they used Pascal for the encoding. The software
worked, but was difficult to write, and was in a large complex module,
and only provided some of the features they wanted to provide.
However, the world of vaccines kept changing. New vaccines were coming
out that combined earlier vaccines in a single vaccination with new more
complex rules about the interactions between the components. Customers
wanted to know when the software would support Pediatrix, a new complex
multi-disease vaccine. The software developers groaned.
While they were a Delphi shop, and familiar with Delphi, and would love
to do all their work in Delphi, they realized the vaccination module was
just too difficult to maintain, so they opted for a logic base solution.
The logic base reduced the code size from thousands of lines of code to
hundreds of lines of easily understandable rules. It was the same 10:1
ratio seen so many times for these applications.
Further, the rules were now in a format that their resident pediatrician,
not a programmer, could understand. The application was restructured so
that the Delphi code called the logic base, much the same way it called
the database. The "knowledge" of vaccination scheduling was
now completely outside of the core Delphi code. The logic base can be
updated without affecting the main application, just as the database can
be updated without changing the application.
Unlike the database, the logic base must be tested, and Office Practicum
uses a tool set to independently test the rules. Regression tests are
a part of the system, so that various scenarios can be automatically retested
when changes are made to the logic base.
The Nature of Vaccine Logical Knowledge
Visual Data did not use an off-the-shelf rule engine for a couple of
reasons. One was cost, but more important, the logical knowledge of vaccines
seemed to require its own specific set of ways to represent knowledge.
Here are the types of logical knowledge expressed in the vaccination documents.
First there are definitions, such as the fact that there are two types
of Hib vaccines, those that contain PRP-OMP and those that don't. A different
schedule is used for each. There are also many brands of Hib vaccines,
and many abbreviations doctors use for a Hib vaccine. It is important
to know for each whether it contains PRP-OMP or not.
Another critical fact to know about a vaccine is if it contains live
virus or not. There are rules concerned with the spacing of such vaccines.
Additionally, there are multi-vaccine products, such as a combined measles,
mumps and rubella (MMR) vaccine. There are rules that are just concerned
with, for example, whether or not a child had a measles vaccine, but the
database might indicate MMR.
Standard tables provide the minimum age, recommended age, and minimum
spacing interval for each dose of a vaccine. If this was all there was
to the vaccination logic, then a database solution or other table lookup
would have worked, although even the tables aren't that simple. For a
given vaccine, different tables apply depending on factors such as whether
it is a multi-vaccine, what the active components are, and whether or
not the child has followed a standard schedule.
For example, Hib has multiple tables based on when the series of Hib
vaccinations is started.
Finally, there are the rules. The rules work in concert with the definitions
and the tables. They are used to determine which table is appropriate
in a given situation. They also provide coverage for all the exception
cases, such as the fact that a given vaccine isn't necessary after a certain
age, or that a schedule can't be kept if other live virus vaccines have
been given, or what the corrective measures are if a previous vaccine
was given earlier than allowed.
A Custom Solution Provides for All Three
While all of this information could be stored in rules, some of the visual
clarity of the mapping from documentation to logic base would be lost.
It would be better if the logic base more readily expressed the definitions.
Accordingly the knowledge representation language for the vaccination
system was designed to have
- An ontology of terms to store definitions.
- A means of entering tabular knowledge.
- A means of entering rules.
This made it easy to add new definitions without affecting the rules,
allowed for the direct encoding of the basic tables, and enabled the rules
to refer to the tables and reason with concepts such as the last live
It is the ontology that lets that type of rule use the term 'live virus,'
when the actual data is composed of dates and specific vaccine names used
by the office staff. The ontology was also the key to dealing with vaccines
that covered multiple diseases. If a rule needed to refer to the last
measles vaccination, yet the data referred to MMR, the ontology would
recognize that MMR was a kind of measles vaccine.
Date and Sequence Reasoning
There was another wrinkle in the vaccination logic. Almost all of the
rules and tables used date intervals and ages, in any of the units: year,
month, week, or day. For example, the minimum age for the second dose
of Hib (without PRP-OMP) is 10 weeks, the minimum spacing from the previous
Hib vaccination is 4 weeks, and the recommended age is 4 months. Notice
that this requires being able to work with the child's age in weeks and
months, and to be able measure the spacing between vaccinations in weeks.
There is no consistency in the tables, and each can use any of the date
The database, as you might expect, contains the actual dates when past
vaccinations were given and the date of birth.
The ability to reason and manipulate dates, ages and date intervals,
as required, is not a common feature in commercial rule languages. In
the Delphi code they had converted everything to days, but this created
problems for practitioners when a vaccine was allowed four months later
but Jan 15th plus four months didn't produce the result May 15th. It also
made the code more obtuse to read and understand.
So the rule language for the vaccination system was designed to have
full knowledge of various date entities and how to manipulate them. A
rule could directly reference an entity such as: vaccination(last, measles)
< 1 years, and the system would look at the last vaccination, get its
date, and know "1 years" meant an age, which it would convert
to a date so the comparison could be made.
The rules could then express concepts such as:
The minimum date for the next measles vaccination is the maximum of
either the birth date plus the minimum age from the table or the date
of the last live virus vaccination plus four weeks.
This highlights another need for customization. Sequences of vaccinations
are key, so the system needed an easy way to refer to the first vaccination
or last, or count the number of vaccinations. Again, the language was
designed to make it easy to express and reason over sequences of events.
Modularization was a key requirement for this application. The tables
and rules for each vaccine were kept in separate modules. The ontology,
on the other hand, was in a common module as it was used by all the other
The reasoning engine for the vaccine logic base is designed to meet a
variety of application needs. It takes as input the vaccination history
of a child and then goes to the module for each vaccine in question and
gets the status information for that vaccine. This includes an analysis
of the past vaccinations with that vaccine; the status as of today, the
current office visit; and the recommended range and minimum dates for
the next vaccination with that vaccine.
Each module is designed with the same goal and output, and that goal
is called by the reasoning engine. This allows for the easy addition of
different vaccines, and the easy maintenance of any particular vaccine.
The reasoning engine has an application program interface (API) that
is used by the calling application. The API provides the various reports
required for different uses. For example, it can tell what vaccines need
to be given on the day of an office visit, or what vaccines will be needed
for scheduling a follow-up visit. It also allows for short and verbose
reporting and explanations of the recommendations, and provides the historical
analysis reporting required for camp and school forms.
Text File Logic Base
The first version of the Vaccine logic base uses a text file for the
rules. The rules are based on the Prolog syntax which allowed for quick
implementation of the knowledge representation language, as well as providing
a full test and debugging framework for the logic base.
Future plans include a more free form syntax and GUI editing tools. Here
are some examples of the various elements of the logic base.
Here are the entries indicating Varicella and Small Pox are live viruses;
the three elements of the new Pediarix vaccine; various spellings of Hib;
and some of the PRP-OMP flavors of Hib. This is a 'is-a' hierarchy of
terms, so a rule referring to Hib will correctly match the vaccine PedvaxHIB,
because it 'is-a' PRP-OMP, and PRP-OMP 'is-a' Hib.
live_virus ->> 'Varicella'.
live_virus ->> 'Small Pox'.
'DTaP-HepB-IPV+' ->> 'Pediarix(tm)'.
'Hib' ->> 'HbOC'.
'Hib' ->> 'PRP-OMP'.
'Hib' ->> 'PRP-T'.
'PRP-OMP' ->> 'PRP-OMP & Hep B'.
'PRP-OMP' ->> 'PedvaxHIB(TM)'.
'PRP-OMP' ->> 'HIB-OMP'.
The vaccine logic base is used to report on vaccines that can be given
at a given visit, and to forecast vaccines needed in the future. There
is both a minimum and recommended age for the forecast vaccines. These
are reflected in the table entries that provide for the minimum age of
a dose, the minimum separation required from the previous dose, and the
recommended age for a dose.
Here's the table in the Hib module for Hib vaccines that contain PRP-OMP.
table('Recommended B', [
% Recommended Schedule B from 'DHS Hib 2003Mar' for vaccines
% containing PRP-OMP
% Dose Minimum Minimum Recommended
% Age Spacing Age
[ 1, 6 weeks, none, 2 months ],
[ 2, 10 weeks, 4 weeks, 4 months ],
[ 3, 12 months, 8 weeks, 15 months ] ]).
The rules use patterns in the data to determine the status of a particular
vaccination, deciding whether or not to use a table and how to qualify
the results from the table if necessary.
Here's a status rule in the Hib module that defers to late_start_status
rules if the child has had 2 valid Hib vaccines and the second one was
given after 7 months of age. (Other rules will have previously examined
the past history and determined which vaccines were given at valid times.)
valid_count('Hib') gte 2,
vaccination(2, 'Hib') *>= 7 months,
A rule that generates output usually has three parts: the conditions
under which the rule applies; the calculations for status and dates; the
storing of key information about the vaccine.
For example, a rule in the MMR module has:
Conditions - There have been measles vaccinations and there have
been more than one live virus vaccination given.
valid_count('Measles') eq Count,
valid_count(live_virus) gt 0,
Calculations - The next dose is one more than the current count
and the table of MMWR recommendations is used to get the minimum age and
recommended age for the next vaccination. The actual dates are based on
either the table recommendations or the separation from the last live
virus vaccination, which ever is greater. The status for today is calculated
based on those dates, using a utility that is part of the reasoning engine.
NextDose is Count + 1,
get_row('M-M-R':'MMWR Recommended', [NextDose, MinAge, _, RecAge, _]),
MinDate *= maximum( vaccination(last,live_virus) + 4 weeks,
birthday + MinAge),
RecDate1 *= maximum( vaccination(last,live_virus) + 4 weeks,
birthday + lower(RecAge)),
RecDate2 *= maximum( vaccination(last,live_virus) + 4 weeks,
birthday + upper(RecAge)),
calc_status(MinDate, RecDate1, RecDate2, Status),
Output - The dates, the status, the citation and verbose explanation.
dose = NextDose,
dates = [MinDate, RecDate1, RecDate2],
rec_info = RecAge,
status = Status,
citation = 'MMWR 2002Feb08',
note = [
`Next dose based on standard schedule, guaranteeing at `,
`least 4 weeks separation from last live virus vaccination.`]]).
The benefits from the logic base approach has been:
- a 90% reduction in code used for vaccine logic rules,
- direct access to the knowledge by the in-house pediatrician,
- localization of all the vaccine logic, which used to be scattered
in the different parts of the application with different needs,
- easy maintenance, and quality assurance testing, and
- additional capabilities that were too hard to encode before, such
as the complete analysis of past vaccination history and support for
new multi-vaccine products.
All of these benefits add up to the one major benefit, which is that
their software now provides better services for their customers in this
area which is critically important in the running of a pediatric office.
The costs were:
- time spent investigating and learning about various alternative approaches
for encoding the vaccination logic,
- software license fees,
- two month's development time, and
- time spent learning the new technology.
The calendar time for the project was:
- January - start study of alternative approaches,
- March - begin application development,
- June - deploy to the field.
The development environment provides tools for testing and debugging
the logic base, but uses text files for the various modules. The structure
of the various logical knowledge entities would map nicely to a graphical
development environment, and this is planned as a future project.
Now that the logic base is a separate unit, it can be deployed and used
in different contexts. Visual Data is considering offering the history
analysis portions of the vaccine logic base on the Web using a .NET architecture.