public void GoldsteinPrice() { // Goldstein-Price has a valley with a complicated shape and a global minimum value of 3 at (0,-1). // It also has local minima, so we have to start close to this minimum if we expect to end at it. Func <IList <double>, double> fGoldsteinPrice = (IList <double> v) => { double x = v[0]; double y = v[1]; return( (1 + MoreMath.Pow(x + y + 1, 2) * (19 - 14 * x + 3 * x * x - 14 * y + 6 * x * y + 6 * y * y)) * (30 + MoreMath.Pow(2 * x - 3 * y, 2) * (18 - 32 * x + 12 * x * x + 48 * y - 36 * x * y + 27 * y * y)) ); }; ColumnVector start = new ColumnVector(0.5, -0.5); MultiExtremum min = MultiFunctionMath.FindLocalMinimum(fGoldsteinPrice, start); Console.WriteLine(min.EvaluationCount); Console.WriteLine(min.Value); Assert.IsTrue(min.Dimension == 2); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Value, 3.0)); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Location, new ColumnVector(0.0, -1.0), Math.Sqrt(TestUtilities.TargetPrecision))); MultiExtremum min2 = MultiFunctionMath.FindGlobalMinimum(fGoldsteinPrice, new Interval[] { Interval.FromEndpoints(-2.0, 2.0), Interval.FromEndpoints(-2.0, 2.0) }); Assert.IsTrue(min2.Dimension == 2); Assert.IsTrue(TestUtilities.IsNearlyEqual(min2.Value, 3.0, new EvaluationSettings() { AbsolutePrecision = min2.Precision })); //Assert.IsTrue(TestUtilities.IsNearlyEqual(min2.Location, new ColumnVector(0.0, -1.0), Math.Sqrt(TestUtilities.TargetPrecision))); }
public void Perm() { Func <IList <double>, double> fPerm = (IList <double> x) => { double s = 0.0; for (int i = 1; i <= x.Count; i++) { double t = 0.0; for (int j = 0; j < x.Count; j++) { t += (j + 1) * (MoreMath.Pow(x[j], i) - 1.0 / MoreMath.Pow(j + 1, i)); } s += MoreMath.Sqr(t); } return(s); }; int n = 4; ColumnVector start = new ColumnVector(n); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(fPerm, start); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine(minimum.Value); for (int i = 0; i < minimum.Dimension; i++) { Console.WriteLine(minimum.Location[i]); } }
public void Beale() { // Beale is a very interesting function. // The only local minimum is at (3,1/2) where the function value is 0. // But along the lines (0,+\infty) and (-\infty,1) the function value decreases toward 0 at infinity. // From the point of view of a local minimizer those are perfectly valid downhill directions and // if the minimzer gets caught in them it will move toward infinity until its evaluation budget is // exhausted. Starting from y > 0 will probably keep us safe, or we can do bounded optimization. Func <IList <double>, double> fBeale = (IList <double> x) => MoreMath.Sqr(1.5 - x[0] + x[0] * x[1]) + MoreMath.Sqr(2.25 - x[0] + x[0] * x[1] * x[1]) + MoreMath.Sqr(2.625 - x[0] + x[0] * x[1] * x[1] * x[1]); ColumnVector start = new ColumnVector(2.0, 1.0); MultiExtremum min = MultiFunctionMath.FindLocalMinimum(fBeale, start); Console.WriteLine(min.EvaluationCount); Console.WriteLine(min.Value); ColumnVector solution = new ColumnVector(3.0, 0.5); Assert.IsTrue(min.Dimension == 2); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = min.Precision })); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Location, solution, Math.Sqrt(TestUtilities.TargetPrecision))); }
public void MinimizePerturbedQuadratic2D() { int count = 0; MultiExtremumSettings s = new MultiExtremumSettings() { EvaluationBudget = 100, RelativePrecision = 1.0E-10, Listener = r => { count++; } }; Func <IReadOnlyList <double>, double> f = (IReadOnlyList <double> x) => 1.0 + 2.0 * MoreMath.Sqr(x[0] - 3.0) + 4.0 * (x[0] - 3.0) * (x[1] - 5.0) + 6.0 * MoreMath.Sqr(x[1] - 5.0) + 7.0 * MoreMath.Pow(x[0] - 3.0, 4) + 8.0 * MoreMath.Pow(x[1] - 5.0, 4); MultiExtremum m = MultiFunctionMath.FindLocalMinimum(f, new double[] { 1.0, 1.0 }, s); Assert.IsTrue(m.EvaluationCount <= s.EvaluationBudget); Assert.IsTrue(m.Dimension == 2); Assert.IsTrue(TestUtilities.IsNearlyEqual(m.Value, 1.0, s)); Assert.IsTrue(TestUtilities.IsNearlyEqual(m.Location, new ColumnVector(3.0, 5.0), new EvaluationSettings() { RelativePrecision = Math.Sqrt(s.RelativePrecision) })); Assert.IsTrue(count > 0); }
public void MinimizeQuadratic1D() { Func <IList <double>, double> f = (IList <double> x) => 1.0 + MoreMath.Sqr(x[0] - 3.0); MultiExtremum m = MultiFunctionMath.FindLocalMinimum(f, new double[] { 1.0 }); Assert.IsTrue(TestUtilities.IsNearlyEqual(1.0, m.Value)); }
internal NonlinearRegressionResult( IReadOnlyList <double> x, IReadOnlyList <double> y, Func <IReadOnlyList <double>, double, double> function, IReadOnlyList <double> start, IReadOnlyList <string> names) { Debug.Assert(x != null); Debug.Assert(y != null); Debug.Assert(function != null); Debug.Assert(start != null); Debug.Assert(names != null); Debug.Assert(x.Count == y.Count); Debug.Assert(start.Count > 0); Debug.Assert(names.Count == start.Count); int n = x.Count; int d = start.Count; if (n <= d) { throw new InsufficientDataException(); } MultiExtremum min = MultiFunctionMath.FindLocalMinimum((IReadOnlyList <double> a) => { double ss = 0.0; for (int i = 0; i < n; i++) { double r = y[i] - function(a, x[i]); ss += r * r; } return(ss); }, start); CholeskyDecomposition cholesky = min.HessianMatrix.CholeskyDecomposition(); if (cholesky == null) { throw new DivideByZeroException(); } b = min.Location; C = cholesky.Inverse(); C = (2.0 * min.Value / (n - d)) * C; sumOfSquaredResiduals = 0.0; residuals = new List <double>(n); for (int i = 0; i < n; i++) { double z = y[i] - function(b, x[i]); sumOfSquaredResiduals += z * z; residuals.Add(z); } this.names = names; this.function = function; }
public void SmoothedEasom() { // This function is mostly flat except very near (\pi, \pi). // For (1,1) or (0,0) "converges" to minimum of 0 at (1.30, 1.30). This is probably a local minimum of the cosine product. //Func<IList<double>, double> function = (IList<double> x) => -Math.Exp(-(MoreMath.Sqr(x[0] - Math.PI) + MoreMath.Sqr(x[1] - Math.PI))); Func <IList <double>, double> function = (IList <double> x) => - Math.Cos(x[0]) * Math.Cos(x[1]) * Math.Exp(-(MoreMath.Sqr(x[0] - Math.PI) + MoreMath.Sqr(x[1] - Math.PI))); ColumnVector start = new ColumnVector(2.0, 2.0); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(function, start); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine(minimum.Value); Console.WriteLine("{0} {1}", minimum.Location[0], minimum.Location[1]); }
public void ThomsonLocal() { for (int n = 2; n < 8; n++) { Console.WriteLine(n); // define the thompson metric Func <IList <double>, double> f = GetThompsonFunction(n); // random distribution to start // using antipodal pairs gives us a better starting configuration Random r = new Random(1001110000); double[] start = new double[2 * (n - 1)]; for (int i = 0; i < (n - 1) / 2; i++) { int j = 4 * i; start[j] = -Math.PI + 2.0 * r.NextDouble() * Math.PI; start[j + 1] = Math.Asin(2.0 * r.NextDouble() - 1.0); start[j + 2] = -(Math.PI - start[j]); start[j + 3] = -start[j + 1]; } // add one more point if necessary if (n % 2 == 0) { start[2 * n - 4] = -Math.PI + 2.0 * r.NextDouble() * Math.PI; start[2 * n - 3] = Math.Asin(2.0 * r.NextDouble() - 1.0); } EvaluationSettings set = new EvaluationSettings() { RelativePrecision = 1.0E-9 }; MultiExtremum min = MultiFunctionMath.FindLocalMinimum(f, start, set); Console.WriteLine(min.Dimension); Console.WriteLine(min.EvaluationCount); Console.WriteLine("{0} ({1}) ?= {2}", min.Value, min.Precision, thompsonSolutions[n]); Assert.IsTrue(min.Dimension == 2 * (n - 1)); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Value, thompsonSolutions[n], new EvaluationSettings() { AbsolutePrecision = 4.0 * min.Precision })); } }
/// <summary> /// Finds the parameterized function that best fits the data. /// </summary> /// <param name="f">The parameterized function.</param> /// <param name="start">An initial guess for the parameters.</param> /// <returns>The fit result.</returns> /// <remarks> /// <para> /// In the returned <see cref="FitResult"/>, the parameters appear in the same order as in /// the supplied fit function and initial guess vector. No goodness-of-fit test is returned. /// </para> /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="f"/> or <paramref name="start"/> is null.</exception> /// <exception cref="InsufficientDataException">There are not more data points than fit parameters.</exception> /// <exception cref="DivideByZeroException">The curvature matrix is singular, indicating that the data is independent of /// one or more parameters, or that two or more parameters are linearly dependent.</exception> public FitResult NonlinearRegression(Func <IList <double>, double, double> f, IList <double> start) { if (f == null) { throw new ArgumentNullException(nameof(f)); } if (start == null) { throw new ArgumentNullException(nameof(start)); } int n = this.Count; int d = start.Count; if (n <= d) { throw new InsufficientDataException(); } MultiExtremum min = MultiFunctionMath.FindLocalMinimum((IList <double> a) => { double ss = 0.0; for (int i = 0; i < n; i++) { double r = yData[i] - f(a, xData[i]); ss += r * r; } return(ss); }, start); CholeskyDecomposition cholesky = min.HessianMatrix.CholeskyDecomposition(); if (cholesky == null) { throw new DivideByZeroException(); } SymmetricMatrix curvature = cholesky.Inverse(); curvature = (2.0 * min.Value / (n - d)) * curvature; FitResult result = new FitResult(min.Location, curvature, null); return(result); }
public void Rosenbrock() { // This is a multi-dimensional generalization of the famous Rosenbrock, aka banana function, // which has a narrow parabolic valley whose floor slopes only gently to the minimum. Func <IList <double>, double> fRosenbrock = delegate(IList <double> x) { double s = 0.0; for (int i = 0; i < (x.Count - 1); i++) { s += 100.0 * MoreMath.Pow(x[i + 1] - x[i] * x[i], 2) + MoreMath.Pow(1.0 - x[i], 2); } return(s); }; for (int n = 2; n < 8; n++) { Console.WriteLine("n={0}", n); double[] start = new double[n]; MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(fRosenbrock, start); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine("{0} {1} ?= 0.0", minimum.Value, minimum.Precision); ColumnVector solution = new ColumnVector(n); for (int i = 0; i < solution.Dimension; i++) { solution[i] = 1.0; } Assert.IsTrue(minimum.Dimension == n); Assert.IsTrue(minimum.Precision > 0.0); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 2.0 * minimum.Precision })); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, solution, new EvaluationSettings() { RelativePrecision = 2.0 * Math.Sqrt(minimum.Precision) })); } }
public void SumOfPowers() { // This test is difficult because the minimum is emphatically not quadratic. // We do get close to the minimum but we massivly underestimate our error. Func <IList <double>, double> function = (IList <double> x) => { double s = 0.0; for (int i = 0; i < x.Count; i++) { s += MoreMath.Pow(Math.Abs(x[i]), i + 2); } return(s); }; for (int n = 2; n < 8; n++) { Console.WriteLine(n); ColumnVector start = new ColumnVector(n); for (int i = 0; i < n; i++) { start[i] = 1.0; } EvaluationSettings settings = new EvaluationSettings() { AbsolutePrecision = 1.0E-8, EvaluationBudget = 32 * n * n * n }; MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(function, start, settings); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine("{0} {1}", minimum.Value, minimum.Precision); Console.WriteLine("|| {0} {1} ... || = {2}", minimum.Location[0], minimum.Location[1], minimum.Location.FrobeniusNorm()); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 1.0E-4 })); //Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, new ColumnVector(n), new EvaluationSettings() { AbsolutePrecision = 1.0E-2 })); } }
public void ThreeHumpCamel() { // This function has three local minima, so not at all starting points should be expected to bring us to the global minimum at the origin. Func <IList <double>, double> function = (IList <double> x) => 2.0 * MoreMath.Pow(x[0], 2) - 1.05 * MoreMath.Pow(x[0], 4) + MoreMath.Pow(x[0], 6) / 6.0 + x[0] * x[1] + MoreMath.Pow(x[1], 2); ColumnVector start = new ColumnVector(1.0, 1.0); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(function, start); Console.WriteLine("{0} ({1}) ?= 0.0", minimum.Value, minimum.Precision); Console.WriteLine("{0} {1}", minimum.Location[0], minimum.Location[1]); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 2.0 * minimum.Precision })); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, new ColumnVector(2), new EvaluationSettings { AbsolutePrecision = 2.0 * Math.Sqrt(minimum.Precision) })); }
public void StylblinskiTang() { Func <IList <double>, double> fStyblinskiTang = (IList <double> x) => { double fst = 0.0; for (int i = 0; i < x.Count; i++) { double x1 = x[i]; double x2 = MoreMath.Sqr(x1); fst += x2 * (x2 - 16.0) + 5.0 * x1; } return(fst / 2.0); }; // solution coordinate is root of 5 - 32 x + 4 x^3 = 0 with negative second derivative. // There are two such roots. double root1 = -2.9035340277711770951; double root2 = 2.7468027709908369925; // tested up to n=16, works with slightly decreasing accuracy of Location for (int n = 2; n < 8; n++) { Console.WriteLine(n); ColumnVector start = new ColumnVector(n); //ColumnVector start = new ColumnVector(-1.0, -2.0, -3.0, -4.0, -5.0, -6.0); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(fStyblinskiTang, start); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine(minimum.Value); for (int i = 0; i < minimum.Dimension; i++) { Console.WriteLine(minimum.Location[i]); Assert.IsTrue( TestUtilities.IsNearlyEqual(minimum.Location[i], root1, Math.Sqrt(Math.Sqrt(TestUtilities.TargetPrecision))) || TestUtilities.IsNearlyEqual(minimum.Location[i], root2, Math.Sqrt(Math.Sqrt(TestUtilities.TargetPrecision))) ); } Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, fStyblinskiTang(minimum.Location))); } }
public void Vardim() { // This function is described by Powell in his NEWOUA paper as one that caused problems for the simplest formulation of that minimizer. Func <IList <double>, double> f = (IList <double> x) => { double s1 = 0.0; double s2 = 0.0; for (int i = 0; i < x.Count; i++) { s1 += i * (x[i] - 1.0); s2 += MoreMath.Sqr(x[i] - 1.0); } return(s2 + s1 * s1 + s1 * s1 * s1 * s1); }; for (int n = 2; n < 8; n++) { Console.WriteLine("n = {0}", n); ColumnVector start = new ColumnVector(n); ColumnVector solution = new ColumnVector(n); solution.Fill((i, j) => 1.0); MultiExtremum min = MultiFunctionMath.FindLocalMinimum(f, start); Console.WriteLine(min.EvaluationCount); Console.WriteLine("{0} ({1}) ?= 0.0", min.Value, min.Precision); Assert.IsTrue(min.Dimension == n); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 4.0 * min.Precision })); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Location, solution, new EvaluationSettings() { RelativePrecision = Math.Sqrt(4.0 * min.Precision) })); } }
public void MinimizeQuadratic2D() { Func <IList <double>, double> f = (IList <double> x) => 1.0 + 2.0 * MoreMath.Sqr(x[0] - 3.0) + 4.0 * (x[0] - 3.0) * (x[1] - 5.0) + 6.0 * MoreMath.Sqr(x[1] - 5.0); MultiExtremum m = MultiFunctionMath.FindLocalMinimum(f, new double[] { 1.0, 1.0 }); Console.WriteLine(m.Value); SymmetricMatrix H = new SymmetricMatrix(2); H[0, 0] = 4.0; H[0, 1] = 4.0; H[1, 1] = 12.0; Assert.IsTrue(m.Dimension == 2); Assert.IsTrue(TestUtilities.IsNearlyEqual(m.Value, 1.0)); Assert.IsTrue(TestUtilities.IsNearlyEqual(m.Location, new ColumnVector(3.0, 5.0), new EvaluationSettings() { RelativePrecision = Math.Sqrt(TestUtilities.TargetPrecision) })); Assert.IsTrue(TestUtilities.IsNearlyEqual(m.HessianMatrix, H, new EvaluationSettings() { RelativePrecision = 8.0 * Math.Sqrt(Math.Sqrt(TestUtilities.TargetPrecision)) })); }
/// <summary> /// Computes the best-fit linear logistic regression from the data. /// </summary> /// <returns>The fit result.</returns> /// <remarks> /// <para>Linear logistic regression is a way to fit binary outcome data to a linear model.</para> /// <para>The method assumes that binary outcomes are encoded as 0 and 1. If any y-values other than /// 0 and 1 are encountered, it throws an <see cref="InvalidOperationException"/>.</para> /// <para>The fit result is two-dimensional. The first parameter is a, the second b.</para> /// </remarks> /// <exception cref="InsufficientDataException">There are fewer than three data points.</exception> /// <exception cref="InvalidOperationException">There is a y-value other than 0 or 1.</exception> public FitResult LinearLogisticRegression() { // check size of data set if (Count < 3) { throw new InsufficientDataException(); } // check limits on Y double p = Y.Mean; double q = 1.0 - p; if ((p <= 0.0) || (q <= 0.0)) { throw new InvalidOperationException(); } // Define the log-likelyhood as a function of the parameters Func <IList <double>, double> f = delegate(IList <double> a) { double L = 0.0; for (int i = 0; i < Count; i++) { double x = xData[i]; double z = a[0] + a[1] * x; double ez = Math.Exp(z); double y = yData[i]; if (y == 0.0) { L += Math.Log(1.0 + ez); } else if (y == 1.0) { L += Math.Log(1.0 + 1.0 / ez); } else { throw new InvalidOperationException(); } } return(L); }; // We need an initial guess at the parameters. // This particular initial guess is driven by the fact that, in a logistic model // \frac{\partial p}{\partial x} = \beta p ( 1 - p) // Evaluating at means, and noting that p (1 - p) = var(y) and that, in a development around the means, // cov(p, x) = \frac{\partial p}{\partial x} var(x) // we get // \beta = \frac{cov(y, x)}{var(x) var(y)} // This approximation gets the sign right, but it looks like it usually gets the magnitude quite wrong. double b0 = Covariance / X.Variance / Y.Variance; double a0 = Math.Log(p / q) - b0 * X.Mean; MultiExtremum m = MultiFunctionMath.FindLocalMinimum(f, new double[2] { a0, b0 }); return(new FitResult(m.Location, m.HessianMatrix.Inverse(), null)); //SpaceExtremum m = FunctionMath.FindMinimum(f, new double[2] { a0, b0 }); //return (new FitResult(m.Location(), m.Curvature().Inverse(), null)); }
public static void Optimization() { Interval range = Interval.FromEndpoints(0.0, 6.28); Extremum min = FunctionMath.FindMinimum(x => Math.Sin(x), range); Console.WriteLine($"Found minimum of {min.Value} at {min.Location}."); Console.WriteLine($"Required {min.EvaluationCount} evaluations."); MultiExtremum rosenbrock = MultiFunctionMath.FindLocalMinimum( x => MoreMath.Sqr(2.0 - x[0]) + 100.0 * MoreMath.Sqr(x[1] - x[0] * x[0]), new ColumnVector(0.0, 0.0) ); ColumnVector xm = rosenbrock.Location; Console.WriteLine($"Found minimum of {rosenbrock.Value} at ({xm[0]},{xm[1]})."); Console.WriteLine($"Required {rosenbrock.EvaluationCount} evaluations."); Func <IReadOnlyList <double>, double> leviFunction = z => { double x = z[0]; double y = z[1]; return( MoreMath.Sqr(MoreMath.Sin(3.0 * Math.PI * x)) + MoreMath.Sqr(x - 1.0) * (1.0 + MoreMath.Sqr(MoreMath.Sin(3.0 * Math.PI * y))) + MoreMath.Sqr(y - 1.0) * (1.0 + MoreMath.Sqr(MoreMath.Sin(2.0 * Math.PI * y))) ); }; Interval[] leviRegion = new Interval[] { Interval.FromEndpoints(-10.0, +10.0), Interval.FromEndpoints(-10.0, +10.0) }; MultiExtremum levi = MultiFunctionMath.FindGlobalMinimum(leviFunction, leviRegion); ColumnVector zm = levi.Location; Console.WriteLine($"Found minimum of {levi.Value} at ({zm[0]},{zm[1]})."); Console.WriteLine($"Required {levi.EvaluationCount} evaluations."); // Select a dimension int n = 6; // Define a function that takes 2n polar coordinates in the form // phi_1, theta_1, phi_2, theta_2, ..., phi_n, theta_n, computes // the sum of the potential energy 1/d for all pairs. Func <IReadOnlyList <double>, double> thompson = (IReadOnlyList <double> v) => { double e = 0.0; // iterate over all distinct pairs of points for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { // compute the chord length between points i and j double dx = Math.Cos(v[2 * j]) * Math.Cos(v[2 * j + 1]) - Math.Cos(v[2 * i]) * Math.Cos(v[2 * i + 1]); double dy = Math.Cos(v[2 * j]) * Math.Sin(v[2 * j + 1]) - Math.Cos(v[2 * i]) * Math.Sin(v[2 * i + 1]); double dz = Math.Sin(v[2 * j]) - Math.Sin(v[2 * i]); double d = Math.Sqrt(dx * dx + dy * dy + dz * dz); e += 1.0 / d; } } return(e); }; // Limit all polar coordinates to their standard ranges. Interval[] box = new Interval[2 * n]; for (int i = 0; i < n; i++) { box[2 * i] = Interval.FromEndpoints(-Math.PI, Math.PI); box[2 * i + 1] = Interval.FromEndpoints(-Math.PI / 2.0, Math.PI / 2.0); } // Use settings to monitor proress toward a rough solution. MultiExtremumSettings roughSettings = new MultiExtremumSettings() { RelativePrecision = 0.05, AbsolutePrecision = 0.0, Listener = r => { Console.WriteLine($"Minimum {r.Value} after {r.EvaluationCount} evaluations."); } }; MultiExtremum roughThompson = MultiFunctionMath.FindGlobalMinimum(thompson, box, roughSettings); // Use settings to monitor proress toward a refined solution. MultiExtremumSettings refinedSettings = new MultiExtremumSettings() { RelativePrecision = 1.0E-5, AbsolutePrecision = 0.0, Listener = r => { Console.WriteLine($"Minimum {r.Value} after {r.EvaluationCount} evaluations."); } }; MultiExtremum refinedThompson = MultiFunctionMath.FindLocalMinimum(thompson, roughThompson.Location, refinedSettings); Console.WriteLine($"Minimum potential energy {refinedThompson.Value}."); Console.WriteLine($"Required {roughThompson.EvaluationCount} + {refinedThompson.EvaluationCount} evaluations."); /* * // Define a function that takes 2n coordinates x1, y1, x2, y2, ... xn, yn * // and finds the smallest distance between two coordinate pairs. * Func<IReadOnlyList<double>, double> function = (IReadOnlyList<double> x) => { * double sMin = Double.MaxValue; * for (int i = 0; i < n; i++) { * for (int j = 0; j < i; j++) { * double s = MoreMath.Hypot(x[2 * i] - x[2 * j], x[2 * i + 1] - x[2 * j + 1]); * if (s < sMin) sMin = s; * } * } * return (sMin); * }; * * // Limit all coordinates to the unit box. * Interval[] box = new Interval[2 * n]; * for (int i = 0; i < box.Length; i++) box[i] = Interval.FromEndpoints(0.0, 1.0); * * // Use settings to monitor proress toward a rough solution. * MultiExtremumSettings roughSettings = new MultiExtremumSettings() { * RelativePrecision = 1.0E-2, AbsolutePrecision = 0.0, * Listener = r => { * Console.WriteLine($"Minimum {r.Value} after {r.EvaluationCount} evaluations."); * } * }; * MultiExtremum roughMaximum = MultiFunctionMath.FindGlobalMaximum(function, box, roughSettings); * * // Use settings to monitor proress toward a rough solution. * MultiExtremumSettings refinedSettings = new MultiExtremumSettings() { * RelativePrecision = 1.0E-8, AbsolutePrecision = 0.0, * Listener = r => { * Console.WriteLine($"Minimum {r.Value} after {r.EvaluationCount} evaluations."); * } * }; * MultiExtremum refinedMaximum = MultiFunctionMath.FindLocalMaximum(function, roughMaximum.Location, refinedSettings); */ }