public MinimizationOutput1D FindMinimum(IObjectiveFunction1D objective, double lower_bound, double upper_bound)
        {
            if (!(objective is ObjectiveChecker1D))
            {
                objective = new ObjectiveChecker1D(objective, this.ValueChecker, null, null);
            }

            if (upper_bound <= lower_bound)
            {
                throw new OptimizationException("Lower bound must be lower than upper bound.");
            }

            double        middle_point_x = lower_bound + (upper_bound - lower_bound) / (1 + _golden_ratio);
            IEvaluation1D lower          = objective.Evaluate(lower_bound);
            IEvaluation1D middle         = objective.Evaluate(middle_point_x);
            IEvaluation1D upper          = objective.Evaluate(upper_bound);

            int expansion_steps = 0;

            while ((expansion_steps < this.MaximumExpansionSteps) && (upper.Value < middle.Value || lower.Value < middle.Value))
            {
                if (lower.Value < middle.Value)
                {
                    lower_bound = 0.5 * (upper_bound + lower_bound) - this.LowerExpansionFactor * 0.5 * (upper_bound - lower_bound);
                    lower       = objective.Evaluate(lower_bound);
                }

                if (upper.Value < middle.Value)
                {
                    upper_bound = 0.5 * (upper_bound + lower_bound) + this.UpperExpansionFactor * 0.5 * (upper_bound - lower_bound);
                    upper       = objective.Evaluate(upper_bound);
                }

                middle_point_x = lower_bound + (upper_bound - lower_bound) / (1 + _golden_ratio);
                middle         = objective.Evaluate(middle_point_x);

                expansion_steps += 1;
            }

            if (upper.Value < middle.Value || lower.Value < middle.Value)
            {
                throw new OptimizationException("Lower and upper bounds do not necessarily bound a minimum.");
            }

            int iterations = 0;

            while (Math.Abs(upper.Point - lower.Point) > this.XTolerance && iterations < this.MaximumIterations)
            {
                double test_x = lower.Point + (upper.Point - middle.Point);
                var    test   = objective.Evaluate(test_x);

                if (test.Point < middle.Point)
                {
                    if (test.Value > middle.Value)
                    {
                        lower = test;
                    }
                    else
                    {
                        upper  = middle;
                        middle = test;
                    }
                }
                else
                {
                    if (test.Value > middle.Value)
                    {
                        upper = test;
                    }
                    else
                    {
                        lower  = middle;
                        middle = test;
                    }
                }

                iterations += 1;
            }

            if (iterations == this.MaximumIterations)
            {
                throw new MaximumIterationsException("Max iterations reached.");
            }
            else
            {
                return(new MinimizationOutput1D(middle, iterations, ExitCondition.BoundTolerance));
            }
        }
 public CheckedEvaluation1D(ObjectiveChecker1D checker, IEvaluation1D evaluation)
 {
     this.Checker         = checker;
     this.InnerEvaluation = evaluation;
 }