这是一篇相对较长的帖子。 F#现在具有matrix和vector类型(在PowerPack中不在Core中)。这很棒!即使是Python的数值计算能力也来自第三部分。
但是那里提供的函数仅限于矩阵和向量算法,所以要进行反演,分解等,我们仍然需要使用另一个库。我现在正在使用最新的dnAnalytics,它正在合并到Math.Net项目中。但Math.Net项目现在已经有一年多没有对公众进行更新了,我不知道他们是否有继续计划。
我做了以下包装器,这个包装器使用类似Matlab的函数来做简单的线性代数。由于我是F#和FP的新手,您能否提出一些改进包装和代码的建议?谢谢!
#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)
和测试代码
(* 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"
我也比较了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
时间安排(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的速度提高了约两倍。这是合理的,因为原生R也有similar results。
答案 0 :(得分:3)
我认为使用dnmat2mat
可以简化randmat
和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())