3

I am trying to add a method to the DenseVector class to be able to difference the vector n times. The following doesn't seem to work as type inference complains that the type Vector is not compatible with the type DenseVector:

open System
open System.IO
open Deedle
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.LinearAlgebra.Double
open MathNet.Numerics.Distributions

[<Extension>]
type DenseVector with
    member this.diffVector (v : DenseVector) (n : int) =
        let rec run (v : DenseVector) (n : int) =
            match n with
            | 0 -> v
            | _ -> run (v.[ 1 .. v.Count-1 ] - v.[ 0 .. (v.Count-1)-1 ]) (n - 1)
        run v n

v.[ 0 .. (v.Count-1)-1 ] in the above is causing problems. Why is it being inferred as Vector and not DenseVector which is what is passed to the function? Also, is my way of adding the extension method correct?

1 Answers1

3

The reason for your issue is because the extension method that defines the GetSlice method for all Vector<'T> returns a Vector<'T> not a DenseVector. So if you use slicing, which works by calling GetSlice, you will get a Vector and your code above will not work as expected.

I'm not sure how the internals of MathNet work, but you may just be able to make your extension method work for all Vector<'T>s with something like this:

type Vector with
    member this.diffVector (v : Vector<'T>) (n : int) =
        let rec run (v : Vector<'T>) (n : int) =
            match n with
            | 0 -> v
            | _ -> run (v.[ 1 .. v.Count-1 ] - v.[ 0 .. (v.Count-1)-1 ]) (n - 1)
        run v n

Alternatively, it may be that you can just downcast from Vector to DenseVector safely by something like this. This may or may not work:

[<Extension>]
type DenseVector with
    member this.diffVector (v : DenseVector) (n : int) =
        let rec run (v : DenseVector) (n : int) =
            match n with
            | 0 -> v
            | _ -> let v1 = v.[ 1 .. v.Count-1 ] :?> DenseVector
                   let v2 = v.[ 0 .. (v.Count-1)-1 ] :?> DenseVector
                   run (v1 - v2) (n - 1)
        run v n
Ringil
  • 6,277
  • 2
  • 23
  • 37
  • Excellent. One slight modification would be to create a static member instead. Seems a bit cleaner to use that way. Thank you! – professor bigglesworth Oct 01 '16 at 17:58
  • 2
    The Math.NET Numerics API is optimized for the assumption that you always work with the generic base classes in user code (and only downcast if you actually need to access specific DenseVector members). So I'd recommend to write extension method like this on generic vectors directly, i.e. the first example in this answer. – Christoph Rüegg Oct 02 '16 at 06:15
  • 1
    (can also be `Vector`) – Christoph Rüegg Oct 02 '16 at 06:21