Example #1
0
        public static double Brent(
				FunctionOfTwoVariables f,
				double left,
				double right,
				double tolerance = 1e-6,
				double target = 0.0,
				double[] y = null
			)
        {
            // extra info that callers may not always want
            int iterationsUsed;
            double errorEstimate;

            return Brent(f, left, right, tolerance, target, out iterationsUsed, out errorEstimate, y);
        }
Example #2
0
        public static double Brent(
				FunctionOfTwoVariables g,
				double left,
				double right,
				double tolerance,
				double target,
				out int iterationsUsed,
				out double errorEstimate,
				double[] y
			)
        {
            if (tolerance <= 0.0)
            {
                string msg = string.Format("Tolerance must be positive. Received {0}.", tolerance);
                throw new ArgumentOutOfRangeException(msg);
            }

            errorEstimate = double.MaxValue;

            // Standardize the problem.  To solve g(x) = target,
            // solve f(x) = 0 where f(x) = g(x) - target.
            FunctionOfTwoVariables f = (x, y2) => g(x, y2) - target;

            // Implementation and notation based on Chapter 4 in
            // "Algorithms for Minimization without Derivatives"
            // by Richard Brent.

            double c, d, e, fa, fb, fc, tol, m, p, q, r, s;

            // set up aliases to match Brent's notation
            double a = left;
            double b = right;
            double t = tolerance;
            iterationsUsed = 0;

            fa = f(a, y);
            fb = f(b, y);

            // *************************************************
            // This is the where the exception is being raised
            if (fa * fb > 0.0)
            {
                string str = "Invalid starting bracket. Function must be above target on one end and below target on other end.";
                string msg = string.Format("{0} Target: {1}. f(left) = {2}. f(right) = {3}", str, target, fa + target, fb + target);
                throw new ArgumentException(msg);
            }
            // *************************************************

            label_int:
            c = a;
            fc = fa;
            d = e = b - a;
            label_ext:
            if (Math.Abs(fc) < Math.Abs(fb))
            {
                a = b;
                b = c;
                c = a;
                fa = fb;
                fb = fc;
                fc = fa;
            }

            iterationsUsed++;

            double machine_epsilon = Math.Pow(2.0, -53);
            tol = 2.0 * machine_epsilon * Math.Abs(b) + t;

            errorEstimate = m = 0.5 * (c - b);
            if (Math.Abs(m) > tol && fb != 0.0) // exact comparison with 0 is OK here
            {
                // See if bisection is forced
                if (Math.Abs(e) < tol || Math.Abs(fa) <= Math.Abs(fb))
                {
                    d = e = m;
                }
                else
                {
                    s = fb / fa;
                    if (a == c)
                    {
                        // linear interpolation
                        p = 2.0 * m * s;
                        q = 1.0 - s;
                    }
                    else
                    {
                        // Inverse quadratic interpolation
                        q = fa / fc;
                        r = fb / fc;
                        p = s * (2.0 * m * q * (q - r) - (b - a) * (r - 1.0));
                        q = (q - 1.0) * (r - 1.0) * (s - 1.0);
                    }
                    if (p > 0.0)
                        q = -q;
                    else
                        p = -p;
                    s = e;
                    e = d;
                    if (2.0 * p < 3.0 * m * q - Math.Abs(tol * q) && p < Math.Abs(0.5 * s * q))
                        d = p / q;
                    else
                        d = e = m;
                }
                a = b;
                fa = fb;
                if (Math.Abs(d) > tol)
                    b += d;
                else if (m > 0.0)
                    b += tol;
                else
                    b -= tol;
                if (iterationsUsed == maxIterations)
                    return b;

                fb = f(b, y);
                if ((fb > 0.0 && fc > 0.0) || (fb <= 0.0 && fc <= 0.0))
                    goto label_int;
                else
                    goto label_ext;
            }
            else
                return b;
        }