GenSolver


How to use this library

The simplest way to use or tryout this library is through the Api interface

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open Informedica.GenSolver.Utils

module API = Informedica.GenSolver.Api

let procss s = "> " + s + " </br> "|> String.replace "*" "\*"

let printEqs = API.printEqs procss
let solve    = API.solve procss
let init     = API.init

Setting up a Calulation Model

A string based calculation model can be specified. This model can only contain sum equations and/or product equations. So take for example conversion from Fahrenheit to Celsius. The original formula looks like this:

cels = (fahr - 32) * 5 / 9

This can be refactored to:

fahr = x + 32 and
cels = x * 5/9

However an equation can only contain variables, so the final version of the model looks like:

fahr = x + const32
cels = x * const5/9

These equations can be feed as strings to the init function that will convert those strings in 2 equations with the variables fahr, cels, x, const32 and const5/9.

1: 
2: 
3: 
4: 
5: 
let fahrCelsConv_Setup =
    init [
        "fahr = x + const32"
        "cels = x * const5/9"
    ]

We can look at the generated equations by using the printEquations function.

1: 
2: 
fahrCelsConv_Setup
|> printEqs |> ignore

This wil spit out the equations:

cels<..> = x<..> * const5/9<..>
fahr<..> = x<..> + const32<..>

Having obtained the model fahrCelsConv_Setup, the model can be solved by the API.solve function. This will print out the intermediate results and return an updated model. The following properties can be set for each variable in the equation:

  • unr: Whether the value range for the variable is unrestricted
  • vals: A list of possible values for the variable
  • minincl: The lower boundary for the variable, inclusive that value
  • minexcl: The lower boundary for the variable, exclusive that value
  • increment: Each possible of a value for the variable should be a multiple of the increment for that variable
  • maxincl: The upper boundary for the variable, inclusive that value
  • maxexcl: The upper boundary for the variable, exclusive that value

So, the first step to further prepare the model is to set the two constant variables to a single possible value

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let fahrCelsConv =
    init [
        "fahr = x + const32"
        "cels = x * const5/9"
    ]
    |> solve "const32"  "vals" "32"
    |> solve "const5/9" "vals" "5/9"

Now the calulation model is ready for use.

Using the Calculation Model

For example convert 20 degrees Celsius to Fahrenheit:

1: 
2: 
3: 
fahrCelsConv
|> solve "cels" "vals" "20"
|> ignore

The result looks like:

cels[20] = x[36] * const5/9[5/9]
fahr[68] = x[36] + const32[32]

However the model is more capable than simple conversion. It can also determine the value range in Celsius for a value range in Fahrenheit:

1: 
2: 
3: 
4: 
fahrCelsConv
|> solve "fahr" "minincl" "50"
|> solve "fahr" "maxincl" "140"
|> ignore

Setting variable fahr minincl with 50
cels[10..> = x[18..> * const5/9[5/9]
fahr[50..> = x[18..> + const32[32]

Setting variable fahr maxincl with 140
cels[10..60] = x[18..108] * const5/9[5/9]
fahr[50..140] = x[18..108] + const32[32]

And so the Celsius range is 10 to 60.

Discrete sets of values

To calculate the amount of joules to perform a medical cardioversion the following formula can be used:

joules = weight * joules.perkg

1: 
2: 
3: 
4: 
let cardioversion = 
    init [
        "joules = weight * joules.perkg"
    ]

However, a defribillator can only be set to a discrete set of joule values

1: 
2: 
cardioversion 
|> solve "joules" "vals" "1,2,3,5,7,10,20,30,50,70,100,150,200,300,360"

For this set of values the amount of joule can be calculated for a weight range

1: 
2: 
|> solve "weight" "minincl" "3"
|> solve "weight" "maxincl" "150"

Typically the amount of joules necessary is about 4 joules/kg

1: 
|> solve "joules.perkg" "maxincl" "4"

Then the amount of joules can be calculated rounded for the available discrete set of possible joules. For example for a body weight of 4 kg.

1: 
|> solve "weight" "vals" "4"

It can be determined that with 10 joules the nearest possible dose of joules to 4 joules/kg can be reached.

1: 
2: 
|> solve "joules" "vals" "10"
|> ignore

Setting variable joules vals with 1,2,3,5,7,10,20,30,50,70,100,150,200,300,360
joules[1, 2, 3, 5, 7, 10, 20, 30, 50, 70, 100, 150, 200, 300, 360] = weight<..> * joules.perkg<..>

Setting variable weight minincl with 3 joules[1, 2, 3, 5, 7, 10, 20, 30, 50, 70, 100, 150, 200, 300, 360] = weight[3..> * joules.perkg<..120]

Setting variable weight maxincl with 150 joules[1, 2, 3, 5, 7, 10, 20, 30, 50, 70, 100, 150, 200, 300, 360] = weight[3..150] * joules.perkg[1/150..120]

Setting variable joules.perkg maxincl with 4
joules[1, 2, 3, 5, 7, 10, 20, 30, 50, 70, 100, 150, 200, 300, 360] = weight[3..150] * joules.perkg[1/150..4]

Setting variable weight vals with 4
joules[1, 2, 3, 5, 7, 10] = weight[4] * joules.perkg[1/4, 1/2, 3/4, 5/4, 7/4, 5/2]

Setting variable joules vals with 10
joules[10] = weight[4] * joules.perkg[5/2]

val it : unit = ()

namespace Informedica
namespace Informedica.GenSolver
namespace Informedica.GenSolver.Utils
module Api

from Informedica.GenSolver


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

Full name: Tutorial.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 printEqs : (Informedica.GenSolver.Lib.Equation.Equation list -> Informedica.GenSolver.Lib.Equation.Equation list)

Full name: Tutorial.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: Tutorial.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: Tutorial.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 fahrCelsConv_Setup : Informedica.GenSolver.Lib.Equation.Equation list

Full name: Tutorial.fahrCelsConv_Setup
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val fahrCelsConv : Informedica.GenSolver.Lib.Equation.Equation list

Full name: Tutorial.fahrCelsConv
val cardioversion : Informedica.GenSolver.Lib.Equation.Equation list

Full name: Tutorial.cardioversion
Fork me on GitHub