Categories
Medicine

Anemia diagnosis with a forward-chaining rules engine

To better understand the use of a rules engine for support of clinical decision-making, an app for a simple diagnostic task was implemented in Clojure(script) using a forward-chaining rules engine (Clara) based on the Rete algorithm.

The app reflects well-known diagnostic approaches to anemia (see for example, Leung et al [1]), which are typically implemented imperatively, but here is based on a series of forward-chaining rules providing a functional approach.

Here are example rules:

(defrule anemic
[:or
[Lab (= test-name 'hct) (lab-low? hct-nl value)]
[Lab (= test-name 'hgb) (lab-low? hgb-nl value)]
[Lab (= test-name 'rbc-count) (lab-low? rbc-count-nl value)]]
=>
(insert! (->Diagnoses "pt-0" "anemia")))
(defrule microcytic-anemia
[Diagnoses (= diagnosis "anemia")]
[Lab (= test-name 'mcv) (lab-low? mcv-nl value)]
=>
(insert! (->Diagnoses "pt-0" "microcytic anemia")))
(defrule microcytic-but-no-iron-studies
[Diagnoses (= diagnosis "microcytic anemia")]
[:not [Lab (= test-name 'fe)]]
[:not [Lab (= test-name 'tibc)]]
[:not [Lab (= test-name 'ferritin)]]
=>
(insert! (->Diagnoses "pt-0" "Advise getting iron studies.")))
(defrule macrocytic-anemia
[Diagnoses (= diagnosis "anemia")]
[Lab (= test-name 'mcv) (lab-high? mcv-nl value)]
=>
(insert! (->Diagnoses "pt-0" "macrocytic anemia")))
(defrule macrocytic-but-no-workup
[Diagnoses (= diagnosis "macrocytic anemia")]
[:not [Lab (= test-name 'b12)]]
[:not [Lab (= test-name 'folate)]]
=>
(insert! (->Diagnoses "pt-0" "Advise obtaining vitamin B12 and folate levels.")))
(defrule b12-deficiency-anemia
[Diagnoses (= diagnosis "macrocytic anemia")]
[Lab (= test-name 'b12) (lab-low? b12-nl value)]
[Lab (= test-name 'methylmalonate) (lab-low? methylmalonate-nl value)]
[Lab (= test-name 'homocysteine) (lab-high? homocysteine-nl value)]
=>
(insert! (->Diagnoses "pt-0" "B12 deficiency anemia")))

(defrule fe-deficiency-anemia
[Diagnoses (= diagnosis "microcytic anemia")]
[Lab (= test-name 'fe) (lab-low? fe-nl value)]
[Lab (= test-name 'tibc) (lab-high? tibc-nl value)]
[Lab (= test-name 'ferritin) (lab-low? ferritin-nl value)]
=>
(insert! (->Diagnoses "pt-0" "Iron deficiency anemia: find cause")))

(defrule sideroblastic-anemia
;; Microcytic anemia with iron overload, siderocytes/sideroblasts
[Diagnoses (= diagnosis "microcytic anemia")]
[:or
[Lab (= test-name 'fe) (lab-normal? fe-nl value)]
[Lab (= test-name 'fe) (lab-high? fe-nl value)]]
[:or
[Lab (= test-name 'ferritin) (lab-high? ferritin-nl value)]
[Lab (= test-name 'ferritin) (lab-normal? ferritin-nl value)]]
[:or
[Lab (= test-name 'sideroblasts)]
[Lab (= test-name 'siderocytes)]]
=>
(insert! (->Diagnoses "pt-0" "Sideroblastic anemia; find cause")))
(defrule thalassemias
;; Microcytic anemia with signs of α or β thalassemia
[Diagnoses (= diagnosis "microcytic anemia")]
[:or
[Lab (= test-name 'fe) (lab-normal? fe-nl value)]
[Lab (= test-name 'fe) (lab-high? fe-nl value)]]
[:or
[Lab (= test-name 'ferritin) (lab-high? ferritin-nl value)]
[Lab (= test-name 'ferritin) (lab-normal? ferritin-nl value)]]
[:or
[Lab (= test-name 'teardrops)]
[Lab (= test-name 'targetcells)]
[Lab (= test-name 'splenomegaly)]]
=>
(insert! (->Diagnoses "pt-0" "α or β thalassemia; get Hgb electrophoresis")))

The example app (demonstration purposes only; not suitable for clinical use) is here.

Complete source is available.

[1] Leung LL et al.”Approach to the adult with anemia.” Waltham, MA: UpToDate Inc. https://www.uptodate.com/contents/diagnostic-approach-to-anemia-in-adults (Accessed February 15, 2021.)