Присваивание изменчивой переменной мешает выводу типа другого действительного вычисления

Я пытаюсь обновить Ньютона Рафсона. Вот фрагмент кода, который компилируется и запускается (предупреждение: бесконечный цикл).

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 ответ

Вы должны изменить как минимум let mutable thetam = [|beta; sigSq|] |> DenseVector в
let mutable thetam = [|beta; sigSq|] |> DenseVector.ofArray (и, возможно, другие DenseVector Рекомендации). Mathnet по соображениям производительности вносит изменения на месте, поэтому он может отключить вас, если вы используете изменяемые ссылки:

DenseVector (Двойное хранилище [])

Создайте новый плотный вектор, напрямую связанный с необработанным массивом. Массив используется напрямую без копирования. Очень эффективно, но изменения в массиве и векторе будут влиять друг на друга.

Против:

DenseVector OfArray (массив Double[])

Создайте новый плотный вектор как копию заданного массива. Этот новый вектор будет независим от массива. Новый блок памяти будет выделен для хранения вектора.

На самом деле мы видели это поведение в вашем предыдущем вопросе, когда Exponential.Samples вел себя подобным образом.

Документы по API (хотя и не очень удобные) здесь.

Другие вопросы по тегам