/// <summary> /// This method returns the zero of the <see cref="IObjectiveFunction"/> /// <pramref name="objectiveFunction"/>, determined with the given accuracy. /// </summary> /// <remarks> /// <i>x</i> is considered a zero if <i>|f(x)| < accuracy</i>. /// An initial guess must be supplied, as well as two values which /// must bracket the zero (i.e., either /// <i>f(x<sub>min</sub>) > 0</i> && /// <i>f(x<sub>max</sub>) < 0</i>, or /// <i>f(x<sub>min</sub>) < 0</i> && /// <i>f(x<sub>max</sub>) > 0</i> must be true). /// </remarks> /// <param name="objectiveFunction">The <see cref="IObjectiveFunction"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <param name="guess">Initial guess used to scan the range /// of the possible bracketing values.</param> /// <param name="xMin">Lower bracket.</param> /// <param name="xMax">Upper bracket.</param> /// <returns>The zero of the objective function.</returns> /// <exception cref="ApplicationException"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="MaxEvaluations"/>). /// </exception> public double Solve(IObjectiveFunction objectiveFunction, double xAccuracy, double guess, double xMin, double xMax) { #region Check that input data is valid if (xMin >= xMax) { throw new ArgumentException($"Solver minimum bracket ({xMin}) must be below maximum bracket ({xMax})."); } if (LowerBoundEnforced && xMin < LowerBound) { throw new ArgumentException( $"Solver minimum bracket ({xMin}) is less than lower bound ({LowerBound})."); } if (UpperBoundEnforced && xMax > _upperBound) { throw new ArgumentException( $"Solver maximum bracket ({xMax}) is more than upper bound ({_upperBound})."); } // Check if the guess is within specified range (xMin, xMax) // if (guess < xMin) { throw new ApplicationException($"Solver guess ({guess}) is less than minimum bracket ({xMin})."); } if (guess > xMax) { throw new ApplicationException($"Solver guess ({guess}) is more than maximum bracket ({xMax})."); } #endregion XMin = xMin; XMax = xMax; FXMin = objectiveFunction.Value(xMin); if (Math.Abs(FXMin) < xAccuracy) { return(xMin); } FXMax = objectiveFunction.Value(xMax); if (Math.Abs(FXMax) < xAccuracy) { return(xMax); } EvaluationNumber = 2; if (FXMin * FXMax >= 0.0) { throw new ApplicationException( $"Solver bounds must return different values with different signs; it returned {FXMin} and {FXMax}."); } Root = guess; return(SolveImpl(objectiveFunction, Math.Max(Math.Abs(xAccuracy), Double.Epsilon))); }
/// <summary> /// Overloaded constructor /// </summary> /// <param name="objective">A tour length objectiveulator object</param> /// <param name="initialSolution">An initial solution</param> /// <param name="swapPattern">A method for swapping the order of cities</param> public SteepestDecent(IObjectiveFunction objective, List<int> initialSolution, ICitySwapPattern swapMethod) { this.objective = objective; this.solution = initialSolution; this.currentTourLength = objective.Value(initialSolution); this.swapPattern = swapMethod; }
/// <summary> /// Implementation of the actual code to search for the zeroes of /// the <see cref="IObjectiveFunction"/>. /// </summary> /// <remarks> /// It assumes that: /// <list type="bullet"> /// <item> /// <description> /// <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/> form a valid bracket; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.FXMin"/> and <see cref="Solver1D.FXMax"/> contain the values of the /// function in <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/>; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.Root"/> was initialized to a valid initial guess. /// </description> /// </item> /// </list> /// </remarks> /// <param name="objectiveFunction">The <see cref="IObjectiveFunction"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <returns>The zero of the objective function.</returns> /// <exception cref="ApplicationException"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="Solver1D.MaxEvaluations"/>). /// </exception> protected override double SolveImpl(IObjectiveFunction objectiveFunction, double xAccuracy) { // Orient the search so that f>0 lies at root_+dx double dx; if (FXMin < 0.0) { dx = XMax - XMin; Root = XMin; } else { dx = XMin - XMax; Root = XMax; } while (EvaluationNumber++ < MaxEvaluations) { dx /= 2.0; double xMid = Root + dx; double fMid = objectiveFunction.Value(xMid); if (fMid <= 0.0) { Root = xMid; } if (Math.Abs(dx) < xAccuracy || fMid == 0.0) { return(Root); } } throw new ApplicationException("SlvMaxEval"); }
/// <summary> /// Constructor /// </summary> /// <param name="objective">A tour length objectiveulator object</param> /// <param name="initialSolution">An initial solution</param> public OrdinaryDecent(IObjectiveFunction objective, List<int> initialSolution) { this.objective = objective; this.solution = initialSolution; this.currentTourLength = objective.Value(initialSolution); this.swapPattern = new TwoCitySwapPattern(initialSolution); }
/// <summary> /// Implementation of the actual code to search for the zeroes of /// the <see cref="IObjectiveFunction"/>. /// </summary> /// <remarks> /// It assumes that: /// <list type="bullet"> /// <item> /// <description> /// <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/> form a valid bracket; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.FXMin"/> and <see cref="Solver1D.FXMax"/> contain the values of the /// function in <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/>; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.Root"/> was initialized to a valid initial guess. /// </description> /// </item> /// </list> /// </remarks> /// <param name="objectiveFunction">The <see cref="IObjectiveFunction"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <returns>The zero of the objective function.</returns> /// <exception cref="ApplicationException"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="Solver1D.MaxEvaluations"/>). /// </exception> /// <exception cref="NotImplementedException"> /// Thrown by the <see cref="ObjectiveFunction"/> base class /// when the function's derivative has not been implemented. /// </exception> protected override double SolveImpl(IObjectiveFunction objectiveFunction, double xAccuracy) { while (EvaluationNumber++ < MaxEvaluations) { double froot = objectiveFunction.Value(Root); double dfroot = objectiveFunction.Derivative(Root); double dx = froot / dfroot; Root -= dx; // jumped out of brackets, switch to NewtonSafe if ((XMin - Root) * (Root - XMax) < 0.0) { ISolver1D newtonSafe = new NewtonSafe(); newtonSafe.MaxEvaluations -= EvaluationNumber; return(newtonSafe.Solve(objectiveFunction, xAccuracy, Root + dx, XMin, XMax)); } if (Math.Abs(dx) < xAccuracy) { return(Root); } } throw new ApplicationException("SlvMaxEval"); }
/// <summary> /// Implementation of the actual code to search for the zeroes of /// the <see cref="IObjectiveFunction"/>. /// </summary> /// <remarks> /// It assumes that: /// <list type="bullet"> /// <item> /// <description> /// <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/> form a valid bracket; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.FXMin"/> and <see cref="Solver1D.FXMax"/> contain the values of the /// function in <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/>; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.Root"/> was initialized to a valid initial guess. /// </description> /// </item> /// </list> /// </remarks> /// <param name="objectiveFunction">The <see cref="IObjectiveFunction"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <returns>The zero of the objective function.</returns> /// <exception cref="ApplicationException"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="Solver1D.MaxEvaluations"/>). /// </exception> /// <exception cref="NotImplementedException"> /// Thrown by the <see cref="ObjectiveFunction"/> base class /// when the function's derivative has not been implemented. /// </exception> protected override double SolveImpl(IObjectiveFunction objectiveFunction, double xAccuracy) { // Orient the search so that f(xl) < 0 double xh, xl; if (FXMin < 0.0) { xl = XMin; xh = XMax; } else { xh = XMin; xl = XMax; } // the "stepsize before last" double dxold = XMax - XMin; // it was dxold=QL_FABS(_xMax_-_xMin_); in Numerical Recipes // here (_xMax_-_xMin_ > 0) is verified in the constructor // and the last step double dx = dxold; double froot = objectiveFunction.Value(Root); double dfroot = objectiveFunction.Derivative(Root); // the objectiveFunction throws System.NotImplementedException while (++EvaluationNumber < MaxEvaluations) { // Bisect if (out of range || not decreasing fast enough) if ((((Root - xh) * dfroot - froot) * ((Root - xl) * dfroot - froot) > 0.0) || (Math.Abs(2.0 * froot) > Math.Abs(dxold * dfroot))) { dxold = dx; dx = (xh - xl) / 2.0; Root = xl + dx; } else { dxold = dx; dx = froot / dfroot; Root -= dx; } // Convergence criterion if (Math.Abs(dx) < xAccuracy) { return(Root); } froot = objectiveFunction.Value(Root); dfroot = objectiveFunction.Derivative(Root); if (froot < 0.0) { xl = Root; } else { xh = Root; } } throw new ApplicationException(String.Format( "SlvMaxEval") ); }
/// <summary> /// Solves for unconstrained problems, using a gradient descendent. /// </summary> /// <param name="initialGuess">The vector initial guess.</param> /// <param name="gradientTolerance">The gradient tolerance set per default to 1e-8.</param> /// <param name="maxIteration">The number of iteration used, set per default 1000.</param> /// <returns>The minimization result, <see cref="MinimizationResult"/>.</returns> internal MinimizationResult UnconstrainedMinimizer(Vector initialGuess, double gradientTolerance = 1e-8, int maxIteration = 1000) { Vector x0 = new Vector(initialGuess); int n = x0.Count; double f0 = _objectiveFunction.Value(x0); double f1 = 0.0; Vector x1 = null; Vector s = null; string message = string.Empty; if (double.IsNaN(f0)) { throw new Exception("Unconstrained Minimizer: f(x0) is a NaN!"); } gradientTolerance = Math.Max(gradientTolerance, GSharkMath.Epsilon); Matrix H1 = Matrix.Identity(n); int iteration = 0; Vector g0 = _objectiveFunction.Gradient(x0); while (iteration < maxIteration) { if (g0.Any(val => double.IsNaN(val) || double.IsInfinity(val))) { message = "Gradient has Infinity or NaN."; break; } Vector step = Vector.Reverse(g0 * H1); if (step.Any(val => double.IsNaN(val) || double.IsInfinity(val))) { message = "Search direction has Infinity or NaN"; break; } double lengthStep = step.Length(); if (lengthStep < gradientTolerance) { message = "Newton step smaller than tolerance."; break; } double t = 1.0; double df0 = Vector.Dot(g0, step); // Line search. while (iteration < maxIteration) { if (t * lengthStep < gradientTolerance) { break; } s = step * t; x1 = x0 + s; f1 = _objectiveFunction.Value(x1); if (f1 - f0 >= 0.1 * t * df0 || double.IsNaN(f1)) { t *= 0.5; iteration++; continue; } break; } if (t * lengthStep < gradientTolerance) { message = "Line search step size smaller than gradient tolerance."; break; } if (iteration > maxIteration) { message = "ParameterB iteration reached during line search."; break; } Vector g1 = _objectiveFunction.Gradient(x1); Vector y = g1 - g0; double ys = Vector.Dot(y, s); Vector Hy = y * H1; Matrix T0 = Tensor(s, s); Matrix T1 = Tensor(Hy, s); Matrix T2 = Tensor(s, Hy); H1 = (H1 + (T0 * (ys + Vector.Dot(y, Hy)) / (ys * ys))) - (T1 + T2) / ys; x0 = x1; f0 = f1; g0 = g1; iteration++; } return(new MinimizationResult(x0, f0, g0, H1, iteration, message)); }
/// <summary> /// This method returns the zero of the <see cref="IObjectiveFunction"/> /// <pramref name="objectiveFunction"/>, determined with the given accuracy. /// </summary> /// <remarks> /// <i>x</i> is considered a zero if <i>|f(x)| < accuracy</i>. /// This method contains a bracketing routine to which an initial /// guess must be supplied as well as a step used to scan the range /// of the possible bracketing values. /// </remarks> /// <param name="objectiveFunction">The <see cref="ApplicationException"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <param name="guess">Initial guess used to scan the range /// of the possible bracketing values.</param> /// <param name="step">Initial step used to scan the range /// of the possible bracketing values.</param> /// <returns>The zero of the objective function.</returns> /// <exception cref="MaxEvaluations"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="IObjectiveFunction"/>). /// </exception> public double Solve(IObjectiveFunction objectiveFunction, double xAccuracy, double guess, double step) { const double growthFactor = 1.618;//golden ratio int flipflop = -1; Root = guess; FXMax = objectiveFunction.Value(Root); // monotonically crescent bias, as in optionValue(volatility) if (Math.Abs(FXMax) <= xAccuracy) { return(Root); } if (FXMax > 0.0) { XMin = EnforceBounds(Root - step); FXMin = objectiveFunction.Value(XMin); XMax = Root; } else { XMin = Root; FXMin = FXMax; XMax = EnforceBounds(Root + step); FXMax = objectiveFunction.Value(XMax); } EvaluationNumber = 2; while (EvaluationNumber <= MaxEvaluations) { if (FXMin * FXMax <= 0.0) { if (FXMin == 0.0) { return(XMin); } if (FXMax == 0.0) { return(XMax); } Root = (XMax + XMin) / 2.0; // check whether we really want to pass epsilon return(SolveImpl(objectiveFunction, Math.Max(Math.Abs(xAccuracy), Double.Epsilon))); } if (Math.Abs(FXMin) < Math.Abs(FXMax)) { XMin = EnforceBounds(XMin + growthFactor * (XMin - XMax)); FXMin = objectiveFunction.Value(XMin); } else if (Math.Abs(FXMin) > Math.Abs(FXMax)) { XMax = EnforceBounds(XMax + growthFactor * (XMax - XMin)); FXMax = objectiveFunction.Value(XMax); } else if (flipflop == -1) { XMin = EnforceBounds(XMin + growthFactor * (XMin - XMax)); FXMin = objectiveFunction.Value(XMin); EvaluationNumber++; flipflop = 1; } else if (flipflop == 1) { XMax = EnforceBounds(XMax + growthFactor * (XMax - XMin)); FXMax = objectiveFunction.Value(XMax); flipflop = -1; } EvaluationNumber++; } throw new ApplicationException($"Solver has exceeded its maximum iterations ({MaxEvaluations})."); }
/// <summary> /// Implementation of the actual code to search for the 0.0es of /// the <see cref="IObjectiveFunction"/>. /// </summary> /// <remarks> /// It assumes that: /// <list type="bullet"> /// <item> /// <description> /// <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/> form a valid bracket; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.FXMin"/> and <see cref="Solver1D.FXMax"/> contain the values of the /// function in <see cref="Solver1D.XMin"/> and <see cref="Solver1D.XMax"/>; /// </description> /// </item> /// <item> /// <description> /// <see cref="Solver1D.Root"/> was initialized to a valid initial guess. /// </description> /// </item> /// </list> /// </remarks> /// <param name="objectiveFunction">The <see cref="IObjectiveFunction"/>.</param> /// <param name="xAccuracy">Given accuracy.</param> /// <returns>The 0.0 of the objective function.</returns> /// <exception cref="ApplicationException"> /// Thrown when a bracket is not found after the maximum /// number of evaluations (see <see cref="Solver1D.MaxEvaluations"/>). /// </exception> protected override double SolveImpl(IObjectiveFunction objectiveFunction, double xAccuracy) { // dummy assignements to avoid compiler warning // double d = 0.0; double e = 0.0; Root = XMax; double froot = FXMax; while (EvaluationNumber++ < MaxEvaluations) { if (froot > 0.0 && FXMax > 0.0 || froot < 0.0 && FXMax < 0.0) { // Rename _xMin, root, _xMax and adjust bounding interval d // XMax = XMin; FXMax = FXMin; e = d = Root - XMin; } if (Math.Abs(FXMax) < Math.Abs(froot)) { XMin = Root; Root = XMax; XMax = XMin; FXMin = froot; froot = FXMax; FXMax = FXMin; } // Convergence check // double xAcc1 = 2.0 * Double.Epsilon * Math.Abs(Root) + 0.5 * xAccuracy; double xMid = (XMax - Root) / 2.0; // Yield return value // (exit path) // if (Math.Abs(xMid) <= xAcc1 || froot == 0.0) { return(Root); } if (Math.Abs(e) >= xAcc1 && Math.Abs(FXMin) > Math.Abs(froot)) { double p, q; double s = froot / FXMin; // Attempt inverse quadratic interpolation if (XMin == XMax) { p = 2.0 * xMid * s; q = 1.0 - s; } else { q = FXMin / FXMax; double r = froot / FXMax; p = s * (2.0 * xMid * q * (q - r) - (Root - XMin) * (r - 1.0)); q = (q - 1.0) * (r - 1.0) * (s - 1.0); } if (p > 0.0) { q = -q; // Check whether in bounds } p = Math.Abs(p); double min1 = 3.0 * xMid * q - Math.Abs(xAcc1 * q); double min2 = Math.Abs(e * q); if (2.0 * p < (min1 < min2 ? min1 : min2)) { e = d; // Accept interpolation d = p / q; } else { d = xMid; // Interpolation failed, use bisection e = d; } } else { // Bounds decreasing too slowly, use bisection // d = xMid; e = d; } XMin = Root; FXMin = froot; if (Math.Abs(d) > xAcc1) { Root += d; } else { Root += Math.Sign(xMid) * Math.Abs(xAcc1); } froot = objectiveFunction.Value(Root); } throw new ApplicationException("SlvMaxEval"); }
/// <summary> /// Constructor /// </summary> /// <param name="objective">A tour length objectiveulator object</param> /// <param name="initialSolution">An initial solution</param> public BruteForceSearch(IObjectiveFunction objective, List<int> initialSolution) { this.objective = objective; this.solution = initialSolution; this.currentTourLength = objective.Value(initialSolution); }