예제 #1
0
        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);
        }
예제 #2
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);
        }
예제 #3
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)
                }));
            }
        }
예제 #4
0
        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 }));
            }
        }
예제 #5
0
        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.
            }
        }
예제 #6
0
        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
                }));
            }
        }
예제 #7
0
        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
                }));
            }
        }
예제 #8
0
        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);
             */
        }