public static ScalarMinimizationResult Minimum(IScalarObjectiveFunction objective, double lowerBound, double upperBound, double xTolerance = 1e-5, int maxIterations = 1000) { if (upperBound <= lowerBound) { throw new OptimizationException("Lower bound must be lower than upper bound."); } double middlePointX = lowerBound + (upperBound - lowerBound) / (1 + Constants.GoldenRatio); IScalarObjectiveFunctionEvaluation lower = objective.Evaluate(lowerBound); IScalarObjectiveFunctionEvaluation middle = objective.Evaluate(middlePointX); IScalarObjectiveFunctionEvaluation upper = objective.Evaluate(upperBound); ValueChecker(lower.Value, lowerBound); ValueChecker(middle.Value, middlePointX); ValueChecker(upper.Value, upperBound); int iterations = 0; while (Math.Abs(upper.Point - lower.Point) > xTolerance && iterations < maxIterations) { double testX = lower.Point + (upper.Point - middle.Point); var test = objective.Evaluate(testX); ValueChecker(test.Value, testX); 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 == maxIterations) { throw new MaximumIterationsException("Max iterations reached."); } return(new ScalarMinimizationResult(middle, iterations, ExitCondition.BoundTolerance)); }
public static ScalarMinimizationResult Minimum(IScalarObjectiveFunction objective, double lowerBound, double upperBound, double xTolerance = 1e-5, int maxIterations = 1000, int maxExpansionSteps = 10, double lowerExpansionFactor = 2.0, double upperExpansionFactor = 2.0) { if (upperBound <= lowerBound) { throw new OptimizationException("Lower bound must be lower than upper bound."); } double middlePointX = lowerBound + (upperBound - lowerBound) / (1 + Constants.GoldenRatio); IScalarObjectiveFunctionEvaluation lower = objective.Evaluate(lowerBound); IScalarObjectiveFunctionEvaluation middle = objective.Evaluate(middlePointX); IScalarObjectiveFunctionEvaluation upper = objective.Evaluate(upperBound); ValueChecker(lower.Value); ValueChecker(middle.Value); ValueChecker(upper.Value); int expansionSteps = 0; while ((expansionSteps < maxExpansionSteps) && (upper.Value < middle.Value || lower.Value < middle.Value)) { if (lower.Value < middle.Value) { lowerBound = 0.5 * (upperBound + lowerBound) - lowerExpansionFactor * 0.5 * (upperBound - lowerBound); lower = objective.Evaluate(lowerBound); } if (upper.Value < middle.Value) { upperBound = 0.5 * (upperBound + lowerBound) + upperExpansionFactor * 0.5 * (upperBound - lowerBound); upper = objective.Evaluate(upperBound); } middlePointX = lowerBound + (upperBound - lowerBound) / (1 + Constants.GoldenRatio); middle = objective.Evaluate(middlePointX); expansionSteps += 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) > xTolerance && iterations < maxIterations) { // Recompute middle point on each iteration to avoid loss of precision middlePointX = lower.Point + (upper.Point - lower.Point) / (1 + Constants.GoldenRatio); middle = objective.Evaluate(middlePointX); ValueChecker(middle.Value); double testX = lower.Point + (upper.Point - middle.Point); var test = objective.Evaluate(testX); ValueChecker(test.Value); if (test.Point < middle.Point) { if (test.Value > middle.Value) { lower = test; } else { upper = middle; } } else { if (test.Value > middle.Value) { upper = test; } else { lower = middle; } } iterations += 1; } if (iterations == maxIterations) { throw new MaximumIterationsException("Max iterations reached."); } return(new ScalarMinimizationResult(middle, iterations, ExitCondition.BoundTolerance)); }
public ScalarMinimizationResult(IScalarObjectiveFunctionEvaluation functionInfo, int iterations, ExitCondition reasonForExit) { FunctionInfoAtMinimum = functionInfo; Iterations = iterations; ReasonForExit = reasonForExit; }