Monday, January 14, 2013

F# infinite lists

Recently I ran into a problem. I had to present a list of numbers that could either contain one, a limited amount or an infinite amount of numbers. Normally, in a non functional language this would pose a big challenge. For example, the concept of an infinite list (in javascript) is something like:
function infinitelist() {
    var list = [];
    for (i = 0; i > 0; i++) {
        list[i] = i;
    }
    return list;
}
Obviously, this would generate a overflow due to an infinite loop. In F# sequences are lazy evaluated and can be constructed using computations. Meaning that a sequence can be defined by a computational expression like:
let allEvens = 
    let rec loop x = seq { yield x; yield! loop (x + 2) }
    loop 0
as the computation in this case is recursive without a base case, this represents an infinite loop. The result will be: 0, 2, 4, 6, ... infinity. However, this code is possible because in F# the calculation of te actual values is deferred until they are actually needed. For example when the above code is called with:
for a in allEvens |> Seq.take 10 do
    printfn "%A\n" a
10 numbers will be calculated and then printed resulting in a list of [0, 2, .. 10]. Infinite sequences need some special treatment. Searching an infinite sequence is a tricky business as this can result in an infinite loop, like:
allEvens |> Seq.find(fun n -> n = 3) |> printfn "%A";;
will take forever, the fact that there is no 3 in the list of even numbers can not be determined by the normal find procedure. A procedure that checks whether the the pickings from the list diverge from the number that is to be found is an algorithm that works, the important prerequisite is that the list is ordered.
let infiniteSequenceFind f i e (s: 'a seq) =
    let rec find d nth =
        match (s |> Seq.nth nth, s |> Seq.nth (nth + 1)) with
        | (_,  _)  when s |> Seq.take nth |> Seq.exists(fun n -> (n |> f i) = e) -> i |> Some
        | (s1, s2) when (s1 |> f i) < (s2 |> f i) -> None  
        | _ -> nth + d |> find (d + 100)

    match s with
    |_ when s |> Seq.isEmpty  -> None
    |_ when s |> Seq.head = i -> Some i
    |_ -> find 1 0

let findBigRationalInInfinite n s = s |> infiniteSequenceFind (fun i s -> abs(s - i)) n 0N

The above code can be used to find a big rational in a lists, the algorithm stops when it realizes that is overshooting the number to find. Another problem I had with infinite lists was that I had to generate lists that were or were not infinite depending on whether there was a maximum (and minimum) or not. The following code gave the solution:
seq{ for v in (s |> Seq.takeWhile(fun x -> match max with |Some m -> x <= m |None -> true)) do
        if (match min with |Some m -> v >= m |None -> true) then yield v else ignore v } |> Seq.cache
The trick was to nest the infinite list in a for loop that checked with the takeWhile method if the number exceeded a maximum. If no maximum is supplied the takeWhile function always returns true, yielding all the numbers in the infinite list. Otherwise the list is truncated by the maximum.

Wednesday, October 10, 2012

Implementing a Rule Based System for First Aid Prescriptions

A rule based system for the calculation of medication to be used in an APLS (Acute Pediatric Life Support) setting follows can be nicely implemented using a functional approach.

F# is a relatively new .net family member is the .net version of a functional programming language. Functional programming languages are particularly suitable to solve data processing and decision support problems. So, I decided to give it a go.

First of all, the problem. As medication in children has to applied to a broad range of age and weight categories, different medication solutions have to be applied. For example, for midazolam we use the following solutions:


Weight Category Solution
< 5.0 kg 50 mg/ 50 mL
5.0 - 15 kg 100 mg/ 50 mL
15 - 23 kg 150 mg/ 50 mL
> 23 kg 200 mg/ 50 mL

In 'normal' C# this would require a lot of if then constructs. In F# the initial solution already looks nicer:

[<Measure>] type kg
[<Measure>] type mg

let selectMidazolamQuantity (weight: float<kg>) :float<mg> =
    match weight with
    | w when w < 0.0<kg> || w > 200.0<kg> -> failwith "Not a valid weight"
    | w when w < 5.0<kg> -> 50.0<mg>
    | w when w >= 5.0<kg> && w < 15.0<kg> -> 100.0<mg>
    | w when w >= 15.0<kg> && w < 23.0<kg> -> 150.0<mg>
    | w when w >= 23.0<kg> -> 200.0<mg>

let qty = selectMidazolamQuantity(23.0<kg>)
qty

In F# instead of if then constructs, pattern matching can be used. The correctness of the pattern is checked at compiler time. So, for example when the pattern is incomplete, this is immediately shown in the editor. Also, primitive values can be decorated with a measure attribute.

When the above code is send to F# interactive this will have the following result:


Script.fsx(40,11): warning FS0025: Incomplete pattern matches on this expression.
val selectMidazolamQuantity : float<kg> -> float<mg>
val qty : float<mg> = 200.0
This code can be further improved by matching against a list of categories:



let milrinoneRules = [| 
    (0.4<kg>, 5.0<kg>, 5.0<mg>); 
    (5.0<kg>, 10.0<kg>, 10.0<mg>);
    (10.0<kg>, 200.0<kg>, 15.0<mg>) 
    |]

let selectQuantity (weight: float<kg>, rules: (float<kg>*float<kg>*float<mg>)[]) : float<mg> =
    match weight with
    | w when w < 0.0<kg> || w > 200.0<kg> -> failwith "Not a valid weight"
    | w ->  
        let rule = Array.find(fun (lower, upper, _) -> w > lower && w <= upper) rules
        let _, _, quantity = rule
        printf "quantity is %s\n" (quantity.ToString())
        quantity

selectQuantity (12.0<kg>, milrinoneRules)

Next step is to annotate the rules set with the medication for wich it is used.

Monday, October 8, 2012

Setting up a SoapClient to use Windows Authentication

Setting up a soap client to use windows authentication is rather tricky as there many configuration options concerning ASP.NET security.

First of all make sure that IIS 7.0 is correctly configured to use Windows authentication instead of default anonymous user login. Therefore, the following has to be applied to the


This effectively forces IIS to use an authenticated windows user. If a user is already windows authenticated, the user does not need to log in. So, this setting is appropriate for use in intranet environments, not in intranet environments.

However, users do not interact with webservices, code interacts with webservices. To consume a web service a service reference has to be added to the project:


Adding a service reference to a project creates an app.config describing the binding of that service including the security settings. Default security settings only enable anonymous user to consume the code. If IIS is configured to use windows security this will result in a HTTP 401 error.

Therefore, the following section has to be modified:


                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
To:

                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>

Note: this section resides in the:

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>

After adjusting the security section the code when run using an authorized windows user should work. But for an application with a web based user interface this is not required! The user will be prompted to log in, if required. So then the code is run with the authenticated user and the webservices can be consumed. I use the above to enable test code to run.


Wednesday, September 5, 2012

How complex can a fluid balance be?

In critical patient care we want to monitor the patient's fluid balance. The fluid balance is an important aspect in assessing a patient and to treat a patient. But what is a fluid balance exactly? Simply put fluid balance can be summarized by the following formula:

balance = fluid in - fluid out

When fluid balance is positive, this means the patient is accumulating fluid, when the fluid balance is negative, the patient is losing fluid. However, this simple notion is complicated by the following factors:

1. What is the time frame of the balance?
There are different possibilities:
  • Balance from start of the day until current time 
  • Balance from 24 hours ago until current time 
  • Balance from date time of admission 
  • -Balance between from date time and to date time 
So, in general a fluid balance always refers to a time frame.

2. Insensible loss
Normally, when a fluid balance is calculated this will yield a positive estimate. This is due to the fact that the human body loses fluid through transpiration and by breathing. This undetected loss is called: insensible loss.

An estimation of insensible loss is:
500 mL/m2/day

Fever increases insensible water losses by
10% per degree Celsius above 38°, or 100-150 mL/day increase per degree Celsius above 37°.

3. Fluid balance has to be related to patient size
What does it mean if the fluid balance is, say +300 mL? If this is an adult patient, this is less than the estimated 500-1000 mL insensible loss per day, so this patient loses fluid. However, in a neonate of with a body weight of 3 kg, this means that this patients accumulates 100 mL/kg/day!

So, size matters. the fluid balance has to be related to body size. Body weight is the most convenient adjustment measure.

4. What goes in and what goes out?
To further analyze a fluid balance it is important to know the amount of what goes in (intake) and what goes out (particularly urine output).

Intake can be categorized as:
  • enteral
  • intravenous
  • dialysis
Fluids can be further categorized as:
  • crystalloids
  • colloid
 Likewise, what goes out can be through:
  • insensible loss
  • urine
  • stool
  • gastric
  • blood loss
  • dialysis
So, in the end the fluid balance is a more complex concept which can be summarized by the folowing formula:




In which there are
  • i to j intake parameters, 
  • and k to l output parameters
  • to is the end date time of the interval and from is the start of the interval, so
  • the interval = to - from, i.e. the time difference between from and to
  • BSA is the body surface area
  • and temp is the body temperature with a minimum of 37
This formula still simplifies the insensible loss by assuming a constant temperature during the interval.

Saturday, January 21, 2012

StructureMap DI Constructor Injection

I spent some considerable time figuring out how the h*** I did this:
public class Repository: NHibernateRepository
{
        public Repository(ISessionFactory factory): base(fact)


        // Etc….
}
public class SomeOtherClass

{
        public IRepository GetRepository()
        {
                return ObjectFactory.GetInstance<IRepository>();
        }
}
The repository class was dependent on a SessionFactory, so in the constructor of that class this was injected. This enables testing code like:
[TestMethod]
public void TestTheRepository()
{
        var repos = new Repository(CreateSomeTestFactory());
        // perform the tests
}
However, in the production code I could not find a single line that did the same as in the above test code. So, how did StructureMap create the Repository class, i.e. how did it inject the required factory??

Turned out that I had written the following sort of code:
public void DoSomeThingWithRepository()
{
        // First tell StructureMap what factory to use
        ObjectFactory.Configure(x => x.For<ISessionFactory>().Use(new ProductionFactory());
        // Now I can let StructureMap get the repository, and have it constructed with the factory I just configured
        var repos = ObjectFactory.GetInstance<IRepository>();
}
That means that the following should be regarded as an anti-pattern:
public class Repository
{
        public Repository()
        {
                base.SetFactory(ObjectFactory.GetInstance<ISessionFactory>());
        }
}
Besides the ugliness of the code, it creates an unnecessary dependance on StructureMap. In general, classes that rely on other classes should be constructed with those classes. Preferably, interfaces of those classes so the constructed class can remain blissfully unaware about the implementation details of the classes it depends on.

See also blog by Jeremy Miller: IOC antipattern

Saturday, December 3, 2011

A Form Script Debugging System in MetaVision

Debugging vbscript that resides in forms in MetaVision is problematic. Runtime exceptions are often thrown without even the right message. I have, therefore, developped a debugging system that can be used in vbscripts in MetaVision to track function calls and provide information of scripting flow and runtime info.

The following script has to be added to a form:

Private Function Debug(strMsg)

If Not Scripts.CurrentUserType = "Beheerders" Then Exit Function

' Set environment variables
strFormName  = "MS Afspraken" ' Aanpassen per formulier
intPatientId = Scripts.CurrentPatientId
' Debug parameters aanpassen per database
intDebugLevelParamId = 12438 'Debug Level Debug parameter Id
intDebugFileParamId  = 12446 'Debug File Location Parameter to give optional file location
intDebugTagParamId   = 12445 'Debug Tag Parameter to add a tag to debug msg
' Debug levels
intLevelDebug   = 0
intLevelOff     = 1
intLevelSilent  = 2
intLevelMessage = 3
' Get Debug level
strSql = strSql & "Select TextId From TextSignals Where ParameterId = "
strSql = strSql & intDebugLevelParamId & " " 
If intPatientId > 0 Then strSql = strSql & "And PatientId = " & intPatientId & " "
strSql = strSql & "Order By ValidationTime Desc"
Set objRecordSet = Scripts.ExecuteStatement(strSql)
If Not objRecordSet.EOF Then intDebugLevel = objRecordSet.Fields("TextId").Value

If intDebugLevel > intLevelOff Then 
 strFileLocation = ""
 strDebugTag     = ""
 ' Get Debug file location
 If intDebugFileParamId > 0 Then
  strSql = "Select Value From FreeTextSignals "
  strSql = strSql & "Where ParameterId = " & intDebugFileParamId & " " 
  If intPatientId > 0 Then strSql = strSql & "And PatientId = " & intPatientId & " "
  strSql = strSql & "Order By ValidationTime Desc"
  Set objRecordSet = Scripts.ExecuteStatement(strSql)
  If Not objRecordSet.EOF Then strFileLocation = objRecordSet.Fields("Value").Value
 End IF
 ' Get Debug tag
 If intDebugTagParamId > 0 Then
  strSql = "Select Value From FreeTextSignals "
  strSql = strSql & "Where ParameterId = " & intDebugTagParamId & " " 
  If intPatientId > 0 Then strSql = strSql & "And PatientId = " & intPatientId & " "
  strSql = strSql & "Order By ValidationTime Desc"
  Set objRecordSet = Scripts.ExecuteStatement(strSql)
  If Not objRecordSet.EOF Then strDebugTag = objRecordSet.Fields("Value").Value
 End IF
  
 If intDebugLevel = intLevelMessage Then Scripts.MsgBox strMsg
 
 intForReading   = 1
 intForWriting   = 2
 intForAppending = 8 
 
 Set objFileSys = CreateObject("Scripting.FileSystemObject")
 If strFileLocation = "" Then strPath = "C:\mvlog.txt" Else strPath = strFileLocation
 
 If objFileSys.FileExists(strPath) Then
  If strDebugTag <> "" Then strLogText = strDebugTag & " "
  strLogText = strLogText & Now & ": " 
  strLogText = strLogText & strFormName & ", " 
  strLogText = strLogText & "Session: " & Scripts.CurrentSessionID & ", "
  strLogText = strLogText & Cstr(strMsg) & vbNewLine 

  Set objLogFile = objFileSys.OpenTextFile(strPath, intForAppending, True) 
  objLogFile.WriteLine(strLogText)
  objLogFile.Close
 End IF
End IF
End Function

First of all I have to apology for the length of the above function. This function is 65 lines! Normally, I try to keep function as simple as possible, let them do just one thing which typically results in function of about 10 lines max. But by putting everything an a single function it is easier to copy and paste (also ugly) this function in forms I need debugging.

The result is that at runtime I can start and/or change debugging for a particular patient in MetaVision. I can even debug the form in the formbuilder! This will look something like:

An Example of Debug level set to Message

In order to set the debug level for a particular patient there needs to be a 'Debug form' like:

The Debug Form

In my next blog entry I will go into more detail of how the debug function works

Scripting in MetaVision

In our hospital we use MetaVision as a PDMS (Patient Data Management System). It is a very flexible product, which is it's strength and also it's weakness. Part of the flexibility comes from the possibility to use vbscript as a scripting language to automate tasks, processes, data analyses and/or create user forms.

I will publish my experiences with using scripting in MetaVision.

The first challenge of using vbscript in MetaVision, specifically in forms, is debugging. Debugging script in MetaVision forms is difficult. Moreover, vbscript exceptions thrown at runtime tend to be misleading! This can be a very frustrating trap, in which I have fallen many times. Therefore, the first thing you should do when using vbscript is setup a debugging system.

The most obvious and simple way to debug vbscripts is using message boxes. The following vbscript can be used as a simple helper function that can act to test pre- and postconditions of functions:

Private Function AssertIsTrue(blnIsTrue, strMsg)

 If Not blnIsTrue Then Scripts.MsgBox strMsg

End Function

A precondition is the condition that has to be met for the function to work, and the post condition must be met by the result of the function.

The function can then be used as follows:

Private Function ClearComboBox(cboBox)

 '' Clears a multi select combobox
 AssertIsTrue cboBox.Name = "cboTextComboMulti", "cboBox is not valid"
 
 intUpper = cboBox.Count - 1
 For intIndex = 0 To intUpper
  If cboBox.Selected(Clng(intIndex)) Then _
   cboBox.Selected(Clng(intIndex)) = False
 Next

End Function

In this function I make sure nothing is selected in a combobox. The combobox is passed in, but because there is no type checking in vbscript, I cannot be sure that the parameter cboBox really references a combobox control. Hence the assertion.

In the next blog I will discuss a more advanced debugging solution.