Customer Stories

Products and ServicesNews and Mailing ListsCustomer StoriesArticles and  LinksSupport and ForumsSearch and Site MapDownload and BuyContact and About


Education & Government




Office Practicum
Ensures Timely and Correct Vaccinations
with Amzi! and Delphi

Visual 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 expect.

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 application.

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

Visual 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 virus vaccination.

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 units.

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 modules.

Reasoning Engine

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.)

status :-
   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.

output('M-M-R', [
   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.`]]).

Cost Benefit

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.

Future Plans

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.