F# - How to convert array into nativeptr<double>

Viewed 205

I need to interop with some low level C/ FORTAN library. The library requires me to provide a call back function, which has the following signature in C#:

public static class Interop
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public unsafe delegate void F(
        ref int neq,
        ref double t,
        double* y,
        double* yDot);
}

Variable neq contains the lengths of the arrays y and yDot. The external library will provide pointers to the first elements of these arrays.

I can easily create an F# interop to be consumed by this library, e.g.:

let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)


let createInterop() = Interop.F(fun n t y dy -> f(&n, &t, y, dy))

It works and I can see that the function is being called and does something.

Now, I want to write a test that the interop that I created works correctly.

let interopTest() =
    let neq = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n
    let interop = createInterop()

    // Call the interop. ! DOES NOT COMPILE !
    do interop.Invoke(ref neq, ref t, x, dx)

    // Verify the results.

No matter what tried, the call to interop.Invoke does not compile. For the code above, it fails at x and dx with the message:

[FS0001] This expression was expected to have type
    'nativeptr<float>'    
but here has type
    'double []'

I can declare neq and t as mutable and then call the interop like: interop.Invoke(&neq, &t, .... That makes no difference. However, using e.g. &dx.[0] produces the same compiler error.

I need to pass the pointers to the first elements of arrays x and dx to the interop function. Unfortunately searching for how to cast array to a nativeptr in F# did not produce any useful results.

Thanks.

1 Answers

This is how to "how to cast array to a nativeptr in F#":

open Microsoft.FSharp.NativeInterop  
    
let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)

let createInterop() = fun n t y dy -> f(&n, &t, y, dy))

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = NativePtr.ofNativeInt<double> x     
    let tdx = NativePtr.ofNativeInt<double> dx     
   
    let interop = createInterop()

    // Call the interop. Does compile but does not call your c# interop
    // but does create the correct nativeptr(s)
    interop n  t tx tdx

    // Verify the results.

Update:

Apparently this did not work for the OP but both tx and tdx produce the same correct type, either way, in VS Code, at least for me. Anyway this shows another interesting way of doing the same thing and maybe others might find that one works when the other does not?

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = fixed &x.[0]    // val tx: nativeptr<double>
    let tdx = fixed &dx.[0]  // val tdx: nativeptr<double>

      
    let interop = createInterop()

    // Call the interop.
    do interop.Invoke(ref n, ref t, tx, tdx)

    // Verify the results.
Related