/// <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);
        }
Esempio n. 2
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);
        }