Присваивание изменчивой переменной мешает выводу типа другого действительного вычисления
Я пытаюсь обновить Ньютона Рафсона. Вот фрагмент кода, который компилируется и запускается (предупреждение: бесконечный цикл).
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 (хотя и не очень удобные) здесь.