C#,数值计算——多维拟牛顿或变度量方法(Quasi-Newton or Variable Metric Methods in Multidimensions)的计算方法与源程序

C#,数值计算——多维拟牛顿或变度量方法(Quasi-Newton or Variable Metric Methods in Multidimensions)的计算方法与源程序

1 Quasi-Newton (Variable Metric) Methods

Quasi-Newton methods attempt to generate an estimate of the inverse of the Hessian matrix 

. This is then used to determine the next iteration point.

The gradient in the region around a is given by

At the minima the gradient is zero

thus the best next direction step is given by

The BFGS (`Broyden-Fletcher-Goldfarb-Shanno') algorithm is based on this technique.

2 C#源程序

using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// Quasi-Newton or Variable Metric Methods in Multidimensions
    /// </summary>
    public class QuasiNewton
    {
        public static void dfpmin(double[] p, double gtol, ref int iter, ref double fret, RealValueFunWithDiff funcd)
        {
            const int ITMAX = 200;
            const double EPS = float.Epsilon; //numeric_limits<double>.epsilon();
            const double TOLX = 4 * EPS;
            const double STPMX = 100.0;

            bool check = false;
            int n = p.Length;
            double[] dg = new double[n];
            double[] g = new double[n];
            double[] hdg = new double[n];
            double[] pnew = new double[n];
            double[] xi = new double[n];
            double[,] hessin = new double[n, n];

            double fp = funcd.funk(p);
            funcd.df(p,g);

            double sum = 0.0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    hessin[i, j] = 0.0;
                }
                hessin[i, i] = 1.0;
                xi[i] = -g[i];
                sum += p[i] * p[i];
            }
            double stpmax = STPMX * Math.Max(Math.Sqrt(sum), (double)n);
            for (int its = 0; its < ITMAX; its++)
            {
                iter = its;
                Roots.lnsrch(p, fp, g, xi, pnew, ref fret, stpmax, ref check, funcd);
                fp = fret;
                for (int i = 0; i < n; i++)
                {
                    xi[i] = pnew[i] - p[i];
                    p[i] = pnew[i];
                }
                double test = 0.0;
                for (int i = 0; i < n; i++)
                {
                    double temp = Math.Abs(xi[i]) / Math.Max(Math.Abs(p[i]), 1.0);
                    if (temp > test)
                    {
                        test = temp;
                    }
                }
                if (test < TOLX)
                {
                    return;
                }
                for (int i = 0; i < n; i++)
                {
                    dg[i] = g[i];
                }

                funcd.df(p,g);

                test = 0.0;
                double den = Math.Max(Math.Abs(fret), 1.0);
                for (int i = 0; i < n; i++)
                {
                    double temp = Math.Abs(g[i]) * Math.Max(Math.Abs(p[i]), 1.0) / den;
                    if (temp > test)
                    {
                        test = temp;
                    }
                }
                if (test < gtol)
                {
                    return;
                }
                for (int i = 0; i < n; i++)
                {
                    dg[i] = g[i] - dg[i];
                }
                for (int i = 0; i < n; i++)
                {
                    hdg[i] = 0.0;
                    for (int j = 0; j < n; j++)
                    {
                        hdg[i] += hessin[i, j] * dg[j];
                    }
                }
                double fac = 0.0;
                double fae = 0.0;
                double sumdg = 0.0;
                double sumxi = 0.0;
                for (int i = 0; i < n; i++)
                {
                    fac += dg[i] * xi[i];
                    fae += dg[i] * hdg[i];
                    sumdg += Globals.SQR(dg[i]);
                    sumxi += Globals.SQR(xi[i]);
                }
                if (fac > Math.Sqrt(EPS * sumdg * sumxi))
                {
                    fac = 1.0 / fac;
                    double fad = 1.0 / fae;
                    for (int i = 0; i < n; i++)
                    {
                        dg[i] = fac * xi[i] - fad * hdg[i];
                    }
                    for (int i = 0; i < n; i++)
                    {
                        for (int j = i; j < n; j++)
                        {
                            hessin[i, j] += fac * xi[i] * xi[j] - fad * hdg[i] * hdg[j] + fae * dg[i] * dg[j];
                            hessin[j, i] = hessin[i, j];
                        }
                    }
                }
                for (int i = 0; i < n; i++)
                {
                    xi[i] = 0.0;
                    for (int j = 0; j < n; j++)
                    {
                        xi[i] -= hessin[i, j] * g[j];
                    }
                }
            }
            throw new Exception("too many iterations in dfpmin");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/beijinghorn/article/details/132286523
今日推荐