背景:
有时一些变量依赖前面时刻的值,例如下面的问题。
$$
\begin{aligned}
x_0 &= 0.2
\\
y_0&=0.1
\\
x_1&=0.15
\\
y_1&=0.08
\\
&\begin{cases}
x_i &= a_0\sin(x_{i-1})+a_1x_{i-2}+\cos(y_{i-1}+a_2)
\\
y_i &= a_3x_{i-1}y_{i-1}
\end{cases},i=2,3,4,...
\end{aligned}
$$
这里将这类问题称为时间模型,对这类模型就需要构建特殊的代码进行处理,本程序提供ClassTimeModel类进行处理。

代码:
这里以上面例子为例,可参看具体写法
//-------------------------------------------------------------------------
Private Sub Test()
    '1. 初始化模型
    Dim model As New ClassTimeModel

    '2. 求解问题维度
    Dim rowNum As Integer = 30'这里假设有30组观测数据
    Dim colNum As Integer = 2'因变量个数x,y
    Dim varNum As Integer = 4'优化变量个数a0,a1,a2,a3,a4

    '3. 设置观察数据
    Dim data(rowNum - 1, colNum - 1) As Double 
    model.SetObservedValue(data)

    '4. 设置模型参数最大索引(最大索引=优化参数个数-1)
    ReDim model.params(varNum - 1)

    '5. 设置模型函数
    model.fun = AddressOf ModelFun

    '6. 设置问题维度
    model.SetDim(rowNum, colNum)

    '7. 初始化
    model.init()

    '8. 设置变量值(优化时可以不设置)
    model.params(0) = 1'a0
    model.params(1) = 1'a1
    model.params(2) = 1'a2
    model.params(3) = 1'a3

    '或者按这种方式设置
    Dim var() As Double = {1,1,1,1}
    model.SetParams(var)

    '9 设置初始边界值
    model.SetPredictedValue(0, 0, 0.2) 'x(0) = 0.2
    model.SetPredictedValue(1, 0, 0.15) 'x(1) = 0.15
    model.SetPredictedValue(0, 1, 0.1) 'y(0) = 0.1
    model.SetPredictedValue(1, 1, 0.08) 'y(1)=0.08

    '10. 不考虑梯度时,求解每次误差平方和
    Dim sumError As Double = model.CalcError()

    '10. 获取梯度维度
    Dim errorSize As Integer = model.GetOptimizerErrorSize() '误差维度,这个=rowNum * colNum
    Dim varSize As Integer = model.GetOptimizerVarSize() '求解变量维度,这个和varNum一致

    '11. 考虑梯度时,每次求解
    Dim er(errorSize - 1) As Double
    Dim diff(errorSize - 1, varSize - 1) As Double
    model.SetDiffZero()'将所有梯度置0
    model.Compute()'计算
    model.GetDiffInfo(er, diff)'获取梯度信息
End Sub

Private Sub ModelFun(ByVal index As Int32, ByVal model As ClassTimeModel)
    '1. 索引2以下已经赋值
    If index < 2 Then
        Return
    End If

    '2. 获取基本数据
    Dim x1 As Double = model.GetPredictedValue(index - 1, 0) 'x(i-1)
    Dim y1 As Double = model.GetPredictedValue(index - 1, 1) 'y(i-1)
    Dim x2 As Double = model.GetPredictedValue(index - 2, 0) 'x(i-2)
    Dim y2 As Double = model.GetPredictedValue(index - 2, 1) 'y(i-2)
    Dim a0 As Double = model.params(0)
    Dim a1 As Double = model.params(1)
    Dim a2 As Double = model.params(2)
    Dim a3 As Double = model.params(3)

    '3. 计算预测值
    Dim x As Double = a0 * sin(x1) + a1 * x2 + cos(y1+a2)
    Dim y As Double = a3 * x1 * y1
    model.SetPredictedValue(index, 0, x)'x(i) = x
    model.SetPredictedValue(index, 1, y)'y(i) = y

    '4. 如果需要梯度,使用如下代码进行设置,误差函数 = 预测值 - 观测值
    Dim dx1da0 As Double = model.GetDiffValue(index - 1, 0, 0)'获取dx(i-1)对da0的导数
    Dim dx1da1 As Double = model.GetDiffValue(index - 1, 0, 1)'获取dx(i-1)对da1的导数
    Dim dx1da2 As Double = model.GetDiffValue(index - 1, 0, 2)'获取dx(i-1)对da2的导数
    Dim dx1da3 As Double = model.GetDiffValue(index - 1, 0, 3)'获取dx(i-1)对da3的导数
    Dim dx2da0 As Double = model.GetDiffValue(index - 2, 0, 0)'获取dx(i-2)对da0的导数
    Dim dx2da1 As Double = model.GetDiffValue(index - 2, 0, 1)'获取dx(i-2)对da1的导数
    Dim dx2da2 As Double = model.GetDiffValue(index - 2, 0, 2)'获取dx(i-2)对da2的导数
    Dim dx2da3 As Double = model.GetDiffValue(index - 2, 0, 3)'获取dx(i-2)对da3的导数
    Dim dy1da0 As Double = model.GetDiffValue(index - 1, 1, 0)'获取dy(i-1)对da0的导数
    Dim dy1da1 As Double = model.GetDiffValue(index - 1, 1, 1)'获取dy(i-1)对da1的导数
    Dim dy1da2 As Double = model.GetDiffValue(index - 1, 1, 2)'获取dy(i-1)对da2的导数
    Dim dy1da3 As Double = model.GetDiffValue(index - 1, 1, 3)'获取dy(i-1)对da3的导数
    
    Dim dxda0 As Double = sin(x1) + a0 * cos(x1) * dx1da0 + a1 * dx2da0 - sin(y1 + a2) * dy1da0
    Dim dxda1 As Double = a0 * cos(x1) * dx1da1 + x2 + a1 * dx2da1 - sin(y1 + a2) * dy1da1
    ...

    model.SetDiffValue(index, 0, 0, dxda0)'设置获取dx(i)对da0的导数
    model.SetDiffValue(index, 0, 1, dxda1)'设置获取dx(i)对da1的导数
    ...

End Sub
//-------------------------------------------------------------------------