2

I have just downloaded the last version of ILNumerics, to be used in my F# project. Is it possible to leverage on this library in F#? I have tried simple computations and it seems very cumbersome (in F#).

I would like to set up a constrained (or even unconstrained) optimization problem. The usual Rosenbrock function would do and then I will use my own function. I am having hard times in having even an Array being defined. The only kind of array I could define was a RetArray, for example with this code

let vector = ILMath.vector<float>(1.0, 2.0)

The compiler signals that vector is a RetArray; I think this is due to the fact that it is returning from a function (i.e.: ILMath.vector). If I define another similar vector, I can -e.g.- sum vectors, simply writing, for example

let a = ILMath.vector<float>(1.0, 2.0)
let b = ILMath.vector<float>(3.2,2.2)
let c = a  + b 

and I get

RetArray<float> = seq [4.2; 4.2]

but if I try to retrieve the value of c, again, writing, for example in FSI,

c;;

I get

Error: Object reference not set to an instance of an object.

What is the suggested way of using ILNumerics in F#? Is it possible to use the library natively in F# or I am forced to call my F# code from a C# library to use the whole ILNumerics library? Other than with the problem cited, I have problems in understanding the very basic logic of ILNumerics, when ported in F#.

For example, what would be the F# equivalent of the C# using scope as in the example code, as in:

using (ILScope.Enter(inData)) { ...

}
  • "but if I try to retrieve the value of c" - can you elaborate on that? Your question doesn't have any code that accesses c. – Jim Foye Mar 10 '21 at 00:21
  • @JimFoye I have modified the post, accordingly. Thanks for asking the clarification. – pacta_sunt_servanda Mar 10 '21 at 01:24
  • About `using` here's language reference on [resource management](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/resource-management-the-use-keyword). So code will look like `using (ILScope.Enter inData) (fun () -> some computations)` – JL0PD Mar 10 '21 at 03:06

2 Answers2

6

Just to elaborate a bit on brianberns' answer, there are a couple of things you could do to make it easier for yourself.

I would personally not go the route of defining a custom operator - especially one that overrides an existing one. Instead, perhaps you should consider using a computation expression to work with the ILMath types. This will allow you to hide a lot of the uglyness, that comes when working with libraries making use of non-F# standards (e.g. implicit type conversions).

I don't have access to ILMath, so I have just implemented these dummy alternatives, in order to get my code to compile. I suspect you should be able to just not copy that in, and the rest of the code will work as intended

module ILMath =
    type RetArray<'t> = { Values: 't seq }

    and Array<'t> = { OtherValues: 't seq } with
        static member op_Implicit(x: RetArray<_>) = { OtherValues = x.Values }
        static member inline (+) (x1, x2) = { Values = (x1.OtherValues, x2.OtherValues) ||> Seq.map2 (+) }

type ILMath =
    static member vector<'t>([<ParamArray>] vs : 't []) = { ILMath.Values = vs }

If you have never seen or implemented a computation expression before, you should check the documentation I referenced. Basically, it adds some nice, syntactic sugar on top of some uglyness, in a way that you decide. My sample implementation adds just the let! (desugars to Bind) and return (desugars to Return, duh) key words.

type ILMathBuilder() =
    member __.Bind(x: ILMath.RetArray<'t>, f) =
        f(ILMath.Array<'t>.op_Implicit(x))
    member __.Return(x: ILMath.RetArray<'t>) =
        ILMath.Array<'t>.op_Implicit(x)

let ilmath = ILMathBuilder()

This should be defined and instantiated (the ilmath variable) at the top level. This allows you to write

let c = ilmath {
    let! a = vector(1.0, 2.0)
    let! b = vector(3.2, 2.2)
    return a + b
}

Of course, this implementation adds only support for very few things, and requires, for instance, that a value of type RetArray<'t> is always returned. Extending the ILMathBuilder type according to the documentation is the way to go from here.

torbonde
  • 2,459
  • 1
  • 15
  • 17
  • FWIW, I considered a computation builder as well, but it's considerably more work for someone who just wants to *use* the library. (The builder should really be provided by ILNumerics itself.) Also, note that your last code snippet is very similar to what I wrote - the main difference is the location of the `!`. – Brian Berns Mar 10 '21 at 13:39
  • Torbonde, Thanks so much. It is a great answer. @brianberns: you are definitely right. I enjoyed the answer and it is very instructive, but possibly I will try with a simpler approach first, just to use the library. Thanks a lot to both of you. – pacta_sunt_servanda Mar 10 '21 at 14:40
4

The reason that the second access of c fails is that ILNumerics is doing some very unusual memory management, which automatically releases the vector's memory when you might not expect it. In C#, this is managed via implicit conversion from vector to Array:

// C#
var A = vector<int>(1, 2, 3);          // bad!
Array<int> A = vector<int>(1, 2, 3);   // good

F# doesn't have implicit type conversions, but you can invoke the op_Implicit member manually, like this:

open ILNumerics
open type ILMath   // open static class - new feature in F# 5

let inline (!) (x : RetArray<'t>) =
    Array<'t>.op_Implicit(x)

[<EntryPoint>]
let main argv =
    let a = !vector<float>(1.0, 2.0)
    let b = !vector<float>(3.2,2.2)
    let c = !(a  + b)
    printfn "%A" c
    printfn "%A" c
    0

Note that I've created an inline helper function called ! to make this easier. Every time you create an ILNumerics vector in F#, you must call this function to convert it to an array. (It's ugly, I know, but I don't see an easier alternative.)

To answer your last question, the equivalent F# code is:

use _scope = Scope.Enter(inData)
...
Brian Berns
  • 15,499
  • 2
  • 30
  • 40