GenSolver


Medication Calculation Model

A more complex calcultation model involves calculation of medication

A prescription of a drug can have a frequency, quantity and total or/and a rate, quantity and time in which the drug is administered. A drug can contain one or more components and each component can contain multiple substances.

This gives rise to the following model:

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
let eqs = " = "
let tms = " * "
let add = " + "

let time   = "time"         // Time
let freq   = "freq"         // Frequency
let total  = "prescr.total" // Total prescribed
let qty    = "prescr.qty"   // Quantity prescribed
let rate   = "prescr.rate"  // Rate prescribed

let drug_total = "drug.total" // Total of drug
let drug_qty   = "drug.qty"   // Quantity of drug

let wght = "weight" // Weight adjustment
let bsa  = "bsa"    // Body surface area adjustment

let compSub c comp_total comp_drug_qty s = 
    let sub_comp_qty  = s + "." + c + ".comp.qty"  // Quantity of substance in component
    let sub_comp_conc = s + "." + c + ".comp.conc" // Concentration of substance in component

    let sub_drug_qty  = s + ".drug.qty"  // Quantity of substance in drug
    let sub_drug_conc = s + ".drug.conc" // Concentration of substance in drug

    let sub_dose_qty   = s + ".dose.qty"   // Quantity dose of substance
    let sub_dose_total = s + ".dose.total" // Total dose of substance
    let sub_dose_rate  = s + ".dose.rate"  // Rate dose of substance

    let sub_dose_qty_wght   = s + ".dose.qty.wght"   // Weight adjusted quantity dose of substance
    let sub_dose_total_wght = s + ".dose.total.wght" // Weight adjusted total dose of substance
    let sub_dose_rate_wght  = s + ".dose.rate.wght"  // Weight adjusted rate dose of substance

    let sub_dose_qty_bsa   = s + ".dose.qty.bsa"   // Body surface area adjusted quantity dose of substance
    let sub_dose_total_bsa = s + ".dose.total.bsa" // Body surface area adjusted total dose of substance
    let sub_dose_rate_bsa  = s + ".dose.rate.bsa"  // Body surface area adjusted rate dose of substance


    [
        sub_comp_qty   + eqs + sub_comp_conc + tms + comp_total
        sub_drug_qty   + eqs + sub_drug_conc + tms + drug_total
        sub_drug_qty   + eqs + sub_comp_conc + tms + comp_drug_qty
        sub_dose_total + eqs + sub_dose_qty  + tms + freq 
        sub_dose_qty   + eqs + sub_dose_rate + tms + time
        sub_dose_qty   + eqs + sub_drug_conc + tms + qty
        sub_dose_total + eqs + sub_drug_conc + tms + total
        sub_dose_rate  + eqs + sub_drug_conc + tms + rate

        sub_dose_qty   + eqs + sub_dose_qty_wght   + tms + wght
        sub_dose_total + eqs + sub_dose_total_wght + tms + wght
        sub_dose_rate  + eqs + sub_dose_rate_wght  + tms + wght

        sub_dose_qty   + eqs + sub_dose_qty_bsa   + tms + bsa
        sub_dose_total + eqs + sub_dose_total_bsa + tms + bsa
        sub_dose_rate  + eqs + sub_dose_rate_bsa  + tms + bsa
    ]

let comp cs =
    let c, sl = cs
    let comp_qty   = c + ".comp.qty"   // Quantity of component
    let comp_total = c + ".comp.total" // Total of component

    let comp_drug_qty  = c + ".drug.qty"  // Quantity of component in drug
    let comp_drug_conc = c + ".drug.conc" // Concentration of component in drug

    let comp_dose_qty   = c + ".dose.qty"   // Quantity dose of component
    let comp_dose_total = c + ".dose.total" // Total dose of component
    let comp_dose_rate  = c + ".dose.rate"  // Rate dose of component

    let comp_dose_qty_wght   = c + ".dose.qty.wght"   // Weight adjusted quantity dose of component
    let comp_dose_total_wght = c + ".dose.total.wght" // Weight adjusted total dose of component
    let comp_dose_rate_wght  = c + ".dose.rate.wght"  // Weight adjusted rate dose of component

    let comp_dose_qty_bsa   = c + ".dose.qty.bsa"   // Body surface area adjusted quantity dose of component
    let comp_dose_total_bsa = c + ".dose.total.bsa" // Body surface area adjusted total dose of component
    let comp_dose_rate_bsa  = c + ".dose.rate.bsa"  // Body surface area adjusted rate dose of component

    [
        drug_total      + eqs + comp_qty       + tms + comp_total
        comp_drug_qty   + eqs + comp_drug_conc + tms + drug_total
        comp_dose_total + eqs + comp_dose_qty  + tms + freq 
        comp_dose_qty   + eqs + comp_dose_rate + tms + time
        comp_dose_qty   + eqs + comp_drug_conc + tms + qty
        comp_dose_total + eqs + comp_drug_conc + tms + total
        comp_dose_rate  + eqs + comp_drug_conc + tms + rate

        comp_dose_qty   + eqs + comp_dose_qty_wght   + tms + wght
        comp_dose_total + eqs + comp_dose_total_wght + tms + wght
        comp_dose_rate  + eqs + comp_dose_rate_wght  + tms + wght

        comp_dose_qty   + eqs + comp_dose_qty_bsa   + tms + bsa
        comp_dose_total + eqs + comp_dose_total_bsa + tms + bsa
        comp_dose_rate  + eqs + comp_dose_rate_bsa  + tms + bsa

    ] |> List.append (sl |> List.collect (compSub c comp_total comp_drug_qty))

let drug cs =   
    [ 
        total + eqs + qty        + tms + freq
        qty   + eqs + rate       + tms + time
        total + eqs + drug_total + tms + drug_qty
    ] 
    |> List.append (cs |> List.collect comp)
    |> List.append [ 
        drug_total + eqs + (cs |> List.fold (fun acc (c, _) -> 
        if acc = "" then c + ".drug.qty" else acc + add + c + ".drug.qty") "")
        ]

    |> init              // Initialize the calculation model
    |> nonZeroNegative   // Set all variables to only contain non zero positive values

For a 'simple' one component, one substance drug like a paracetamol supp, the following equantions are generated:

1: 
2: 
3: 
4: 
5: 
let paracetamol = [("supp", ["paracetamol"])] |> drug

paracetamol 
|> printEqs
|> ignore

drug.total<0N..> = supp.comp.qty<0N..> * supp.comp.total<0N..>
drug.total<0N..> = supp.drug.qty<0N..>
paracetamol.dose.qty<0N..> = paracetamol.dose.rate<0N..> * time<0N..>
paracetamol.dose.qty<0N..> = paracetamol.drug.conc<0N..> * prescr.qty<0N..>
paracetamol.dose.qty<0N..> = paracetamol.dose.qty.wght<0N..> * weight<0N..>
paracetamol.dose.qty<0N..> = paracetamol.dose.qty.bsa<0N..> * bsa<0N..>
paracetamol.dose.rate<0N..> = paracetamol.drug.conc<0N..> * prescr.rate<0N..>
paracetamol.dose.rate<0N..> = paracetamol.dose.rate.wght<0N..> * weight<0N..>
paracetamol.dose.rate<0N..> = paracetamol.dose.rate.bsa<0N..> * bsa<0N..>
paracetamol.dose.total<0N..> = paracetamol.dose.qty<0N..> * freq<0N..>
paracetamol.dose.total<0N..> = paracetamol.drug.conc<0N..> * prescr.total<0N..>
paracetamol.dose.total<0N..> = paracetamol.dose.total.wght<0N..> * weight<0N..>
paracetamol.dose.total<0N..> = paracetamol.dose.total.bsa<0N..> * bsa<0N..>
paracetamol.drug.qty<0N..> = paracetamol.drug.conc<0N..> * drug.total<0N..>
paracetamol.drug.qty<0N..> = paracetamol.supp.comp.conc<0N..> * supp.drug.qty<0N..>
paracetamol.supp.comp.qty<0N..> = paracetamol.supp.comp.conc<0N..> * supp.comp.total<0N..>
prescr.qty<0N..> = prescr.rate<0N..> * time<0N..>
prescr.total<0N..> = prescr.qty<0N..> * freq<0N..>
prescr.total<0N..> = drug.total<0N..> * drug.qty<0N..>
supp.dose.qty<0N..> = supp.dose.rate<0N..> * time<0N..>
supp.dose.qty<0N..> = supp.drug.conc<0N..> * prescr.qty<0N..>
supp.dose.qty<0N..> = supp.dose.qty.wght<0N..> * weight<0N..>
supp.dose.qty<0N..> = supp.dose.qty.bsa<0N..> * bsa<0N..>
supp.dose.rate<0N..> = supp.drug.conc<0N..> * prescr.rate<0N..>
supp.dose.rate<0N..> = supp.dose.rate.wght<0N..> * weight<0N..>
supp.dose.rate<0N..> = supp.dose.rate.bsa<0N..> * bsa<0N..>
supp.dose.total<0N..> = supp.dose.qty<0N..> * freq<0N..>
supp.dose.total<0N..> = supp.drug.conc<0N..> * prescr.total<0N..>
supp.dose.total<0N..> = supp.dose.total.wght<0N..> * weight<0N..>
supp.dose.total<0N..> = supp.dose.total.bsa<0N..> * bsa<0N..>
supp.drug.qty<0N..> = supp.drug.conc<0N..> * drug.total<0N..>
-----
Real: 00:00:00.036, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0

Using the model

Next we can start using the model.

A paracetamol supp can have a set of quanities, like: 50, 60, 120, 240, 500 and 1000 mg. And a supp has a total of 1. As the drug contains only the supp, the drug total equals the compoment total and is 1.

1: 
2: 
3: 
4: 
paracetamol
|> solve "paracetamol.supp.comp.qty" "vals" [50N; 60N; 120N; 240N; 500N; 1000N]
|> solve "supp.comp.total"           "vals" [1N]
|> solve "supp.drug.qty"             "vals" [1N]

Lets assume that patients normally tolerate one supp at a time. So, the prescription quantity can be set to 1. Also, the frequency of administration will be around, 1,2,3,4 or 6 times daily.

1: 
2: 
|> solve "prescr.qty" "vals" [1N]
|> solve "freq"       "vals" [1N; 2N; 3N; 4N; 6N]

The maximum paracetamol dose is 4000 mg/day. For children the dose is weight adjusted and should not exceed 90 mg/kg/day

1: 
2: 
|> solve "paracetamol.dose.total"      "maxincl" [4000N]
|> solve "paracetamol.dose.total.wght" "maxincl" [90N]

Suppose we want to prescribe paracetamol with this setup to a child of 6 kg. With a frequency of 3 or 4 times/day.

1: 
2: 
3: 
|> solve "weight" "vals" [6N]
|> solve "freq"   "vals" [3N; 4N]
|> ignore

drug.total[1] = supp.drug.qty[1]
drug.total[1] = supp.comp.qty[1] * supp.comp.total[1]
paracetamol.dose.qty[50, 60, 120] = paracetamol.dose.rate<0N..> * time<0N..>
paracetamol.dose.qty[50, 60, 120] = paracetamol.dose.qty.bsa<0N..> * bsa<0N..>
paracetamol.dose.qty[50, 60, 120] = paracetamol.drug.conc[50, 60, 120] * prescr.qty[1]
paracetamol.dose.qty[50, 60, 120] = paracetamol.dose.qty.wght[25/3, 10, 20] * weight[6]
paracetamol.dose.rate<0N..> = paracetamol.dose.rate.bsa<0N..> * bsa<0N..>
paracetamol.dose.rate<0N..> = paracetamol.dose.rate.wght<0N..> * weight[6]
paracetamol.dose.rate<0N..> = paracetamol.drug.conc[50, 60, 120] * prescr.rate<0N..>
paracetamol.dose.total[150, 180, 200, 240, 360, 480] = paracetamol.dose.qty[50, 60, 120] * freq[3, 4]
paracetamol.dose.total[150, 180, 200, 240, 360, 480] = paracetamol.dose.total.bsa<0N..> * bsa<0N..>
paracetamol.dose.total[150, 180, 200, 240, 360, 480] = paracetamol.drug.conc[50, 60, 120] * prescr.total[3, 4]
paracetamol.dose.total[150, 180, 200, 240, 360, 480] = paracetamol.dose.total.wght[25, 30, 100/3, 40, 60, 80] * weight[6]
paracetamol.drug.qty[50, 60, 120] = paracetamol.drug.conc[50, 60, 120] * drug.total[1]
paracetamol.drug.qty[50, 60, 120] = paracetamol.supp.comp.conc[50, 60, 120] * supp.drug.qty[1]
paracetamol.supp.comp.qty[50, 60, 120] = paracetamol.supp.comp.conc[50, 60, 120] * supp.comp.total[1]
prescr.qty[1] = prescr.rate<0N..> * time<0N..>
prescr.total[3, 4] = prescr.qty[1] * freq[3, 4]
prescr.total[3, 4] = drug.total[1] * drug.qty[3, 4]
supp.dose.qty[1] = supp.drug.conc[1] * prescr.qty[1]
supp.dose.qty[1] = supp.dose.rate<0N..> * time<0N..>
supp.dose.qty[1] = supp.dose.qty.bsa<0N..> * bsa<0N..>
supp.dose.qty[1] = supp.dose.qty.wght[1/6] * weight[6]
supp.dose.rate<0N..> = supp.dose.rate.bsa<0N..> * bsa<0N..>
supp.dose.rate<0N..> = supp.drug.conc[1] * prescr.rate<0N..>
supp.dose.rate<0N..> = supp.dose.rate.wght<0N..> * weight[6]
supp.dose.total[3, 4] = supp.dose.qty[1] * freq[3, 4]
supp.dose.total[3, 4] = supp.drug.conc[1] * prescr.total[3, 4]
supp.dose.total[3, 4] = supp.dose.total.bsa<0N..> * bsa<0N..>
supp.dose.total[3, 4] = supp.dose.total.wght[1/2, 2/3] * weight[6]
supp.drug.qty[1] = supp.drug.conc[1] * drug.total[1]
-----
Real: 00:00:00.092, CPU: 00:00:00.109, GC gen0: 3, gen1: 1, gen2: 1

From the output it can be deduced that:

  • The supp's that can be used are the 50, 60 and 120 mg supps
  • The maximum total dose is 480 mg/day
  • The maximum weight adjusted total dose is 80 mg/kg/day
namespace Informedica
namespace Informedica.GenSolver
namespace Informedica.GenSolver.Utils
module Api

from Informedica.GenSolver


 Public funtions to use the library
val procss : s:string -> unit

Full name: Medication.procss
val s : string
Multiple items
module String

from Informedica.GenSolver.Utils


 Helper functions for `System.String`


--------------------
module String

from Microsoft.FSharp.Core
val replace : (string -> string -> System.String -> string)

Full name: Informedica.GenSolver.Utils.String.replace
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val printEqs : (Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list)

Full name: Medication.printEqs
val printEqs : f:(string -> unit) -> eqs:Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list

Full name: Informedica.GenSolver.Api.printEqs


 Format a set of equations to print.
 Using **f** to allow additional processing
 of the string.
val solve : (string -> string -> BigRational list -> Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list)

Full name: Medication.solve
val solve : f:(string -> unit) -> n:string -> p:string -> vs:BigRational list -> eqs:Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list

Full name: Informedica.GenSolver.Api.solve


 Solve an `Equations` list with

 * f: function used to process string message
 * n: the name of the variable to be updated
 * p: the property of the variable to be updated
 * vs: the values to update the property of the variable
 * eqs: the list of equations to solve
val init : (System.String list -> Informedica.GenSolver.Lib.Equation.Equation list)

Full name: Medication.init
val init : eqs:System.String list -> Informedica.GenSolver.Lib.Equation.Equation list

Full name: Informedica.GenSolver.Api.init


 Initialize the solver returning a set of equations
val nonZeroNegative : (Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list)

Full name: Medication.nonZeroNegative
val nonZeroNegative : eqs:Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list

Full name: Informedica.GenSolver.Api.nonZeroNegative


 Make a list of `Equation`
 to contain only positive
 values as solutions
val eqs : string

Full name: Medication.eqs
val tms : string

Full name: Medication.tms
val add : string

Full name: Medication.add
val time : string

Full name: Medication.time
val freq : string

Full name: Medication.freq
val total : string

Full name: Medication.total
val qty : string

Full name: Medication.qty
val rate : string

Full name: Medication.rate
val drug_total : string

Full name: Medication.drug_total
val drug_qty : string

Full name: Medication.drug_qty
val wght : string

Full name: Medication.wght
val bsa : string

Full name: Medication.bsa
val compSub : c:string -> comp_total:string -> comp_drug_qty:string -> s:string -> string list

Full name: Medication.compSub
val c : string
val comp_total : string
val comp_drug_qty : string
val sub_comp_qty : string
val sub_comp_conc : string
val sub_drug_qty : string
val sub_drug_conc : string
val sub_dose_qty : string
val sub_dose_total : string
val sub_dose_rate : string
val sub_dose_qty_wght : string
val sub_dose_total_wght : string
val sub_dose_rate_wght : string
val sub_dose_qty_bsa : string
val sub_dose_total_bsa : string
val sub_dose_rate_bsa : string
val comp : string * string list -> string list

Full name: Medication.comp
val cs : string * string list
val sl : string list
val comp_qty : string
val comp_drug_conc : string
val comp_dose_qty : string
val comp_dose_total : string
val comp_dose_rate : string
val comp_dose_qty_wght : string
val comp_dose_total_wght : string
val comp_dose_rate_wght : string
val comp_dose_qty_bsa : string
val comp_dose_total_bsa : string
val comp_dose_rate_bsa : string
Multiple items
module List

from Informedica.GenSolver.Utils


 Helper functions for `List`


--------------------
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val append : list1:'T list -> list2:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.append
val collect : mapping:('T -> 'U list) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.collect
val drug : cs:(string * string list) list -> Informedica.GenSolver.Lib.Equation.Equation list

Full name: Medication.drug
val cs : (string * string list) list
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State

Full name: Microsoft.FSharp.Collections.List.fold
val acc : string
val paracetamol : Informedica.GenSolver.Lib.Equation.Equation list

Full name: Medication.paracetamol
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
Fork me on GitHub