Пример #1
0
        // NOTE: Неизвстно, как преобразовать Func<Vector<double>, double> к Func<PointN, double>
        // Поэтому будут использованы две аналогичные функции
        // Для них используются ужасно похожие лямбды.
        // Возможно, этот конфликт можно решить
        // TODO: надо бы сравнить производительность алгоритмов
        // Можно привлечь сюда число итераций например
        // TODO: см в тетради и реши все тестовые задачи
        // COMPLETE
        #region TEST2_1
        static void Test2_1()
        {
            // Input data
            FunctionNDByAlex  funcND        = (PointN point) => { return(4 * System.Math.Pow(point.At(0) - 5.0, 2.0) + System.Math.Pow(point.At(1) - 6.0, 2.0)); };
            FunctionNDMathNet funcNDMathNet = (VectorNMathNet point) => { return(4 * System.Math.Pow(point.At(0) - 5.0, 2.0) + System.Math.Pow(point.At(1) - 6.0, 2.0)); };
            PointN            x0            = new PointN(100.0, 100.0);
            VectorNMathNet    x0MathNet     = Helpers.PointNToMathNet(x0);
            const double      eps           = 0.01;

            // Testing
            TestOptimalGradientMethod(funcND, x0, eps);
            TestVariableMetricMethod(funcNDMathNet, x0MathNet, eps);
        }
        // Это хорошая идея - выносить параметры вроде eps сюда
        // Можно добавить список строк List<String>
        // И выводить в него информацию по алгоритму
        // Затем, в output мы берем его и выводим на экран (по желанию)
        public PointNMathNet FindMin(double eps)
        {
            int             k    = 0;
            PointNMathNet   xk   = x0;         // x(k)
            PointNMathNet   xk_1 = x0;         // x(k-1)
            Matrix <double> Hk   = H0.Clone(); // Квазиньютоновская матрицы
            double          ak   = 0.0;

            // Вспомогательные вектора
            VectorNMathNet sk = VectorNMathNet.Build.Dense(n);
            VectorNMathNet yk = VectorNMathNet.Build.Dense(n);

            while (true)
            {
                VectorNMathNet gradient = Gradient.Calculate(funcND, xk);
                Log.Add(String.Format("Grad(F(\n{0, -23})) = \n{1, -25}", xk, gradient)); // TODO: некрасивый вывод
                if (gradient.L2Norm() <= eps)                                             // градиент слишком мал, максимум очень близко
                {
                    return(xk);
                }

                if (k != 0)
                {
                    sk = xk - xk_1;
                    //Log.Add(String.Format("sk:\n{0}", sk));
                    Matrix <double> m_sk   = sk.ToColumnMatrix();
                    Matrix <double> m_sk_t = m_sk.Transpose();

                    yk = Gradient.Calculate(funcND, xk) - Gradient.Calculate(funcND, xk_1); // TODO Один из членов этого вектора становится слишком мал (или Hk или M_yk_t)
                    //Log.Add(String.Format("yk:\n{0}", yk));
                    Matrix <double> m_yk   = yk.ToColumnMatrix();
                    Matrix <double> m_yk_t = m_yk.Transpose();

                    Hk = Hk - ((Hk * m_yk * m_yk_t * Hk) / (m_yk_t * Hk * m_yk)[0, 0]) + ((m_sk * m_sk_t)[0, 0] / (m_yk_t * m_sk)[0, 0]);
                    Log.Add(String.Format("Hk:\n{0}", Hk));
                }

                VectorNMathNet pk     = -Hk * gradient;
                Function1D     func1D = (double alpha) => { return(funcND((xk + pk * alpha))); };
                ak = OneDimensionalMinimization.FindMin(func1D, ak, eps);
                Log.Add(String.Format("ak = {0}", ak));

                // Инкремент
                xk_1 = xk;
                xk   = xk + ak * pk;
                k++;
                Log.Add("==================Next Iteration====================");
            }
        }
Пример #3
0
        public static VectorNMathNet Calculate(Func <PointNMathNet, double> f, PointNMathNet point, double h = 0.1)
        {
            int            n        = point.Count;
            VectorNMathNet gradient = VectorNMathNet.Build.Dense(n);

            for (int i = 0; i < n; i++)
            {
                PointNMathNet xMinusH = point.Clone();
                xMinusH[i] -= h;
                PointNMathNet xPlusH = point.Clone();
                xPlusH[i]  += h;
                gradient[i] = (f(xPlusH) - f(xMinusH)) / (2 * h);
            }

            return(gradient);
        }
Пример #4
0
        // Работает с MathNet.Numerics.LinearAlgebra.Vector<double>;
        static void TestVariableMetricMethod(FunctionNDMathNet funcNDMathNet, VectorNMathNet x0, double eps)
        {
            VariableMetricMethod vmm = new VariableMetricMethod(funcNDMathNet, x0);

            sw.Start();
            VectorNMathNet result = vmm.FindMin(eps);

            sw.Stop();

            //Console.Write(String.Join("\n", vmm.Log)); // Выводим все сообщения от этого метода
            Console.WriteLine("Рабочая информация метода VariableMetric лежит в txt файле VariableMetricOutput");
            System.IO.File.WriteAllText(@"D:\Study\OptimizationMethods\3\VariableMetricOutput.txt", String.Join("\n", vmm.Log));
            Console.WriteLine("\n---------------------------------------------");
            Console.WriteLine("Variable metric method: x_min = {{{0} {1}}}", result[0].ToString("N6"), result[1].ToString("N6"));
            Console.WriteLine("F(x_min) = {0}", funcNDMathNet(result));
            Console.WriteLine("Time: {0}ms", sw.ElapsedMilliseconds);
            Console.WriteLine("=============================================");
        }
Пример #5
0
        // FAILED (первый несет чушь)
        // 1) Градиент все время прыгает во все стороны, а xk все наращивается
        // Все потому, что вектор указыает направление наискорейшего возрастания и очень большой
        // xk быстро наращивается
        // 2) yk или Hk или M_yk_t становится слишком мал
        // вследствие этого, на одной из итераций (когда близко к минимуму), мы получаем деление на нуль
        // Поэтому я выставил eps = 0.5 для того, чтобы метод остановился до деления на нуль
        // Вывод: Методы чуть менее чем полностью не приспособлены для минимизации не униминимальных функций
        #region TEST2_1_1
        static void Test2_1_1()
        {
            // Input data
            FunctionNDByAlex funcND = (PointN point) =>
            {
                return(SMath.Pow(SMath.Pow(point.At(0), 2) + point.At(1) - 11.0, 2.0)
                       + SMath.Pow(point.At(0) + SMath.Pow(point.At(1), 2) - 7.0, 2.0));
            };
            FunctionNDMathNet funcNDMathNet = (VectorNMathNet point) =>
            {
                return(SMath.Pow(SMath.Pow(point.At(0), 2) + point.At(1) - 11.0, 2.0)
                       + SMath.Pow(point.At(0) + SMath.Pow(point.At(1), 2) - 7.0, 2.0));
            };

            PointN         x0        = new PointN(3.0, 3.0);
            VectorNMathNet x0MathNet = Helpers.PointNToMathNet(x0);
            const double   eps       = 0.1; // TODO при слишком малых eps происходит деление на 0 в формуле пересчета Hk

            // Testing
            TestOptimalGradientMethod(funcND, x0, eps);
            TestVariableMetricMethod(funcNDMathNet, x0MathNet, eps);
        }