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)); }
// try this for multiparameter optimization: https://numerics.mathdotnet.com/api/MathNet.Numerics.Optimization.TrustRegion/index.htm // Golden Section Minimizer public static Value Argmin(Value function, Value lowerBound, Value upperBound, Value tolerance, Netlist netlist, Style style, int s) { if (!(lowerBound is NumberValue) || !(upperBound is NumberValue)) { throw new Error("argmin: expecting numbers for lower and upper bounds"); } double lower = (lowerBound as NumberValue).value; double upper = (upperBound as NumberValue).value; if (lower > upper) { throw new Error("argmin: lower bound greater than upper bound"); } if (!(function is FunctionValue)) { throw new Error("argmin: expecting a function as first argument"); } FunctionValue closure = function as FunctionValue; if (closure.parameters.parameters.Count != 1) { throw new Error("argmin: initial values and function parameters have different lengths"); } IScalarObjectiveFunction objectiveFunction = ObjectiveFunction.ScalarValue( (double parameter) => { List <Value> arguments = new List <Value>(); arguments.Add(new NumberValue(parameter)); bool autoContinue = netlist.autoContinue; netlist.autoContinue = true; Value result = closure.ApplyReject(arguments, netlist, style, s); if (result == null) { throw new Error("Objective function returned null"); } netlist.autoContinue = autoContinue; if (!(result is NumberValue)) { throw new Error("Objective function must return a number, not: " + result.Format(style)); } KGui.gui.GuiOutputAppendText("argmin: parameter=" + Style.FormatSequence(arguments, ", ", x => x.Format(style)) + " => cost=" + result.Format(style) + Environment.NewLine); return((result as NumberValue).value); }); try { ScalarMinimizationResult result = GoldenSectionMinimizer.Minimum(objectiveFunction, lower, upper); if (result.ReasonForExit == ExitCondition.Converged || result.ReasonForExit == ExitCondition.BoundTolerance) { KGui.gui.GuiOutputAppendText("argmin: converged with parameter=" + result.MinimizingPoint + " and reason '" + result.ReasonForExit + "'" + Environment.NewLine); return(new NumberValue(result.MinimizingPoint)); } else { throw new Error("reason '" + result.ReasonForExit.ToString() + "'"); } } catch (Exception e) { throw new Error("argmin ended: " + ((e.InnerException == null) ? e.Message : e.InnerException.Message)); } // somehow we need to recatch the inner exception coming from CostAndGradient }
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 FindMinimum(IScalarObjectiveFunction objective, double lowerBound, double upperBound) { return(Minimum(objective, lowerBound, upperBound, XTolerance, MaximumIterations, MaximumExpansionSteps, LowerExpansionFactor, UpperExpansionFactor)); }
public ScalarMinimizationResult FindMinimum(IScalarObjectiveFunction objective, double lowerBound, double upperBound) { return(Minimum(objective, lowerBound, upperBound, XTolerance, MaximumIterations)); }