public override void OnLoad(ConfigNode node) { Instance = this; GeneratePresets(); int index = 4; if (node.HasValue("newGame")) { newGame = bool.Parse(node.GetValue("newGame")); } if (node.HasValue("index")) { index = int.Parse(node.GetValue("index")); } dropdown = new GUIDropDown <FARDifficultyAndExactnessSettings>(presetNames.ToArray(), presets.ToArray(), index < 0 ? 2 : index); voxelSettings = new FARVoxelSettings(); if (node.HasValue("numVoxelsControllableVessel")) { voxelSettings.numVoxelsControllableVessel = int.Parse(node.GetValue("numVoxelsControllableVessel")); } if (node.HasValue("numVoxelsDebrisVessel")) { voxelSettings.numVoxelsDebrisVessel = int.Parse(node.GetValue("numVoxelsDebrisVessel")); } if (node.HasValue("minPhysTicksPerUpdate")) { voxelSettings.minPhysTicksPerUpdate = int.Parse(node.GetValue("minPhysTicksPerUpdate")); } if (node.HasValue("useHigherResVoxelPoints")) { voxelSettings.useHigherResVoxelPoints = bool.Parse(node.GetValue("useHigherResVoxelPoints")); } if (index == -1) { settings = new FARDifficultyAndExactnessSettings(index); if (node.HasValue("fractionTransonicDrag")) { settings.fractionTransonicDrag = double.Parse(node.GetValue("fractionTransonicDrag")); } if (node.HasValue("gaussianVehicleLengthFractionForSmoothing")) { settings.gaussianVehicleLengthFractionForSmoothing = double.Parse(node.GetValue("gaussianVehicleLengthFractionForSmoothing")); } if (node.HasValue("numAreaSmoothingPasses")) { settings.numAreaSmoothingPasses = int.Parse(node.GetValue("numAreaSmoothingPasses")); } if (node.HasValue("numDerivSmoothingPasses")) { settings.numDerivSmoothingPasses = int.Parse(node.GetValue("numDerivSmoothingPasses")); } customSettings = settings; } else { settings = presets[index]; customSettings = new FARDifficultyAndExactnessSettings(-1); } currentIndex = index; FARLogger.Info("Loading FAR Data"); flightGUISettings = new List <ConfigNode>(); if (node.HasNode("FlightGUISettings")) { foreach (ConfigNode flightGUINode in node.GetNode("FlightGUISettings").nodes) { flightGUISettings.Add(flightGUINode); } } FARDebugAndSettings.LoadConfigs(node); }
// ReSharper disable once UnusedMember.Global public static OptimizationResult BrentsMethod( Func <double, double> function, double a, double b, double epsilon = 0.001, int maxIter = int.MaxValue ) { double delta = epsilon * 100; double fa = function(a); double fb = function(b); if (fa * fb >= 0) { FARLogger.Debug("Brent's method failed to converge in 2 calls due to invalid brackets"); return(new OptimizationResult(0, 2)); } if (Math.Abs(fa) < Math.Abs(fb)) { double tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } double c = a, d = a, fc = function(c); int funcCalls = 3; double s = b, fs = fb; bool flag = true; for (int iter = 0; iter < maxIter; iter++) { if (fa - fc > double.Epsilon && fb - fc > double.Epsilon) //inverse quadratic interpolation { s = a * fc * fb / ((fa - fb) * (fa - fc)); s += b * fc * fa / ((fb - fa) * (fb - fc)); s += c * fc * fb / ((fc - fa) * (fc - fb)); } else { s = (b - a) / (fb - fa); //secant method s *= fb; s = b - s; } double b_s = Math.Abs(b - s), b_c = Math.Abs(b - c), c_d = Math.Abs(c - d); //Conditions for bisection method bool condition1; double a3pb_over4 = (3 * a + b) * 0.25; if (a3pb_over4 > b) { if (s < a3pb_over4 && s > b) { condition1 = false; } else { condition1 = true; } } else if (s > a3pb_over4 && s < b) { condition1 = false; } else { condition1 = true; } bool condition2; if (flag && b_s >= b_c * 0.5) { condition2 = true; } else { condition2 = false; } bool condition3; if (!flag && b_s >= c_d * 0.5) { condition3 = true; } else { condition3 = false; } bool condition4; if (flag && b_c <= delta) { condition4 = true; } else { condition4 = false; } bool condition5; if (!flag && c_d <= delta) { condition5 = true; } else { condition5 = false; } if (condition1 || condition2 || condition3 || condition4 || condition5) { s = a + b; s *= 0.5; flag = true; } else { flag = false; } fs = function(s); funcCalls++; d = c; c = b; if (fa * fs < 0) { b = s; fb = fs; } else { a = s; fa = fs; } if (Math.Abs(fa) < Math.Abs(fb)) { double tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } if (fs.NearlyEqual(0) || Math.Abs(a - b) <= epsilon) { return(new OptimizationResult(s, funcCalls, true)); } } FARLogger.Debug($"Brent's method failed to converged in {funcCalls.ToString()} function calls"); return(new OptimizationResult(s, funcCalls)); }
/// <summary> /// C# implementation of /// https://github.com/scipy/scipy/blob/d5617d81064885ef2ec961492bc703f36bb36ee9/scipy/optimize/zeros.py#L95-L363 /// with optional <see cref="minLimit" /> and <see cref="maxLimit" /> constraints for physical problems. The solver /// terminates when it either reaches the maximum number of iterations <see cref="maxIter" />, current and previous /// <see cref="function" /> values are equal, current and previous solutions are close enough, are both NaN or both /// fall outside limits. /// </summary> /// <param name="function">Function to find root of</param> /// <param name="x0">Initial guess</param> /// <param name="x1">Optional second guess</param> /// <param name="tol">Absolute convergence tolerance</param> /// <param name="rTol">Relative convergence tolerance</param> /// <param name="maxIter">Maximum number of iterations</param> /// <param name="maxLimit">Maximum value of the solution</param> /// <param name="minLimit">Minimum value of the solution</param> /// <returns><see cref="OptimizationResult" /> solution</returns> /// <exception cref="ArgumentException">When initial and second guesses are equal</exception> public static OptimizationResult Secant( Func <double, double> function, double x0, double?x1 = null, double tol = 0.001, double rTol = 0.001, int maxIter = 50, double maxLimit = double.PositiveInfinity, double minLimit = double.NegativeInfinity ) { // ReSharper disable CompareOfFloatsByEqualityOperator int funcCalls = 0; double p0 = x0; double p1; if (x1 is null) { const double eps = 1e-4; p1 = x0 * (1 + eps); p1 += p1 >= 0 ? eps : -eps; } else { if (x1 == x0) { throw new ArgumentException($"{nameof(x1)} and {nameof(x0)} must be different"); } p1 = (double)x1; } double q0 = function(p0); double q1 = function(p1); funcCalls += 2; double p = 0; if (Math.Abs(q1) < Math.Abs(q0)) { Swap(ref p0, ref p1); Swap(ref q0, ref q1); } for (int itr = 0; itr < maxIter; itr++) { if (q1 == q0) { if (p1 != p0) { FARLogger.Warning($"Tolerance of {(p1 - p0).ToString(CultureInfo.InvariantCulture)} reached"); } FARLogger.Debug($"Secant method converged in {funcCalls.ToString()} function calls"); return(new OptimizationResult((p1 + p0) / 2, funcCalls, true)); } if (Math.Abs(q1) > Math.Abs(q0)) { p = (-q0 / q1 * p1 + p0) / (1 - q0 / q1); } else { p = (-q1 / q0 * p0 + p1) / (1 - q1 / q0); } if (IsClose(p, p1, tol, rTol)) { FARLogger.Debug($"Secant method converged in {funcCalls.ToString()} function calls with tolerance of {(p1 - p).ToString(CultureInfo.InvariantCulture)}"); return(new OptimizationResult(p, funcCalls, true)); } p0 = p1; q0 = q1; p1 = p; if (double.IsNaN(p0) && double.IsNaN(p1)) { FARLogger.Warning($"Both {nameof(p0)} and {nameof(p1)} are NaN, used {funcCalls.ToString()} function calls"); return(new OptimizationResult(p, funcCalls)); } if (p1 < minLimit && p0 < minLimit || p1 > maxLimit && p0 > maxLimit) { FARLogger.Warning($"{nameof(p1)} and {nameof(p0)} are outside the limits, used {funcCalls.ToString()} function calls"); return(new OptimizationResult(p, funcCalls)); } q1 = function(p1); funcCalls++; } FARLogger.Warning($"Secant method failed to converge in {funcCalls.ToString()} function calls"); return(new OptimizationResult(p, funcCalls)); // ReSharper restore CompareOfFloatsByEqualityOperator }
public double BrentSolve(string dbgmsg) { FARLogger.Info("MirroredFunction (mirrored= " + mirror + ") reverting to BrentsMethod: " + dbgmsg); return(FARMathUtil.BrentsMethod(this.F, leftedge, rightedge, tol_brent, iterlim)); }