C#, Numerical Calculation - Chebyshev approximation method (Chebyshev approximation) calculation method and source program

using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// Chebyshev approximation
    /// </summary>
    public class Chebyshev
    {
        private int n { get; set; }
        private int m { get; set; }
        private double[] c { get; set; }
        private double a { get; set; }
        private double b { get; set; }

        public Chebyshev(double[] cc, double aa, double bb)
        {
            this.n = cc.Length;
            this.m = n;
            this.c = Globals.CopyFrom(cc);
            this.a = aa;
            this.b = bb;
        }

        public Chebyshev(double[] d)
        {
            this.n = d.Length;
            this.m = n;
            this.c = new double[n];
            this.a = -1.0;
            this.b = 1.0;

            c[n - 1] = d[n - 1];
            c[n - 2] = 2.0 * d[n - 2];
            for (int j = n - 3; j >= 0; j--)
            {
                c[j] = 2.0 * d[j] + c[j + 2];
                for (int i = j + 1; i < n - 2; i++)
                {
                    c[i] = (c[i] + c[i + 2]) / 2;
                }
                c[n - 2] /= 2;
                c[n - 1] /= 2;
            }
        }
        /*
        public Chebyshev(UniVarRealValueFun func, double aa, double bb)
        {
            new this(func, aa, bb, 50);
        }
        */
        /// <summary>
        /// Inverse of routine polycofs in Chebyshev: Given an array of polynomial
        /// coefficients d[0..n - 1], construct an equivalent Chebyshev object.
        /// </summary>
        /// <param name="func"></param>
        /// <param name="aa"></param>
        /// <param name="bb"></param>
        /// <param name="nn"></param>
        public Chebyshev(UniVarRealValueFun func, double aa, double bb, int nn = 50)
        {
            this.n = nn;
            this.m = nn;
            this.c = new double[n];
            this.a = aa;
            this.b = bb;

            double[] f = new double[n];
            double bma = 0.5 * (b - a);
            double bpa = 0.5 * (b + a);
            for (int k = 0; k < n; k++)
            {
                double y = Math.Cos(Math.PI * (k + 0.5) / n);
                f[k] = func.funk(y * bma + bpa);
            }
            double fac = 2.0 / n;
            for (int j = 0; j < n; j++)
            {
                double sum = 0.0;
                for (int k = 0; k < n; k++)
                {
                    sum += f[k] * Math.Cos(Math.PI * j * (k + 0.5) / n);
                }
                c[j] = fac * sum;
            }
        }

        public double eval(double x, int m)
        {
            double d = 0.0;
            double dd = 0.0;

            if ((x - a) * (x - b) > 0.0)
            {
                throw new Exception("x not in range in Chebyshev::eval");
            }
            double y = (2.0 * x - a - b) / (b - a);
            double y2 = 2.0 * (y);
            for (int j = m - 1; j > 0; j--)
            {
                double sv = d;
                d = y2 * d - dd + c[j];
                dd = sv;
            }
            return y * d - dd + 0.5 * c[0];
        }

        public double[] getc()
        {
            return c;
        }

        /// <summary>
        /// Return a new Chebyshev object that approximates the derivative of the
        /// existing function over the same range[a, b].
        /// </summary>
        /// <returns></returns>
        public Chebyshev derivative()
        {
            double[] cder = new double[n];
            cder[n - 1] = 0.0;
            cder[n - 2] = 2 * (n - 1) * c[n - 1];
            for (int j = n - 2; j > 0; j--)
            {
                cder[j - 1] = cder[j + 1] + 2 * j * c[j];
            }
            double con = 2.0 / (b - a);
            for (int j = 0; j < n; j++)
            {
                cder[j] *= con;
            }
            return new Chebyshev(cder, a, b);
        }

        /// <summary>
        /// Return a new Chebyshev object that approximates the indefinite integral of
        /// the existing function over the same range[a, b]. The constant of
        /// integration is set so that the integral vanishes at a.
        /// </summary>
        /// <returns></returns>
        public Chebyshev integral()
        {
            double sum = 0.0;
            double fac = 1.0;
            double[] cint = new double[n];
            double con = 0.25 * (b - a);
            for (int j = 1; j < n - 1; j++)
            {
                cint[j] = con * (c[j - 1] - c[j + 1]) / j;
                sum += fac * cint[j];
                fac = -fac;
            }
            cint[n - 1] = con * c[n - 2] / (n - 1);
            sum += fac * cint[n - 1];
            belt[0] = 2.0 * sum;
            return new Chebyshev(cint, a, b);
        }

        /// <summary>
        /// Polynomial coefficients from a Chebyshev fit.Given a coefficient array
        /// c[0..n-1], this routine returns a coefficient array d[0..n-1] such that
        /// sum(k= 0, n-1)dky^k = sum(k= 0, n-1)Tk(y)-c0/2. The method is Clenshaw's
        /// recurrence(5.8.11), but now applied algebraically rather than arithmetically.
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public double[] polycofs(int m)
        {
            double[] d = new double[m];
            double[] dd = new double[m];
            for (int j = 0; j < m; j++)
            {
                d[j] = 0.0;
                dd[j] = 0.0;
            }
            d[0] = c[m - 1];
            for (int j = m - 2; j > 0; j--)
            {
                for (int k = m - j; k > 0; k--)
                {
                    double s1v = d[k];
                    d[k] = 2.0 * d[k - 1] - dd[k];
                    dd[k] = s1v;
                }
                double s2v = d[0];
                d[0] = -dd[0] + c[j];
                dd[0] = s2v;
            }
            for (int j = m - 1; j > 0; j--)
            {
                d[j] = d[j - 1] - dd[j];
            }
            d[0] = -dd[0] + 0.5 * c[0];
            return d;
        }

        public int setm(double thresh)
        {
            while (m > 1 && Math.Abs(c[m - 1]) < thresh)
            {
                m--;
            }
            return m;
        }

        public double get(double x)
        {
            return eval(x, m);
        }

        public double[] polycofs()
        {
            return polycofs(m);
        }

        public static void pcshft(double a, double b, double[] d)
        {
            int n = d.Length;
            double cnst = 2.0 / (b - a);
            double fac = cnst;
            for (int j = 1; j < n; j++)
            {
                d[j] *= fac;
                fac *= cnst;
            }
            cnst = 0.5 * (a + b);
            for (int j = 0; j <= n - 2; j++)
            {
                for (int k = n - 2; k >= j; k--)
                {
                    d[k] -= cnst * d[k + 1];
                }
            }
        }

        public static void ipcshft(double a, double b, double[] d)
        {
            pcshft(-(2.0 + b + a) / (b - a), (2.0 - b - a) / (b - a),  d);
        }

    }
}
 

Guess you like

Origin blog.csdn.net/beijinghorn/article/details/132367859