/// <summary> /// 利用广义逆法求解无约束条件下的优化问题 /// <para>f(X0,X1,...,Xn-1)=0,i=0,1,...,m-1,m≥n</para> /// 当 m = n 时,即为求解非线性方程组 /// </summary> /// <param name="m">非线性方程组中方程个数</param> /// <param name="n">非线性方程组中未知数个数</param> /// <param name="eps1">控制最小二乘解的精度要求</param> /// <param name="eps2">用于奇异值分解中的控制精度要求</param> /// <param name="x">存放非线性方程组解的初始近似值X(O),要求各分扯不全为0。返回最小二乘解,当 m = n 时,即为非线性方程组的一组解</param> /// <param name="ka">ka=max(m,n)+1</param> /// <param name="f">指向计算非线性方程组中各方程左端函数值的函数</param> /// <param name="s">指向计算雅可比矩阵的函数名</param> /// <returns>函数返回一个标志值 。 /// 若返回值小于 0, 则说明在 奇异值分解 中迭代超过了 60 次还未满足精度要求; /// 若返回值等千 0, 则说明本函数迭代次还未满足精度要求; /// 若返回值大于 o, 则表示正常返回</returns> public static int NGIN(int m, int n, double eps1, double eps2, double[] x, int ka, NGIN_Func f, NGIN_Func s) { int i, j, k, l = 60, kk, jt; double[] y = new double[10], b = new double[10], p = new double[m * n], d = new double[m], pp = new double[n * m], dx = new double[n], u = new double[m * m], v = new double[n * n], w = new double[ka]; double alpha = 1.0, z = 0, h2, y1, y2, y3, y0, h1; double[,] p_t, pp_t, u_t, v_t; while (l > 0) { f(m, n, x, ref d); s(m, n, x, ref p); p_t = Utility.C.Convert(p, m, n); try { dx = LinearEquations.GMIV(p_t, d, eps2, out pp_t, out u_t, out v_t); } catch { return(-1); } p = Utility.C.Convert(p_t); pp = Utility.C.Convert(pp_t); u = Utility.C.Convert(u_t); v = Utility.C.Convert(v_t); j = 0; jt = 1; h2 = 0; while (jt == 1) { jt = 0; if (j <= 2) { z = alpha + 0.01 * j; } else { z = h2; } for (i = 0; i <= n - 1; i++) { w[i] = x[i] - z * dx[i]; } f(m, n, w, ref d); y1 = 0; for (i = 0; i <= m - 1; i++) { y1 = y1 + d[i] * d[i]; } for (i = 0; i <= n - 1; i++) { w[i] = x[i] - (z + 0.00001) * dx[i]; } f(m, n, w, ref d); y2 = 0; for (i = 0; i <= m - 1; i++) { y2 = y2 + d[i] * d[i]; } y0 = (y2 - y1) / 0.00001; if (Math.Abs(y0) > 1e-10) { h1 = y0; h2 = z; if (j == 0) { y[0] = h1; b[0] = h2; } else { y[j] = h1; kk = 0; k = 0; while ((kk == 0) && (k <= j - 1)) { y3 = h2 - b[k]; if (Math.Abs(y3) == 0) { kk = 1; } else { h2 = (h1 - y[k]) / y3; } k++; } b[j] = h2; if (kk != 0) { b[j] = 1e35; } h2 = 0; for (k = j - 1; k >= 0; k--) { h2 = -y[k] / (b[k + 1] + h2); } h2 += b[0]; } j++; if (j <= 7) { jt = 1; } else { z = h2; } } } alpha = z; y1 = 0; y2 = 0; for (i = 0; i <= n - 1; i++) { dx[i] = -alpha * dx[i]; x[i] = x[i] + dx[i]; y1 = y1 + Math.Abs(dx[i]); y2 = y2 + Math.Abs(x[i]); } if (y1 < eps1 * y2) { return(1); } l--; } return(0); }
/// <summary> /// 根据随机变量及自变量X0,X1,...,Xm-的n组观测值(X0k,X1k,...,Xm-1k,Yk)(k=0,1,...,n-1) 作线性回归分析。 /// </summary> /// <param name="x">x[m,n]: 每一列存放m 个自变量的观测值</param> /// <param name="y">y[n]: 存放随机变量y的n个观测值</param> /// <param name="m">自变量个数</param> /// <param name="n">观测数据的组数</param> /// <param name="a">a[m+1]: 返回回归系数a0,a1,...,am-1,am</param> /// <param name="dt">dt[4]: /// <para>dt(0)返回 偏差平方和q</para> /// <para>dt(1)返回 平均标准偏差s</para> /// <para>dt(2)返回 复相关系数r</para> /// <para>dt(3)返回 回归平方和u</para> /// </param> /// <param name="v">v[m]:返回m个自变量的偏相关系数</param> public static void SQT2(double[,] x, double[] y, int m, int n, out double[] a, out double[] dt, out double[] v) { double[] xx = Utility.C.Convert(x); double q, e, u, p, yy, s, r, pp; int mm = m + 1; double[] b = new double[mm * mm]; b[mm * mm - 1] = n; a = new double[mm]; v = new double[m]; for (int j = 0; j < m; j++) { p = 0; for (int i = 0; i < n; i++) { p += xx[j * n + i]; } b[m * mm + j] = p; b[j * mm + m] = p; } for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { p = 0; for (int k = 0; k < n; k++) { p += xx[i * n + k] * xx[j * n + k]; } b[j * mm + i] = p; b[i * mm + j] = p; } } a[m] = 0; for (int i = 0; i < n; i++) { a[m] += y[i]; } for (int i = 0; i < m; i++) { a[i] = 0; for (int j = 0; j < n; j++) { a[i] += xx[i * n + j] * y[j]; } } var temp_b = Utility.C.Convert(b, mm, mm); var temp_a = Utility.C.Convert(a, mm, 1); LinearEquations.CHLK(ref temp_b, mm, 1, ref temp_a); b = Utility.C.Convert(temp_b); a = Utility.C.Convert(temp_a); yy = 0; for (int i = 0; i < n; i++) { yy += y[i] / n; } q = 0; e = 0; u = 0; for (int i = 0; i < n; i++) { p = a[m]; for (int j = 0; j < m; j++) { p += a[j] * xx[j * n + i]; } q += (y[i] - p) * (y[i] - p); e += (y[i] - yy) * (y[i] - yy); u += (yy - p) * (yy - p); } s = Math.Sqrt(q / n); r = Math.Sqrt(1.0 - q / e); for (int j = 0; j < m; j++) { p = 0; for (int i = 0; i < n; i++) { pp = a[m]; for (int k = 0; k < m; k++) { if (k != j) { pp += a[k] * xx[k * n + i]; } } p += (y[i] - pp) * (y[i] - pp); } v[j] = Math.Sqrt(1.0 - q / p); } dt = new double[4] { q, s, r, u }; }
/// <summary> /// 用拟牛顿法求非线性方程组的一组实数解。 /// </summary> /// <param name="n">方程组中方程个数,也是未知数个数</param> /// <param name="eps">控制精度要求</param> /// <param name="t">控制 h 大小的变量, O<t<l</param> /// <param name="h">增量初值,在本函数中要被破坏</param> /// <param name="x">存放初值,返回方程组的一组实数解</param> /// <param name="k">允许的最大迭代次数</param> /// <param name="func">指向计算方程组左端函数值的函数 /// <para>参数1:点x</para> /// <para>参数2:输出y</para> /// <para>参数3:方程数</para> /// </param> /// <returns>函数返回实际迭代次数。若返回值等于0, 则说明迭代了 K 次还未满足精度要求; /// 若返回值等于-1, 则说明线性代数方程组 AZ = B 奇异; /// 若返回值等于-2,则说明ΣZj=1</returns> public static int NETN(int n, double eps, double t, double h, double[] x, int k, Action <double[], double[], int> func) { if (n != x.Length) { throw new Exception("x长度与指定的n不一致"); } double[] y = new double[n]; double[] a = new double[n * n]; double[] b = new double[n]; int l = k, i, j; double am = 1 + eps, z, beta, d; while (am >= eps) { func(x, b, n); am = 0; for (i = 0; i <= n - 1; i++) { z = Math.Abs(b[i]); if (z > am) { am = z; } } if (am >= eps) { l--; if (l == 0) { return(0);//fail } for (j = 0; j <= n - 1; j++) { z = x[j]; x[j] += h; func(x, y, n); for (i = 0; i <= n - 1; i++) { a[i * n + j] = y[i]; } x[j] = z; } try { LinearEquations.GAUS(Utility.C.Convert(a, n, n), b); } catch { return(-2);//fail } beta = 1; for (i = 0; i <= n - 1; i++) { beta -= b[i]; } if (beta == 0) { return(-2);//fail } d = h / beta; for (i = 0; i <= n - 1; i++) { x[i] = x[i] - d * b[i]; } h = t * h; } } return(k - l); }