简体   繁体   English

F#的简单包装器,用于执行矩阵运算

[英]A Simple Wrapper for F# to do matrix operations

This is a relatively long post. 这是一篇相对较长的帖子。 F# has a matrix and vector type(in PowerPack not in the Core) now. F#现在具有矩阵矢量类型(在PowerPack中不在Core中)。 This is great! 这很棒! Even Python's numerical computing ability is from the third part. 即使是Python的数值计算能力也来自第三部分。

But the functions provided there is limited to the matrix and vector arithmetic, so to do inversion, decompositions etc. we still need to use another library. 但是那里提供的函数仅限于矩阵和向量算法,所以要进行反演,分解等,我们仍然需要使用另一个库。 I am now using the latest dnAnalytics , which is merging into Math.Net project. 我现在正在使用最新的dnAnalytics ,它正在合并到Math.Net项目中。 But Math.Net project has no updates to the public for more than a whole year now, I don't know if they have a plan to continue. 但Math.Net项目现在已经有一年多没有对公众进行更新了,我不知道他们是否有继续计划。

I did the following wrapper, this wrapper uses Matlab-like functions to do simple linear algebra. 我做了以下包装器,这个包装器使用类似Matlab的函数来做简单的线性代数。 As I am new to F# and FP, would you please give some advices to improve the wrapper and code? 由于我是F#和FP的新手,您能否提出一些改进包装和代码的建议? Thanks! 谢谢!

#r @"D:\WORK\tools\dnAnalytics_windows_x86\bin\dnAnalytics.dll"
#r @"FSharp.PowerPack.dll"

open dnAnalytics.LinearAlgebra
open Microsoft.FSharp.Math
open dnAnalytics.LinearAlgebra.Decomposition

// F# matrix -> ndAnalytics DenseMatrix
let mat2dnmat (mat:matrix) = 
    let m = new DenseMatrix(mat.ToArray2D())
    m

// ndAnalytics DenseMatrix -> F# matrix 
let dnmat2mat (dnmat:DenseMatrix) = 
    let n = dnmat.Rows
    let m = dnmat.Columns
    let mat = Matrix.create n m 0.
    for i=0 to n-1 do
        for j=0 to m-1 do
            mat.[i,j] <- dnmat.Item(i,j)
    mat

// random matrix
let randmat n m =
    let r = new System.Random()
    let ranlist m = 
        [ for i in 1..m do yield r.NextDouble() ]
    matrix ([1..n] |> List.map (fun x-> ranlist m))

// is square matrix
let issqr (m:matrix) =
    let n, m = m.Dimensions
    n = m

// is postive definite 
let ispd m =
    if not (issqr m) then false
    else 
        let m1 = mat2dnmat m
        let qrsolver = dnAnalytics.LinearAlgebra.Decomposition.Cholesky(m1)
        qrsolver.IsPositiveDefinite()

// determinant
let det m =
    let m1 = mat2dnmat m
    let lusolver = dnAnalytics.LinearAlgebra.Decomposition.LU(m1)
    lusolver.Determinant ()

// is full rank
let isfull m =
    let m1 = mat2dnmat m
    let qrsolver = dnAnalytics.LinearAlgebra.Decomposition.GramSchmidt(m1)
    qrsolver.IsFullRank()

// rank
let rank m =
    let m1 = mat2dnmat m
    let svdsolver = dnAnalytics.LinearAlgebra.Decomposition.Svd(m1, false)
    svdsolver.Rank()

// inversion by lu
let inv m =
    let m1 = mat2dnmat m
    let lusolver = dnAnalytics.LinearAlgebra.Decomposition.LU(m1)
    lusolver.Inverse()

// lu
let lu m =
    let m1 = mat2dnmat m
    let lusolver = dnAnalytics.LinearAlgebra.Decomposition.LU(m1)
    let l = dnmat2mat (DenseMatrix (lusolver.LowerFactor ()))
    let u = dnmat2mat (DenseMatrix (lusolver.UpperFactor ()))
    (l,u)

// qr 
let qr m =
    let m1 = mat2dnmat m
    let qrsolver = dnAnalytics.LinearAlgebra.Decomposition.GramSchmidt(m1)
    let q = dnmat2mat (DenseMatrix (qrsolver.Q()))
    let r = dnmat2mat (DenseMatrix (qrsolver.R()))
    (q, r)

// svd 
let svd m =
    let m1 = mat2dnmat m
    let svdsolver = dnAnalytics.LinearAlgebra.Decomposition.Svd(m1, true)
    let u = dnmat2mat (DenseMatrix (svdsolver.U()))
    let w = dnmat2mat (DenseMatrix  (svdsolver.W()))
    let vt = dnmat2mat (DenseMatrix (svdsolver.VT()))
    (u, w, vt.Transpose)

and test code 和测试代码

(* todo: read matrix market format   ref: http://math.nist.gov/MatrixMarket/formats.html *)
let readmat (filename:string) = 
    System.IO.File.ReadAllLines(filename) |> Array.map (fun x-> (x |> String.split [' '] |> List.toArray |> Array.map float))
    |> matrix

let timeit f str= 
    let watch = new System.Diagnostics.Stopwatch()
    watch.Start()
    let res = f()
    watch.Stop()
    printfn "%s Needed %f ms" str watch.Elapsed.TotalMilliseconds
    res

let test() = 
    let testlu() = 
        for i=1 to 10 do
            let a,b = lu (randmat 1000 1000)
            ()
        ()
    let testsvd() =
        for i=1 to 10 do
            let u,w,v = svd (randmat 300 300)
            ()
        ()
    let testdet() =
        for i=1 to 10 do
            let d = det (randmat 650 650)
            ()
        ()
    timeit testlu "lu" 
    timeit testsvd "svd"
    timeit testdet "det"

I also compared with matlab 我也比较了matlab

t = cputime; for i=1:10, [l,u] = lu(rand(1000,1000)); end; e = cputime-t
t = cputime; for i=1:10, [u,w,vt] = svd(rand(300,300)); end; e = cputime-t
t = cputime; for i=1:10, d = det(rand(650,650)); end; e = cputime-t

The timings (Duo Core 2.0GH, 2GB memory, Matlab 2009a) 时间安排(Duo Core 2.0GH,2GB内存,Matlab 2009a)

f#:
lu Needed 8875.941700 ms
svd Needed 14469.102900 ms
det Needed 2820.304600 ms
matlab:
  lu 3.7752
  svd 5.7408
  det 1.2636

matlab is about two times faster. matlab的速度快了两倍。 This is reasonable, as a native R also has similar results . 这是合理的,因为原生R也有类似的结果

I think that both dnmat2mat and randmat could be simplified by using Matrix.init : 我认为无论是dnmat2matrandmat可以通过使用简化Matrix.init

let dnmat2mat (dnmat : DenseMatrix) =
  Matrix.init (dnmat.Rows) (dnmat.Columns) (fun i j -> dnmat.[i,j])

let randmat n m =
  let r = System.Random()
  Matrix.init n m (fun _ _ -> r.NextDouble())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM