功能：梯度优化窗口主要是提供更加灵活地求解优化问题

需求：在这个窗口里需要使用VB.NET语言自定义定义误差函数

说明：所谓优化问题，即给定一个误差目标函数，让计算器去寻找满足条件的最优解。这类问题包括：非线性拟合、非线性方程组求解等等。

特点：

1. 支持混合整数优化

2. 支持对变量优化范围进行控制(如果求解效果不理想, 尝试更改变量范围varMax和varMin, 再进行求解)

3. 支持对复数变量优化,具体看第8点

4. 采用多线程加速求解

5. 有一定程度的自定义操作空间

6. 在设置求解算法时(solveType, 如果求解不理想, 请尝试设置其它算法进行求解),对应算法分类如下:

6.1 效率较高, 内部会求解稠密线性方程组, 适合优化变量个数不是很大的情况, 对应算法有: DogLeg, LM, Grad(一种带缩放的梯度优化算法)

6.2 效率一般, 内部不会求解方程组, 适合优化变量个数较大的情况, 对应算法有: Adma, Nadam, AMSGrad, Adadelta, GradNoEqu(一种带缩放的梯度优化算法)

6.3 效率较低, 适合优化变量个数较大的情况, 对应算法有: Fun(函数直接试探)

7. 自定义代码中的函数funPtr对象提供了一些如下的内部函数

7.1 读取数据
申明: bool API_ReadData(f, x)
说明: 主要读取矩阵变量数据, f为string存储的文件路径,如果为空将打开选择读取文件对话框, 读取成功将数据放到二维数组x,每一行数据以逗号或空格分隔,每列数据以分号或者换行符号分隔. 函数执行成功返回True.
例子:
Dim x(0,0) As Double
API_ReadData("", x)

7.2 保存数据
申明1: bool API_WriteData(f, vars)
申明2: bool API_WriteData(f, var)
申明3: bool API_WriteData(vars)
申明4: bool API_WriteData(var)

说明: 主要将数据保存到文件, f为保存文件路径, vars为需要保存的多个数据, var为对应变量, 函数执行成功返回True.
例子:
//下面的代码放到RunEnd函数里, 优化完毕后可以查看C:\test.txt文件内容
Dim vars As Object() = new Object(){"error = ", minError, vbCrLf, "loop = ", loopSum, vbCrLf, "var = " , vbCrLf, optVar}
API_WriteData("C:\test.txt", vars)

Dim x() as Double = {1.5, 2.3}
API_WriteData(x)

7.3 求解线性方程组
申明: API_SolveEqu(A, b, x)
说明: 主要求解线性方程x,即已知二维数组A,一维数组b,求解一维数组x.这里当b为2维数组时,其行数必须与A一致, 求得的x也必须是二维数组. 注意x需要提前申明数组大小.
例子:
API_SolveEqu(a, b, x)

7.4 自适应一维定积分
申明: 
double API_IntegralFun1D(fun, a, b)
double API_IntegralFun1D(fun2, a, b, var, i)

说明: 
(1)主要使用自适应算法进行一维定积分
(2)fun为指定函数,必须是类似Public Function fun(ByVal v As Double) As Double这样定义的一个函数
(3)fun2为指定函数,必须是类似Public Function fun(ByVal v() As Double) As Double这样定义的一个函数
(4)a表示积分下限
(5)b表示积分上限
(6)var为传递的一维变量
(7)i表示var中第i个需要积分的变量
(8)函数执行完毕返回积分结果 

例子:
//已知有函数f = y * sin(x) / exp(x)，现在想在 y = 3.6 的情况下，计算x从0.25到正无穷的积分
Public Function funXY(ByVal x As Double) As Double
    Dim f As Double = 3.6* Sin(x) / Exp(x)
    Return f
End Function

Public Function funXY2(ByVal v() As Double) As Double
    Dim x As Double = v(0)
    Dim y As Double = v(1)
    Dim f As Double = y * Sin(x) / Exp(x)
    Return f
End Function

//然后添加如下代码，运行代码后，可以看z1与z2结果一致。
Dim var(1) As Double
var(1) = 3.6
dim z1 As Double = API_IntegralFun1D(funXY, 0.25, inf)
dim z2 As Double = API_IntegralFun1D(funXY2, 0.25, inf, var, 0)

7.5 一阶导数
申明: double API_DiffFun1D(fun, var, i)
说明: 
(1)fun为指定函数,必须是类似Public Function fun(ByVal v() As Double) As Double这样定义的一个函数
(2)var为传递的一维变量
(3)i表示var中第i个需要求导数的变量

例子:
//已知有函数f = y * sin(x) / exp(x)，现在想计算x = 2.5, y = 3.6时 df/dx 的值
Public Function funXY(ByVal v() As Double) As Double
    Dim x As Double = v(0)
    Dim y As Double = v(1)
    Dim f As Double = y * Sin(x) / Exp(x)
    Return f
End Function

//然后添加如下代码，运行代码后，可以看z的结果
Dim var(1) As Double
var(0) = 2.5
var(1) = 3.6
dim z As Double = API_DiffFun1D(funXY, var, 0)

7.6 一阶常微分方程组求解
申明: 
API_SolveODE45(dxfun, x0, y0, x, y)
API_SolveODE45(dxfun, x0, y0, x, y, h)
说明: 
(1)dxfun为指定的一阶导数函数,必须是类似Public Sub fun(ByVal x As Double, ByRef y() As Double, ByRef dy() As Double)这样定义的一个函数.函数里x为自变量,y为因变量,dy为y的一阶导数
(2)x0: Double类型, 为边界初始值
(3)y0: Double() 类型,为边界初始值
(4)x : Double() 类型,待求解变量每个时刻值
(5)y : Double(,) 类型,待求解变量每个时刻值对应的因变量值。此参数的行数与x的个数一致。如果为微分方程组,y的列数与常微分因变量个数一致。
(6)h : Double类型, 为最小步长,默认为0.001

例子:
//已知 dy/dx = 1 + x - y, 其中边界初值x = 0 时, y = 1, 现在想计算x = 1.2, 1.5时的值, y的值
//下面先写导数函数
Public Sub fun(ByVal x As Double, ByRef y() As Double, ByRef dy() As Double)
    dy(0) = 1 + x - y(0)
End Sub

//然后添加如下代码，运行代码后，可以看y的结果
Dim x0 As Double
Dim y0(0) As Double
Dim x(1),y(1,0) As Double
x0    = 0
y0(0) = 1
x(0)  = 1.2
x(1)  = 1.5
API_SolveODE45(fun, x0, y0, x, y)

7.7 一维线性插值
申明: bool  API_LineInterpolation1D(srcX, srcY, dstX, outY)
说明: 
(1)srcX 为一个一维数组,主要存储节点值
(2)srcY 为一个2维数组, 它的行数与srcX个数一致, srcX的第i个元素值,对应srcY第i行的值, 如果srcY有多列, 每一列分别表示已知值的类型
(3)dstX 为一个一维数组,主要存储需要插值出的节点值
(4)outY 为一个2维数组, 主要存储插值结果, 其行数与dstX元素个数一致, 列数与srcY一致, 每一行对应dstX对应个数的元素

例子:
Dim x() As Double = {1,2,3,4,5,6}
Dim y(,) As Double = {{1}, {2}, {3}, {4}, {5}, {6}}

Dim x1() As Double = {1.5, 3.6}
Dim y1(0,0) As Double
API_LineInterpolation1D(x, y, x1, y1) '执行完毕后,y1变成2*1的数组,里面有插值结果 y1(0,0) = 1.5, y1(1,0) = 3.6

7.8 从矩阵变量获取二维数据
申明: API_GetMatrix(var)
说明: 
(1) var为一个字符串, 为矩阵变量名称
(2) 如果var本身存在, 则返回一个二维数组, 否则返回Nothing

例子: 
Dim x(,) As Double = API_GetMatrix("a")

7.9 从矩阵变量获取二维数据
申明: API_GetMatrixCol(v, j)
说明: 
(1) v为一个2维数组
(2) j为指定的列索引,这里索引从0开始
(3) 执行成功返回一个一维数组,里面存储对应列数据, 执行失败返回Nothing

例子: 
Dim x(,) As Double = {{1,2}, {3,4}}
Dim y() As Double = API_GetMatrixCol(x, 0) '执行成功y的值将为{1, 3}

7.10 将数据保存到矩阵变量
申明: bool API_SetMatrix(var, v)
说明: 
(1) var为一个字符串, 主要设置矩阵变量名称, 这个名称必须合法, 否则将保存失败
(2) v为保存的数据, 可以为2维数组, 可以为1维数组, 可以为数值
(3) 保存成功返回True

例子: 
Dim x() As Double = {1, 2.3}
API_SetMatrix("a", x) '执行完,可以在矩阵运算窗口输入a查看效果

7.11 将2维数组转为1维数组
申明: API_Matrix2DTo1D(v)
说明: 
(1) v为一个2维数组
(2) 执行成功返回一个一维数组,里面存储对应列数据, 执行失败返回Nothing

7.12 将一个对象保存到对象变量
申明: API_SetObject(var, obj)
说明:
(1) var 为字符串存储的变量名称
(2) obj 为一个类对象
(3) 本函数主要作用是将obj保存为一个变量

7.13 绘制2维曲线
申明: API_Plot(x1, y1, x2, y2, ...)
说明: 
(1) 本函数接收2n个参数, 每两个参数为一组
(2) x1, y1, x2, y2, ...为一维数组, 其中每两个参数为一组, 且每组元素个数一致
(3) 函数执行完毕返回一个绘图窗口句柄, 并显示图形

7.14 下载文件
申明: API_DownLoadFile(url, f)
说明: 
(1) url为字符串存储的下载链接
(2) f为字符串存储的下载文件保存路径(包含文件名)
(3) 下载成功返回True, 失败返回False

7.15 运行代码
申明: API_RunCode(code)
说明: 
(1) 本函数主要运行【矩阵运算】窗口可执行的代码
(2) code为字符串存储的代码
例子:
Dim s As String = "x = 0:1:100; y = sin(x/8); plot(x,y)"
API_RunCode(s) '执行后可看到曲线图像窗口

7.16 雅克比椭圆函数
申明: JacobianFun(u, phi, sn, cn, dn)
说明:
(1) u, phi为设置雅克比椭圆参数, 其均为double类型的变量
(2) sn, cn, dn为返回的雅克比椭圆正弦、余弦、Dn函数值
(3) 本函数可一次性计算sn, cn, dn函数值, 比单独调用JacobianSn、JacobianCn、JacobianDn函数要快.

7.17 网络模型代码
Dim net As Object = NetWorkGetFromName("net1") '获取名称为net1的网络模型
Dim n As Integer = NetWorkGetVarSize(net)'获取net优化变量维度个数

Dim var(n-1) As Double
NetWorkSetVar(net, var)'给网络net设置优化变量

var = NetWorkGetVar(net)'获取net优化变量数值

Dim x(2) As Double'假如当前net的输入变量个数为3,这里x存储输入节点值
Dim y() As Double = NetWorkPredict(net, x)'网络预测,预测结果存储在y
Dim dy(,) As Double = NetWorkGetDiffInput(net)'获取对输入层导数, 这个可用于一阶非线性微分方程拟合

7.17 获取对象
Dim obj As Object = API_GetObject("s");//获取变量为s的一个对象类,之后可以对obj进行相关操作

7.18 额外类定义
有时需要在一个结构上使用多个字段,这时为了方便,程序里内置了ClassTempData类,在操作中可以直接使用这个类的字段,这个类定义如下
Public Class ClassTempData
    Public a, b, c, d, e, f, g, alpha, beta, sigma, eta As Double
    Public m, n, num As Integer
    Public flag As Boolean
    Public x(0) As Double
    Public y(0) As Double
    Public z(0) As Double
    Public w(0) As Double
    Public param1(0) As Double
    Public param2(0) As Double
    Public param3(0) As Double
    Public param4(0) As Double
    Public param5(0) As Double
    Public param6(0) As Double
    Public srcX(0) As Double
    Public srcY(0) As Double
    Public srcZ(0) As Double
    Public dx(0, 0) As Double
    Public dy(0, 0) As Double
    Public dz(0, 0) As Double
    Public srcData(0, 0) As Double
    Public dstData(0, 0) As Double
    Public diffData(0, 0) As Double
    Public list1DData As New List(Of Double())
    Public list2DData As New List(Of Double(,))
    Public list1DDataInt As New List(Of Integer())
    Public list2DDataInt As New List(Of Integer(,))
    Public listString As New List(Of String)
    Public listObject As New List(Of Object)
End Class

8. 本模块支持对复数变量的优化(复数拟合, 复数方程求解中会用到), 使用时, 主要遵循以下规则

8.1 复数变量类型为Plural, 因此可以使用如下方式创建一个复数变量
    Dim a As New Plural        '创建一个复数变量,此变量实部与虚部均为0
    Dim a As New Plural(1.5)   '创建一个复数变量,此变量实部为1.5, 虚部均为0
    Dim a As New Plural(1.5, 2)'创建一个复数变量,此变量实部为1.5, 虚部均为2

8.2 对于复数变量,可以通过Real成员变量查看其实部值, 通过Imag查看其虚部值, 例如
    Dim a As New Plural(1.5, 2)
    Dim r As Double = a.Real '这时r为1.5
    Dim g As Double = a.Imag '这时g为2

8.3 所有复数变量的运算返回均为复数变量, 例如
	Dim a As New Plural(1.5, 2)
	Dim b As New Plural(3.5, -2)
	Dim c As Plural = a^2 * b + 3.5 '这里的c直接返回复数变量

8.4 所有复数变量的函数前以小写字母p开始, 后面的函数和【算式解析】窗口函数一致, 例如
	Dim a As New Plural(1.5, 2)
	Dim b As Plural = 1.5 * pSin(a) * pGamma(a)^2 '这里的pSin和原Sin函数一致, pGamma与Gamma函数一致

8.5 因为复数变量包含实部与虚部, 如果将复数变量作为优化变量, 可以将实部与虚部分别作为优化变量进行传递, 在计算过程中, 直接将变量赋值给复数变量进行计算, 完毕后进行相应返回, 即可达到复数优化的目的
	
9. 本模块支持外部C++等语言编写的标准动态链接库, 这样方便与其它语言进行接口互通. 可参考下面例子,来进行调用。

//9.1 申明调用函数类型,假如调用函数接收2个Double, 返回1个Double
Public Delegate Function FunType(ByVal x As Double, ByVal y As Double) As Double

//9.2 下面为大致调用方法
Public Sub TestCall()
    '假如标准动态链接库文件路径为testLib.dll
    dim f as String = "C:\Users\admin\Desktop\testLib.dll"

    '加载dll
    dim hdll as IntPtr = API_LoadLibrary(f)

    '获取dll中对应函数
    dim hfun as IntPtr = API_GetProcAddress(hdll,"mathAdd")

    '使用fun绑定mathAdd函数
    dim fun as FunType = API_GetDelegateForFunctionPointer(hfun, GetType(FunType))
    
    '调用mathAdd函数
    dim xy as Double = fun(1.5, 2.6)

    '如果不再使用, 记得对dll进行释放
    API_FreeLibrary(hdll)
End Sub