This project has moved and is read-only. For the latest updates, please go here.

Function of vectors

Jul 25, 2014 at 6:29 AM
I come from an R background and would like to translate this little R function

kld = function(p,q) ifelse(p == 0 | q == 0, 0, log(p/q)*p)

into F# using Math.NET vectors.

I got as far as this:

let f1 (p:float, q:float) =
if p = 0.0 || q = 0.0 then 0.0
else log(p / q) * p
But unlike R, this function is not vectorized.

p and q should be vectors, and the result should be a vector, too.

I tried

let f2 (p:Vector<float>, q:Vector<float>) =

but didn't get anywhere.
Jul 25, 2014 at 7:16 AM
Edited Jul 25, 2014 at 7:21 AM
If functions are not vectorized already, a common approach is to use a map function (e.g. from the Math.NET Numerics F# extensions). Unfortunately in your case you'd need a map2 function accepting two vectors, which is not yet available. We should add them!

In the meantime you could work around this by defining your own using sequences:
let map2 f u v = Seq.map2 f (Vector.toSeq u) (Vector.toSeq v) |> DenseVector.ofSeq
which has the signature f:('a -> 'b -> 'c) -> u:Vector<'a> -> v:Vector<'b> -> Vector<'c>

then you can write:
let u = vector [1.0; 2.0; 0.0; 3.0]
let v = vector [2.0; 1.0; 3.0; 0.0]

(u, v) ||> map2 (fun p q -> if p = 0.0 || q = 0.0 then 0.0 else log(p / q) * p)
or by defining a function:
let f2 p q = map2 (fun p q -> if p = 0.0 || q = 0.0 then 0.0 else log(p / q) * p) p q

// or in terms of f1:
let f2 p q = map2 f1 p q

// use on vectors u and v:
f2 u v
Marked as answer by Radibor on 7/25/2014 at 12:48 AM
Jul 25, 2014 at 8:47 AM
Thank you very much for your solution and the variants! Now it looks quite concise and similar to what I'm used to.

Would it also be possible as a more general approach to create a matrix from the 2 vectors and then use a mapx function that takes f1 and the rows of the matrix as input? (Similar to the "apply" function in R).

Something like mapx f1 mat?

I looked at ReduceColumns but I'm not sure that's the right function. Map for matrix exists, but operates elementwise.
Jul 29, 2014 at 10:34 AM
Btw, there is now a proper map2 function for vectors in mainline (will be part of the v3.2 release), which is quite a bit faster than the sequence workaround.
Aug 7, 2014 at 8:56 AM
Just installed release 3.2.1. Thanks to the Vector.map2 I can now write
let kld a b = Vector.map2 (fun p q -> if p = 0.0 || q = 0.0 then 0.0 else log(p / q) * p) a b |> Vector.sum 
But then I realized that Vector.fold2 would be even better. Here's the Array version:
let kld a b = Array.fold2 (fun acc p q -> if p = 0.0 || q = 0.0 then acc else acc + log(p / q) * p) a b 
In my tests, Array.fold2 is faster than Array.map2 |> Array.sum

So would it make sense to include a Vector.fold2 function in the next release?