对可变变量的赋值会干扰其他有效计算的类型推断

时间:2016-07-10 22:53:16

标签: f# mathnet mathdotnet

我尝试了一些Newton Raphson更新。这是一段编译和运行的代码(警告:无限循环)。

let thetam = [|beta; sigSq|] |> DenseVector
let mutable gm = grad yt xt betah sigSqh   // returns DenseVector
let hm = hess yt xt betah sigSqh   // return Matrix<float>

while gm*gm > 0.0001 do
    gm <- grad yt xt betah sigSqh
    thetam - (hess yt xt betah sigSqh).Inverse() * gm // unassigned compiles

但是,只要我将最后一个值分配给可变变量thetam,如下所示......

while gm*gm > 0.0001 do
    gm <- grad yt xt betah sigSqh
    thetam <- thetam - (hess yt xt betah sigSqh).Inverse() * gm // gm here has problems

gm下出现了一条红色的红线,编辑抱怨The type 'Vector<float>' is not compatible with the type 'DenseVector'

但是,明确告诉函数grad返回DenseVector并且通常按预期工作。

let grad (yt : Vector<float>) (xt : Vector<float>) (beta : float) (sigSq : float) =
    let T = (float yt.Count)
    let gradBeta = (yt - beta * xt)*xt / sigSq
    let gradSigSq = -0.5*T/sigSq + 0.5/sigSq**2.*(yt - beta * xt)*(yt - beta * xt)
    [|gradBeta; gradSigSq|] |> DenseVector

为什么分配给thetam导致问题?有没有一种神奇的方法来执行更新而没有可变性?

感谢。

[编辑] 这是完整的脚本:

open System
open System.IO
open System.Windows.Forms
open System.Windows.Forms.DataVisualization
open FSharp.Data
open FSharp.Charting
open FSharp.Core.Operators
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.LinearAlgebra.Double
open MathNet.Numerics.Random
open MathNet.Numerics.Distributions
open MathNet.Numerics.Statistics

let beta, sigSq = 3., 9.
let xt = DenseVector [|23.; 78.; 43.; 32.; 90.; 66.; 89.; 34.; 72.; 99.|]
let T = xt.Count

let genProc () =
    beta * xt + DenseVector [|for i in 1 .. T do yield Normal.Sample(0., Math.Sqrt(sigSq))|]

let llNormal (yt : Vector<float>) (xt : Vector<float>) (beta : float) (sigSq : float) =
    let T = (float yt.Count)
    let z = (yt - beta * xt) / Math.Sqrt(sigSq)
    -0.5 * log (2. * Math.PI) - 0.5 * log (sigSq) - z*z/2./T/sigSq

let grad (yt : Vector<float>) (xt : Vector<float>) (beta : float) (sigSq : float) =
    let T = (float yt.Count)
    let gradBeta = (yt - beta * xt)*xt / sigSq
    let gradSigSq = -0.5*T/sigSq + 0.5/sigSq**2.*(yt - beta * xt)*(yt - beta * xt)
    [|gradBeta; gradSigSq|] |> DenseVector

let hess (yt : Vector<float>) (xt : Vector<float>) (beta : float) (sigSq : float) = 
    let T = (float yt.Count)
    let z = yt - beta * xt
    let h11 = -xt*xt/sigSq
    let h22 = T*0.5/sigSq/sigSq - z*z/sigSq/sigSq/sigSq
    let h12 = -1./sigSq**2.*((yt - beta * xt)*xt)
    array2D [[h11;h12];[h12;h22]] |> DenseMatrix.ofArray2

let yt = genProc()

// until convergence
let mutable thetam = [|beta; sigSq|] |> DenseVector
let mutable gm = grad yt xt beta sigSq

while gm*gm > 0.0001 do
    gm <- grad yt xt beta sigSq
    // 'gm' here is complaining upon equation being assigned to thetam
    thetam <- thetam - (hess yt xt beta sigSq).Inverse() * gm 

1 个答案:

答案 0 :(得分:0)

您应该至少将let mutable thetam = [|beta; sigSq|] |> DenseVector更改为
let mutable thetam = [|beta; sigSq|] |> DenseVector.ofArray(可能还有其他DenseVector引用)。出于性能原因,Mathnet会进行就地更改,因此如果您使用可变引用,它可能会绊倒您:

  

DenseVector(Double [] storage)

     

创建一个直接绑定到原始数​​组的新密集向量。阵列   直接使用,无需复制。效率很高,但改变了   数组和向量将相互影响。

对战:

  

DenseVector OfArray(Double [] array)

     

创建一个新的密集向量作为给定数组的副本。这个新的   vector将独立于数组。一个新的内存块将是   分配用于存储矢量。

事实上,当Exponential.Samples以类似的方式行事时,我们已在previous question中看到此行为。

API文档(虽然不是超级用户友好的)是here