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 Bukin() { // Burkin has a narrow valley, not aligned with any axis, punctuated with many tiny "wells" along its bottom. // The deepest well is at (-10,1)-> 0. Func <IReadOnlyList <double>, double> function = (IReadOnlyList <double> x) => 100.0 * Math.Sqrt(Math.Abs(x[1] - 0.01 * x[0] * x[0])) + 0.01 * Math.Abs(x[0] + 10.0); IReadOnlyList <Interval> box = new Interval[] { Interval.FromEndpoints(-15.0, 0.0), Interval.FromEndpoints(-3.0, 3.0) }; int count = 0; MultiExtremumSettings settings = new MultiExtremumSettings() { RelativePrecision = 0.0, AbsolutePrecision = 1.0E-4, EvaluationBudget = 1000000, Listener = r => { count++; } }; /* * settings.Update += (object result) => { * MultiExtremum e = (MultiExtremum) result; * Console.WriteLine("After {0} evaluations, best value {1}", e.EvaluationCount, e.Value); * }; */ MultiExtremum minimum = MultiFunctionMath.FindGlobalMinimum(function, box, settings); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine("{0} ({1})", minimum.Value, minimum.Precision); Console.WriteLine("{0} {1}", minimum.Location[0], minimum.Location[1]); // We do not end up finding the global minimum. Assert.IsTrue(count > 0); }
public void Ackley() { // Ackley's function has many local minima, and a global minimum at (0, 0) -> 0. Func <IReadOnlyList <double>, double> function = (IReadOnlyList <double> x) => { double s = 0.0; double c = 0.0; for (int i = 0; i < x.Count; i++) { s += x[i] * x[i]; c += Math.Cos(2.0 * Math.PI * x[i]); } return(-20.0 * Math.Exp(-0.2 * Math.Sqrt(s / x.Count)) - Math.Exp(c / x.Count) + 20.0 + Math.E); }; MultiExtremumSettings settings = new MultiExtremumSettings() { AbsolutePrecision = 1.0E-8, EvaluationBudget = 10000000 }; for (int n = 2; n < 16; n = (int)Math.Round(AdvancedMath.GoldenRatio * n)) { Console.WriteLine("n={0}", n); Interval[] box = new Interval[n]; for (int i = 0; i < box.Length; i++) { box[i] = Interval.FromEndpoints(-32.0, 32.0); } MultiExtremum minimum = MultiFunctionMath.FindGlobalMinimum(function, box, settings); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine(minimum.Value); foreach (double coordinate in minimum.Location) { Console.WriteLine(coordinate); } Assert.IsTrue(minimum.Dimension == n); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 2.0 * minimum.Precision })); ColumnVector solution = new ColumnVector(n); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, solution, new EvaluationSettings() { AbsolutePrecision = 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 <IReadOnlyList <double>, double> function = (IReadOnlyList <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; } MultiExtremumSettings settings = new MultiExtremumSettings() { 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 Griewank() { // See http://mathworld.wolfram.com/GriewankFunction.html for (int n = 2; n < 8; n++) { Console.WriteLine(n); Func <IReadOnlyList <double>, double> function = (IReadOnlyList <double> x) => { double s = 0.0; double p = 1.0; for (int i = 0; i < x.Count; i++) { s += MoreMath.Sqr(x[i]); p *= Math.Cos(x[i] / Math.Sqrt(i + 1.0)); } return(1.0 + s / 4000.0 - p); }; Interval[] box = new Interval[n]; for (int i = 0; i < n; i++) { box[i] = Interval.FromEndpoints(-100.0, 100.0); } MultiExtremumSettings settings = new MultiExtremumSettings() { AbsolutePrecision = 1.0E-6, EvaluationBudget = 1000000 }; MultiExtremum minimum = MultiFunctionMath.FindGlobalMinimum(function, box, settings); Console.WriteLine(minimum.Dimension); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine("{0} ({1}) ?= 0.0", minimum.Value, minimum.Precision); Console.WriteLine("{0} {1} ...", minimum.Location[0], minimum.Location[1]); // We usually find the minimum at 0, but sometimes land a valley or two over. } }
public void ThomsonLocal() { for (int n = 2; n < 8; n++) { // define the Thompson metric Func <IReadOnlyList <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); } MultiExtremumSettings set = new MultiExtremumSettings() { RelativePrecision = 1.0E-9, AbsolutePrecision = 0.0 }; MultiExtremum min = MultiFunctionMath.FindLocalMinimum(f, start, set); Assert.IsTrue(min.Dimension == 2 * (n - 1)); Assert.IsTrue(TestUtilities.IsNearlyEqual(min.Value, thompsonSolutions[n], new EvaluationSettings() { AbsolutePrecision = 10.0 * min.Precision })); } }
public void PackCirclesInSquare() { // Put n points into the unit square. Place them so as to maximize the minimum distance between them. // See http://en.wikipedia.org/wiki/Circle_packing_in_a_square, http://hydra.nat.uni-magdeburg.de/packing/csq/csq.html // This is a great test problem because it is simple to understand, hard to solve, // solutions are known/proven for many n, and it covers many dimensions. double[] solutions = new double[] { Double.NaN, Double.NaN, Math.Sqrt(2.0), /* at opposite corners */ Math.Sqrt(6.0) - Math.Sqrt(2.0), 1.0, /* at each corner */ Math.Sqrt(2.0) / 2.0 /* at each corner and in center */, Math.Sqrt(13.0) / 6.0, 4.0 - 2.0 * Math.Sqrt(3.0), (Math.Sqrt(6.0) - Math.Sqrt(2.0)) / 2.0, 1.0 / 2.0, /* 3 X 3 grid */ 0.421279543983903432768821760651, 0.398207310236844165221512929748, Math.Sqrt(34.0) / 15.0, 0.366096007696425085295389370603, 2.0 / (4.0 + Math.Sqrt(3.0)), 2.0 / (Math.Sqrt(6.0) + 2.0 + Math.Sqrt(2.0)), 1.0 / 3.0 }; //int n = 11; for (int n = 2; n < 8; n++) { Console.WriteLine("n={0}", n); Func <IReadOnlyList <double>, double> function = (IReadOnlyList <double> x) => { // Interpret coordinates as (x_1, y_1, x_2, y_2, \cdots, x_n, y_n) // Iterate over all pairs of points, finding smallest distance between any pair of points. 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); }; Interval[] box = new Interval[2 * n]; for (int i = 0; i < box.Length; i++) { box[i] = Interval.FromEndpoints(0.0, 1.0); } MultiExtremumSettings settings = new MultiExtremumSettings() { RelativePrecision = 1.0E-4, AbsolutePrecision = 1.0E-6, EvaluationBudget = 10000000 }; MultiExtremum maximum = MultiFunctionMath.FindGlobalMaximum(function, box, settings); Console.WriteLine(maximum.EvaluationCount); Console.WriteLine("{0} {1}", solutions[n], maximum.Value); Assert.IsTrue(maximum.Dimension == 2 * n); Assert.IsTrue(TestUtilities.IsNearlyEqual(maximum.Value, solutions[n], new EvaluationSettings() { AbsolutePrecision = 2.0 * maximum.Precision })); } }
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); */ }