コード例 #1
0
        /// <summary>
        /// Performs one iteration of the secant method on the <paramref name="bracket"/> interval.
        /// </summary>
        /// <param name="bracket">The bracket.</param>
        /// <param name="values">The values.</param>
        /// <returns>System.Double.</returns>
        private double Secant(Bracket bracket, ref FunctionValues values)
        {
            var a = bracket.Start;
            var b = bracket.End;

            var dφa = values.dφ(a);
            var dφb = values.dφ(b);

            var c = (a * dφb - b * dφa) / (dφb - dφa);

            return(c);
        }
コード例 #2
0
        /// <summary>
        /// Determines if the algorithm should terminate, given the currently selected step width <paramref name="α" />
        /// and the shared <paramref name="values"/>.
        /// </summary>
        /// <param name="values">The values.</param>
        /// <param name="α">The selected step width.</param>
        /// <returns><see langword="true" /> if the line search should terminate, <see langword="false" /> otherwise.</returns>
        private bool ShouldTerminate(double α, ref FunctionValues values)
        {
            // calculate the function values at α
            var φα  = values.φ(α);
            var dφα = values.dφ(α);

            // delegate
            return(ShouldTerminate(α, values.φ0, values.dφ0, φα, dφα));
        }
コード例 #3
0
        /// <summary>
        /// Updates the <paramref name="current" /> bracketing interval around the midpoint <paramref name="c" />.
        /// </summary>
        /// <param name="current">The current bracketing interval.</param>
        /// <param name="c">The midpoint.</param>
        /// <param name="values">The values.</param>
        /// <returns>Bracket.</returns>
        /// <exception cref="System.NotImplementedException"></exception>
        private Bracket UpdateBracketing(Bracket current, double c, ref FunctionValues values)
        {
            // we do not check for infinity here, as this will be handled in U0
            Debug.Assert(!Double.IsNaN(c), "!Double.IsNaN(c)");

            // prefetch
            var θ = _θ; // theta
            var ε = _ε; // epsilon

            // helpers
            var a = current.Start;
            var b = current.End;

            // U0: if the midpoint is out of range of the current bracketing
            // interval, stay where we are.
            if (c < a || c > b)
            {
                return(current);
            }

            // U1
            var dφc = values.dφ(c);

            if (dφc >= 0.0D)
            {
                return(new Bracket(start: a, end: c));
            }

            // U2
            var φc = values.φ(c);

            if (φc <= values.φ0 + ε)
            {
                return(new Bracket(start: c, end: b));
            }

            // U3
            return(UpdateBracketInRange(start: a, end: c, values: ref values));
        }
コード例 #4
0
        /// <summary>
        /// Updates the bracketing in range <see cref="start" /> to <see cref="end" />.
        /// </summary>
        /// <param name="start">The starting point.</param>
        /// <param name="end">The end point.</param>
        /// <param name="values">The values.</param>
        /// <returns>Bracket.</returns>
        private Bracket UpdateBracketInRange(double start, double end, ref FunctionValues values)
        {
            Debug.Assert(start.IsFinite(), "start.IsFinite()");
            Debug.Assert(end.IsFinite(), "end.IsFinite()");

            // prefetch
            var θ  = _θ; // theta
            var ɛ  = _ε; // epsilon
            var φ0 = values.φ0;

            var currentStart = start;
            var currentEnd   = end;

            var previousD = double.NaN;

            while (true) // TODO: bug in disguise?
            {
                // U3a
                var d = (1 - θ) * currentStart + θ * currentEnd;
                Debug.Assert(d != previousD, "d != previousD"); // NOTE that this case is not in the paper
                previousD = d;

                if (values.dφ(d) >= 0.0D)
                {
                    return(new Bracket(start: currentStart, end: d));
                }

                // U3b: close in from the left
                if (values.φ(d) <= φ0 + ɛ)
                {
                    currentStart = d;
                    continue;
                }

                // U3c: close in from the right
                currentEnd = d;
            }
        }
コード例 #5
0
        /// <summary>
        /// Brackets the starting point <paramref name="α"/>.
        /// </summary>
        /// <param name="α">The starting point.</param>
        /// <param name="values">The values.</param>
        /// <returns>Bracket.</returns>
        /// <exception cref="System.NotImplementedException"></exception>
        private Bracket BracketStartingPoint(double α, FunctionValues values)
        {
            // prefetch
            var ρ = _ρ; // rho
            var θ = _θ; // theta
            var ε = _ε; // epsilon

            // make sure the parameters are in range
            Debug.Assert(ρ > 1, "ρ > 1");
            Debug.Assert(θ > 0 && θ < 1, "θ > 0 && θ < 1");
            Debug.Assert(α >= 0, "α >= 0");

            // B0: initialize the current step value cj and keep track of the values in a stack
            var c         = α;
            var previousC = new Stack <double>();
            var φ0        = values.φ0;

            // TODO: set a maximum iteration count
            var maxBracketingIterations = _maxBracketingIterations;

            for (var j = 0; j < maxBracketingIterations; ++j)
            {
                // register the current step value
                previousC.Push(c);

                // determine the gradient at the current step length
                var dφc = values.dφ(c);

                // B1: if we find our currently selected end value to be ascending,
                // then backtrack the starting value to the last descend.
                // Note that we may end up here in the first iteration also
                // if the start point generation yields a problematic result.
                if (dφc >= 0)
                {
                    var end = c;

                    // find the most recent step selection c smaller cj that resulted
                    // in a function value less than the starting point.
                    // Since we just added cj, we'll just throw that away.
                    previousC.Pop();
                    while (previousC.Count > 0)
                    {
                        c = previousC.Pop();
                        if (values.φ(c) > φ0 + ε)
                        {
                            continue;
                        }

                        var start = c;
                        return(new Bracket(start, end));
                    }

                    // at this point there was no good starting point.
                    // sadly, this point is not handled in the paper, so
                    // we'll just throw out 0 as the starting point and hope for the best.
                    return(new Bracket(0, end));
                }

                // B2: If, for some reason, we are on a descending direction, yet the
                // current function value is larger than what we started with, then
                // we know a minimum must exist between the current point and the start.
                // By using the secant method, we zoom in the range until we find a valid
                // search region.
                if (values.φ(c) > φ0 + ε)
                {
                    return(UpdateBracketInRange(start: 0.0D, end: c, values: ref values));
                }

                // B3: At this point, we are still descending and we did not skip
                // any minima as far as we know, so we'll increase our step size.
                c = ρ * c;
            }

            // welp
            return(new Bracket(0, c));
        }