C#,数值计算——多维下坡单纯形法(Downhill Simplex Method in Multidimensions)的计算方法与源程序

 

using System;

namespace Legalsoft.Truffer
{
    ///


    /// 多维下坡单纯形法
    /// Downhill Simplex Method in Multidimensions
    ///

    public class Amoeba
    {
        private int nfunc { get; set; }
        private int mpts { get; set; }
        private int ndim { get; set; }
        public double fmin { get; set; }
        private double ftol { get; }
        private double[] y { get; set; }
        private double[,] p { get; set; }

        public Amoeba(double ftoll)
        {
            this.ftol = ftoll;
        }

        public double[] minimize(double[] point, double del, RealValueFun func)
        {
            double[] dels = new double[point.Length];
            for (int i = 0; i < dels.Length; i++)
            {
                dels[i] = del;
            }
            return minimize(point, dels, func);
        }

        public double[] minimize(double[] point, double[] dels, RealValueFun func)
        {
            int ndim = point.Length;
            double[,] pp = new double[ndim + 1, ndim];
            for (int i = 0; i < ndim + 1; i++)
            {
                for (int j = 0; j < ndim; j++)
                {
                    pp[i, j] = point[j];
                }
                if (i != 0)
                {
                    pp[i, i - 1] += dels[i - 1];
                }
            }
            return (minimize(pp, func));
        }

        public double[] minimize(double[,] pp, RealValueFun func)
        {
            const int NMAX = 5000;
            const double TINY = 1.0e-10;

            mpts = pp.GetLength(0);
            ndim = pp.GetLength(1);
            double[] psum = new double[ndim];
            double[] pmin = new double[ndim];
            double[] x = new double[ndim];
            p = pp;
            //y.resize(mpts);
            y = new double[mpts];
            for (int i = 0; i < mpts; i++)
            {
                for (int j = 0; j < ndim; j++)
                {
                    x[j] = p[i, j];
                }
                y[i] = func.funk(x);
            }
            nfunc = 0;
            get_psum(p, psum);
            for (; ; )
            {
                int ilo = 0;
                int ihi = y[0] > y[1] ? (0) : (1);
                int inhi = y[0] > y[1] ? (1) : (0);
                for (int i = 0; i < mpts; i++)
                {
                    if (y[i] <= y[ilo])
                    {
                        ilo = i;
                    }
                    if (y[i] > y[ihi])
                    {
                        inhi = ihi;
                        ihi = i;
                    }
                    else if (y[i] > y[inhi] && i != ihi)
                    {
                        inhi = i;
                    }
                }
                double rtol = 2.0 * Math.Abs(y[ihi] - y[ilo]) / (Math.Abs(y[ihi]) + Math.Abs(y[ilo]) + TINY);
                if (rtol < ftol)
                {
                    Globals.SWAP(ref y[0], ref y[ilo]);
                    for (int i = 0; i < ndim; i++)
                    {
                        Globals.SWAP(ref p[0, i], ref p[ilo, i]);
                        pmin[i] = p[0, i];
                    }
                    fmin = y[0];
                    return (pmin);
                }
                if (nfunc >= NMAX)
                {
                    throw new Exception("NMAX exceeded");
                }
                nfunc += 2;
                double ytry = amotry(p, y, psum, ihi, -1.0, func);
                if (ytry <= y[ilo])
                {
                    ytry = amotry(p, y, psum, ihi, 2.0, func);
                }
                else if (ytry >= y[inhi])
                {
                    double ysave = y[ihi];
                    ytry = amotry(p, y, psum, ihi, 0.5, func);
                    if (ytry >= ysave)
                    {
                        for (int i = 0; i < mpts; i++)
                        {
                            if (i != ilo)
                            {
                                for (int j = 0; j < ndim; j++)
                                {
                                    p[i, j] = psum[j] = 0.5 * (p[i, j] + p[ilo, j]);
                                }
                                y[i] = func.funk(psum);
                            }
                        }
                        nfunc += ndim;
                        get_psum(p, psum);
                    }
                }
                else
                {
                    --nfunc;
                }
            }
        }

        public void get_psum(double[,] p, double[] psum)
        {
            for (int j = 0; j < ndim; j++)
            {
                double sum = 0.0;
                for (int i = 0; i < mpts; i++)
                {
                    sum += p[i, j];
                }
                psum[j] = sum;
            }
        }

        public double amotry(double[,] p, double[] y, double[] psum, int ihi, double fac, RealValueFun func)
        {
            double[] ptry = new double[ndim];
            double fac1 = (1.0 - fac) / ndim;
            double fac2 = fac1 - fac;
            for (int j = 0; j < ndim; j++)
            {
                ptry[j] = psum[j] * fac1 - p[ihi, j] * fac2;
            }
            double ytry = func.funk(ptry);
            if (ytry < y[ihi])
            {
                y[ihi] = ytry;
                for (int j = 0; j < ndim; j++)
                {
                    psum[j] += ptry[j] - p[ihi, j];
                    p[ihi, j] = ptry[j];
                }
            }
            return ytry;
        }
    }
}
 

你可能感兴趣的:(C#数值计算,Numerical,Recipes,c#,算法,数值计算,数学建模)