Beispiel #1
0
        /// <summary>
        /// Finds a minimum of a function by the BFGS quasi-Newton method
        /// This uses the function and it's gradient (partial derivatives in each direction) and approximates the Hessian
        /// </summary>
        /// <param name="initialGuess">An initial guess</param>
        /// <param name="functionValue">Evaluates the function at a point</param>
        /// <param name="functionGradient">Evaluates the gradient of the function at a point</param>
        /// <returns>The minimum found</returns>
        public static Vector <double> Solve(Vector initialGuess, Func <Vector <double>, double> functionValue, Func <Vector <double>, Vector <double> > functionGradient)
        {
            var objectiveFunction = ObjectiveFunction.Gradient(functionValue, functionGradient);

            objectiveFunction.EvaluateAt(initialGuess);

            int dim  = initialGuess.Count;
            int iter = 0;
            // H represents the approximation of the inverse hessian matrix
            // it is updated via the Sherman–Morrison formula (http://en.wikipedia.org/wiki/Sherman%E2%80%93Morrison_formula)
            Matrix <double> H = DenseMatrix.CreateIdentity(dim);

            Vector <double> x     = initialGuess;
            Vector <double> x_old = x;
            Vector <double> grad;
            WolfeLineSearch wolfeLineSearch = new WeakWolfeLineSearch(1e-4, 0.9, 1e-5, 200);

            do
            {
                // search along the direction of the gradient
                grad = objectiveFunction.Gradient;
                Vector <double> p = -1 * H * grad;
                var             lineSearchResult = wolfeLineSearch.FindConformingStep(objectiveFunction, p, 1.0);
                double          rate             = lineSearchResult.FinalStep;
                x = x + (rate * p);
                Vector <double> grad_old = grad;

                // update the gradient
                objectiveFunction.EvaluateAt(x);
                grad = objectiveFunction.Gradient;// functionGradient(x);

                Vector <double> s = x - x_old;
                Vector <double> y = grad - grad_old;

                double rho = 1.0 / (y * s);
                if (iter == 0)
                {
                    // set up an initial hessian
                    H = ((y * s) / (y * y)) * DenseMatrix.CreateIdentity(dim);
                }

                var sM = s.ToColumnMatrix();
                var yM = y.ToColumnMatrix();

                // Update the estimate of the hessian
                H = (H
                     - (rho * ((sM * (yM.TransposeThisAndMultiply(H))) + (H * yM).TransposeAndMultiply(sM))))
                    + (rho * rho * (y.DotProduct(H * y) + (1.0 / rho)) * (sM.TransposeAndMultiply(sM)));
                x_old = x;
                iter++;
            }while ((grad.InfinityNorm() > GradientTolerance) && (iter < MaxIterations));

            return(x);
        }
Beispiel #2
0
        /// <summary>
        /// Find the minimum of the objective function given lower and upper bounds
        /// </summary>
        /// <param name="objective">The objective function, must support a gradient</param>
        /// <param name="initialGuess">The initial guess</param>
        /// <returns>The MinimizationResult which contains the minimum and the ExitCondition</returns>
        public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector <double> initialGuess)
        {
            if (!objective.IsGradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for BFGS minimization.");
            }

            objective.EvaluateAt(initialGuess);
            ValidateGradientAndObjective(objective);

            // Check that we're not already done
            ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0);

            if (currentExitCondition != ExitCondition.None)
            {
                return(new MinimizationResult(objective, 0, currentExitCondition));
            }

            // Set up line search algorithm
            var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.9, Math.Max(ParameterTolerance, 1e-10), 1000);

            // First step
            var inversePseudoHessian = CreateMatrix.DenseIdentity <double>(initialGuess.Count);
            var lineSearchDirection  = -objective.Gradient;
            var stepSize             = 100 * GradientTolerance / (lineSearchDirection * lineSearchDirection);

            var previousPoint = objective;

            LineSearchResult lineSearchResult;

            try
            {
                lineSearchResult = lineSearcher.FindConformingStep(objective, lineSearchDirection, stepSize);
            }
            catch (OptimizationException e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }
            catch (ArgumentException e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }

            var candidate = lineSearchResult.FunctionInfoAtMinimum;

            ValidateGradientAndObjective(candidate);

            var gradient = candidate.Gradient;
            var step     = candidate.Point - initialGuess;

            // Subsequent steps
            Matrix <double> I = CreateMatrix.DiagonalIdentity <double>(initialGuess.Count);
            int             iterations;
            int             totalLineSearchSteps = lineSearchResult.Iterations;
            int             iterationsWithNontrivialLineSearch = lineSearchResult.Iterations > 0 ? 0 : 1;

            iterations = DoBfgsUpdate(ref currentExitCondition, lineSearcher, ref inversePseudoHessian, ref lineSearchDirection, ref previousPoint, ref lineSearchResult, ref candidate, ref step, ref totalLineSearchSteps, ref iterationsWithNontrivialLineSearch);

            if (iterations == MaximumIterations && currentExitCondition == ExitCondition.None)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations));
            }

            return(new MinimizationWithLineSearchResult(candidate, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch));
        }
Beispiel #3
0
        public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector <double> initialGuess)
        {
            if (!objective.IsGradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for Newton minimization.");
            }

            if (!objective.IsHessianSupported)
            {
                throw new IncompatibleObjectiveException("Hessian not supported in objective function, but required for Newton minimization.");
            }

            // Check that we're not already done
            objective.EvaluateAt(initialGuess);
            ValidateGradient(objective);
            if (ExitCriteriaSatisfied(objective.Gradient))
            {
                return(new MinimizationResult(objective, 0, ExitCondition.AbsoluteGradient));
            }

            // Set up line search algorithm
            var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.9, 1e-4, maxIterations: 1000);

            // Subsequent steps
            int  iterations           = 0;
            int  totalLineSearchSteps = 0;
            int  iterationsWithNontrivialLineSearch = 0;
            bool tmpLineSearch = false;

            while (!ExitCriteriaSatisfied(objective.Gradient) && iterations < MaximumIterations)
            {
                ValidateHessian(objective);

                var searchDirection = objective.Hessian.LU().Solve(-objective.Gradient);
                if (searchDirection * objective.Gradient >= 0)
                {
                    searchDirection = -objective.Gradient;
                    tmpLineSearch   = true;
                }

                if (UseLineSearch || tmpLineSearch)
                {
                    LineSearchResult result;
                    try
                    {
                        result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0);
                    }
                    catch (Exception e)
                    {
                        throw new InnerOptimizationException("Line search failed.", e);
                    }

                    iterationsWithNontrivialLineSearch += result.Iterations > 0 ? 1 : 0;
                    totalLineSearchSteps += result.Iterations;
                    objective             = result.FunctionInfoAtMinimum;
                }
                else
                {
                    objective.EvaluateAt(objective.Point + searchDirection);
                }

                ValidateGradient(objective);

                tmpLineSearch = false;
                iterations   += 1;
            }

            if (iterations == MaximumIterations)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations));
            }

            return(new MinimizationWithLineSearchResult(objective, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch));
        }
Beispiel #4
0
        public MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector <double> initial_guess)
        {
            if (!objective.GradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for Newton minimization.");
            }

            if (!objective.HessianSupported)
            {
                throw new IncompatibleObjectiveException("Hessian not supported in objective function, but required for Newton minimization.");
            }

            if (!(objective is ObjectiveChecker))
            {
                objective = new ObjectiveChecker(objective, this.ValidateObjective, this.ValidateGradient, this.ValidateHessian);
            }

            IEvaluation initial_eval = objective.Evaluate(initial_guess);

            // Check that we're not already done
            if (this.ExitCriteriaSatisfied(initial_guess, initial_eval.Gradient))
            {
                return(new MinimizationOutput(initial_eval, 0, ExitCondition.AbsoluteGradient));
            }

            // Set up line search algorithm
            var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9, 1e-4, max_iterations: 1000);

            // Declare state variables
            IEvaluation      candidate_point = initial_eval;
            Vector <double>  search_direction;
            LineSearchOutput result;

            // Subsequent steps
            int  iterations = 0;
            int  total_line_search_steps = 0;
            int  iterations_with_nontrivial_line_search = 0;
            int  steepest_descent_resets = 0;
            bool tmp_line_search         = false;

            while (!this.ExitCriteriaSatisfied(candidate_point.Point, candidate_point.Gradient) && iterations < this.MaximumIterations)
            {
                search_direction = candidate_point.Hessian.LU().Solve(-candidate_point.Gradient);

                if (search_direction * candidate_point.Gradient >= 0)
                {
                    search_direction         = -candidate_point.Gradient;
                    steepest_descent_resets += 1;
                    tmp_line_search          = true;
                }

                if (this.UseLineSearch || tmp_line_search)
                {
                    try
                    {
                        result = line_searcher.FindConformingStep(objective, candidate_point, search_direction, 1.0);
                    }
                    catch (Exception e)
                    {
                        throw new InnerOptimizationException("Line search failed.", e);
                    }
                    iterations_with_nontrivial_line_search += result.Iterations > 0 ? 1 : 0;
                    total_line_search_steps += result.Iterations;
                    candidate_point          = result.FunctionInfoAtMinimum;
                }
                else
                {
                    candidate_point = objective.Evaluate(candidate_point.Point + search_direction);
                }

                tmp_line_search = false;

                iterations += 1;
            }

            if (iterations == this.MaximumIterations)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations));
            }

            return(new MinimizationWithLineSearchOutput(candidate_point, iterations, ExitCondition.AbsoluteGradient, total_line_search_steps, iterations_with_nontrivial_line_search));
        }
Beispiel #5
0
        public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector <double> initialGuess)
        {
            if (!objective.IsGradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for ConjugateGradient minimization.");
            }

            objective.EvaluateAt(initialGuess);
            var gradient = objective.Gradient;

            ValidateGradient(objective);

            // Check that we're not already done
            if (ExitCriteriaSatisfied(initialGuess, gradient))
            {
                return(new MinimizationResult(objective, 0, ExitCondition.AbsoluteGradient));
            }

            // Set up line search algorithm
            var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, 1000);

            // First step
            var    steepestDirection = -gradient;
            var    searchDirection   = steepestDirection;
            double initialStepSize   = 100 * GradientTolerance / (gradient * gradient);

            LineSearchResult result;

            try
            {
                result = lineSearcher.FindConformingStep(objective, searchDirection, initialStepSize);
            }
            catch (Exception e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }

            objective = result.FunctionInfoAtMinimum;
            ValidateGradient(objective);

            double stepSize = result.FinalStep;

            // Subsequent steps
            int iterations           = 1;
            int totalLineSearchSteps = result.Iterations;
            int iterationsWithNontrivialLineSearch = result.Iterations > 0 ? 0 : 1;
            int steepestDescentResets = 0;

            while (!ExitCriteriaSatisfied(objective.Point, objective.Gradient) && iterations < MaximumIterations)
            {
                var previousSteepestDirection = steepestDirection;
                steepestDirection = -objective.Gradient;
                var searchDirectionAdjuster = Math.Max(0, steepestDirection * (steepestDirection - previousSteepestDirection) / (previousSteepestDirection * previousSteepestDirection));
                searchDirection = steepestDirection + searchDirectionAdjuster * searchDirection;
                if (searchDirection * objective.Gradient >= 0)
                {
                    searchDirection        = steepestDirection;
                    steepestDescentResets += 1;
                }

                try
                {
                    result = lineSearcher.FindConformingStep(objective, searchDirection, stepSize);
                }
                catch (Exception e)
                {
                    throw new InnerOptimizationException("Line search failed.", e);
                }

                iterationsWithNontrivialLineSearch += result.Iterations == 0 ? 1 : 0;
                totalLineSearchSteps += result.Iterations;
                stepSize              = result.FinalStep;
                objective             = result.FunctionInfoAtMinimum;
                iterations           += 1;
            }

            if (iterations == MaximumIterations)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations));
            }

            return(new MinimizationWithLineSearchResult(objective, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch));
        }
Beispiel #6
0
        public MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector <double> initial_guess)
        {
            if (!objective.GradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for ConjugateGradient minimization.");
            }

            if (!(objective is ObjectiveChecker))
            {
                objective = new ObjectiveChecker(objective, this.ValidateObjective, this.ValidateGradient, null);
            }

            IEvaluation initial_eval = objective.Evaluate(initial_guess);
            var         gradient     = initial_eval.Gradient;

            // Check that we're not already done
            if (this.ExitCriteriaSatisfied(initial_guess, gradient))
            {
                return(new MinimizationOutput(initial_eval, 0, ExitCondition.AbsoluteGradient));
            }

            // Set up line search algorithm
            var line_searcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, max_iterations: 1000);

            // Declare state variables
            IEvaluation     candidate_point;
            Vector <double> steepest_direction, previous_steepest_direction, search_direction;

            // First step
            steepest_direction = -gradient;
            search_direction   = steepest_direction;
            double           initial_step_size = 100 * this.GradientTolerance / (gradient * gradient);
            LineSearchOutput result;

            try
            {
                result = line_searcher.FindConformingStep(objective, initial_eval, search_direction, initial_step_size);
            }
            catch (Exception e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }

            candidate_point = result.FunctionInfoAtMinimum;

            double step_size = result.FinalStep;

            // Subsequent steps
            int iterations = 1;
            int total_line_search_steps = result.Iterations;
            int iterations_with_nontrivial_line_search = result.Iterations > 0 ? 0 : 1;
            int steepest_descent_resets = 0;

            while (!this.ExitCriteriaSatisfied(candidate_point.Point, candidate_point.Gradient) && iterations < this.MaximumIterations)
            {
                previous_steepest_direction = steepest_direction;
                steepest_direction          = -candidate_point.Gradient;
                var search_direction_adjuster = Math.Max(0, steepest_direction * (steepest_direction - previous_steepest_direction) / (previous_steepest_direction * previous_steepest_direction));

                //double prev_grad_mag = previous_steepest_direction*previous_steepest_direction;
                //double grad_overlap = steepest_direction*previous_steepest_direction;
                //double search_grad_overlap = candidate_point.Gradient*search_direction;

                //if (iterations % initial_guess.Count == 0 || (Math.Abs(grad_overlap) >= 0.2 * prev_grad_mag) || (-2 * prev_grad_mag >= search_grad_overlap) || (search_grad_overlap >= -0.2 * prev_grad_mag))
                //    search_direction = steepest_direction;
                //else
                //    search_direction = steepest_direction + search_direction_adjuster * search_direction;

                search_direction = steepest_direction + search_direction_adjuster * search_direction;
                if (search_direction * candidate_point.Gradient >= 0)
                {
                    search_direction         = steepest_direction;
                    steepest_descent_resets += 1;
                }

                try
                {
                    result = line_searcher.FindConformingStep(objective, candidate_point, search_direction, step_size);
                }
                catch (Exception e)
                {
                    throw new InnerOptimizationException("Line search failed.", e);
                }

                iterations_with_nontrivial_line_search += result.Iterations > 0 ? 1 : 0;
                total_line_search_steps += result.Iterations;

                step_size       = result.FinalStep;
                candidate_point = result.FunctionInfoAtMinimum;

                iterations += 1;
            }

            if (iterations == this.MaximumIterations)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations));
            }

            return(new MinimizationWithLineSearchOutput(candidate_point, iterations, ExitCondition.AbsoluteGradient, total_line_search_steps, iterations_with_nontrivial_line_search));
        }
Beispiel #7
0
        /// <summary>
        /// Find the minimum of the objective function given lower and upper bounds
        /// </summary>
        /// <param name="objective">The objective function, must support a gradient</param>
        /// <param name="initialGuess">The initial guess</param>
        /// <returns>The MinimizationResult which contains the minimum and the ExitCondition</returns>
        public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector <double> initialGuess)
        {
            if (!objective.IsGradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for L-BFGS minimization.");
            }

            objective.EvaluateAt(initialGuess);
            ValidateGradientAndObjective(objective);

            // Check that we're not already done
            ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0);

            if (currentExitCondition != ExitCondition.None)
            {
                return(new MinimizationResult(objective, 0, currentExitCondition));
            }

            // Set up line search algorithm
            var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.9, Math.Max(ParameterTolerance, 1e-10), 1000);

            // First step

            var lineSearchDirection = -objective.Gradient;
            var stepSize            = (100 * GradientTolerance) / (lineSearchDirection * lineSearchDirection);

            var previousPoint = objective;

            LineSearchResult lineSearchResult;

            try
            {
                lineSearchResult = lineSearcher.FindConformingStep(objective, lineSearchDirection, stepSize);
            }
            catch (OptimizationException e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }
            catch (ArgumentException e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }

            var candidate = lineSearchResult.FunctionInfoAtMinimum;

            ValidateGradientAndObjective(candidate);

            var gradient  = candidate.Gradient;
            var step      = candidate.Point - initialGuess;
            var yk        = candidate.Gradient - previousPoint.Gradient;
            var ykhistory = new List <Vector <double> >()
            {
                yk
            };
            var skhistory = new List <Vector <double> >()
            {
                step
            };
            var rhokhistory = new List <double>()
            {
                1.0 / yk.DotProduct(step)
            };

            // Subsequent steps
            int iterations           = 1;
            int totalLineSearchSteps = lineSearchResult.Iterations;
            int iterationsWithNontrivialLineSearch = lineSearchResult.Iterations > 0 ? 0 : 1;

            previousPoint = candidate;
            while ((iterations++ < MaximumIterations) && (previousPoint.Gradient.Norm(2) >= GradientTolerance))
            {
                lineSearchDirection = -ApplyLbfgsUpdate(previousPoint, ykhistory, skhistory, rhokhistory);
                var directionalDerivative = previousPoint.Gradient.DotProduct(lineSearchDirection);
                if (directionalDerivative > 0)
                {
                    throw new InnerOptimizationException("Direction is not a descent direction.");
                }
                try
                {
                    lineSearchResult = lineSearcher.FindConformingStep(previousPoint, lineSearchDirection, 1.0);
                }
                catch (OptimizationException e)
                {
                    throw new InnerOptimizationException("Line search failed.", e);
                }
                catch (ArgumentException e)
                {
                    throw new InnerOptimizationException("Line search failed.", e);
                }
                iterationsWithNontrivialLineSearch += lineSearchResult.Iterations > 0 ? 1 : 0;
                totalLineSearchSteps += lineSearchResult.Iterations;

                candidate            = lineSearchResult.FunctionInfoAtMinimum;
                currentExitCondition = ExitCriteriaSatisfied(candidate, previousPoint, iterations);
                if (currentExitCondition != ExitCondition.None)
                {
                    break;
                }
                step = candidate.Point - previousPoint.Point;
                yk   = candidate.Gradient - previousPoint.Gradient;
                ykhistory.Add(yk);
                skhistory.Add(step);
                rhokhistory.Add(1.0 / yk.DotProduct(step));
                previousPoint = candidate;
                if (ykhistory.Count > Memory)
                {
                    ykhistory.RemoveAt(0);
                    skhistory.RemoveAt(0);
                    rhokhistory.RemoveAt(0);
                }
            }

            if ((iterations == MaximumIterations) && (currentExitCondition == ExitCondition.None))
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations));
            }

            return(new MinimizationWithLineSearchResult(candidate, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch));
        }
        public MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector <double> initial_guess)
        {
            if (!objective.GradientSupported)
            {
                throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for BFGS minimization.");
            }

            if (!(objective is ObjectiveChecker))
            {
                objective = new ObjectiveChecker(objective, this.ValidateObjective, this.ValidateGradient, null);
            }

            IEvaluation initial_eval = objective.Evaluate(initial_guess);

            // Check that we're not already done
            ExitCondition current_exit_condition = this.ExitCriteriaSatisfied(initial_eval, null);

            if (current_exit_condition != ExitCondition.None)
            {
                return(new MinimizationOutput(initial_eval, 0, current_exit_condition));
            }

            // Set up line search algorithm
            var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9, Math.Max(this.ParameterTolerance, 1e-10), max_iterations: 1000);

            // Declare state variables
            IEvaluation     candidate_point, previous_point;
            double          step_size;
            Vector <double> gradient, step, search_direction;
            Matrix <double> inverse_pseudo_hessian;

            // First step
            inverse_pseudo_hessian = LinearAlgebra.Double.DiagonalMatrix.CreateIdentity(initial_guess.Count);
            search_direction       = -initial_eval.Gradient;
            step_size = 100 * this.GradientTolerance / (search_direction * search_direction);

            LineSearchOutput result;

            try
            {
                result = line_searcher.FindConformingStep(objective, initial_eval, search_direction, step_size);
            }
            catch (Exception e)
            {
                throw new InnerOptimizationException("Line search failed.", e);
            }

            previous_point  = initial_eval;
            candidate_point = result.FunctionInfoAtMinimum;
            gradient        = candidate_point.Gradient;
            step            = candidate_point.Point - initial_guess;
            step_size       = result.FinalStep;

            // Subsequent steps
            Matrix <double> I = LinearAlgebra.Double.DiagonalMatrix.CreateIdentity(initial_guess.Count);
            int             iterations;
            int             total_line_search_steps = result.Iterations;
            int             iterations_with_nontrivial_line_search = result.Iterations > 0 ? 0 : 1;
            int             steepest_descent_resets = 0;

            for (iterations = 1; iterations < this.MaximumIterations; ++iterations)
            {
                var y = candidate_point.Gradient - previous_point.Gradient;

                double sy = step * y;
                inverse_pseudo_hessian = inverse_pseudo_hessian + ((sy + y * inverse_pseudo_hessian * y) / Math.Pow(sy, 2.0)) * step.OuterProduct(step) - ((inverse_pseudo_hessian * y.ToColumnMatrix()) * step.ToRowMatrix() + step.ToColumnMatrix() * (y.ToRowMatrix() * inverse_pseudo_hessian)) * (1.0 / sy);
                search_direction       = -inverse_pseudo_hessian * candidate_point.Gradient;

                if (search_direction * candidate_point.Gradient >= 0.0)
                {
                    search_direction         = -candidate_point.Gradient;
                    inverse_pseudo_hessian   = LinearAlgebra.Double.DiagonalMatrix.CreateIdentity(initial_guess.Count);
                    steepest_descent_resets += 1;
                }
                //else if (search_direction * candidate_point.Gradient >= -this.GradientTolerance*this.GradientTolerance)
                //{
                //    search_direction = -candidate_point.Gradient;
                //    inverse_pseudo_hessian = LinearAlgebra.Double.DiagonalMatrix.Identity(initial_guess.Count);
                //    steepest_descent_resets += 1;
                //}

                try
                {
                    result = line_searcher.FindConformingStep(objective, candidate_point, search_direction, 1.0);
                }
                catch (Exception e)
                {
                    throw new InnerOptimizationException("Line search failed.", e);
                }

                iterations_with_nontrivial_line_search += result.Iterations > 0 ? 1 : 0;
                total_line_search_steps += result.Iterations;

                step_size       = result.FinalStep;
                step            = result.FunctionInfoAtMinimum.Point - candidate_point.Point;
                previous_point  = candidate_point;
                candidate_point = result.FunctionInfoAtMinimum;

                current_exit_condition = this.ExitCriteriaSatisfied(candidate_point, previous_point);
                if (current_exit_condition != ExitCondition.None)
                {
                    break;
                }
            }

            if (iterations == this.MaximumIterations && current_exit_condition == ExitCondition.None)
            {
                throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations));
            }

            return(new MinimizationWithLineSearchOutput(candidate_point, iterations, current_exit_condition, total_line_search_steps, iterations_with_nontrivial_line_search));
        }