Exemple #1
0
def run_trajectory(x_0, A, b=np.zeros((2, )), tag=""):
    oracle = QuadraticOracle(A, b)
    func = oracle.func
    line_search_options = [{
        'method': 'Constant',
        'c': 0.1
    }, {
        'method': 'Constant',
        'c': 1.0
    }, {
        'method': 'Armijo'
    }, {
        'method': 'Wolfe'
    }]

    Path("pics/" + tag).mkdir(parents=True, exist_ok=True)
    for options in line_search_options:
        x_opt, message, history = gradient_descent(oracle,
                                                   x_0,
                                                   trace=True,
                                                   line_search_options=options)
        plt.figure()
        plot_levels(func)
        plot_trajectory(func, history['x'])

        filename = "pics/{2}/{0}{1}.png".format(
            options['method'],
            "_" + str(options['c']) if 'c' in options else "", tag)
        print("{}: {}".format(options['method'], len(history['x'])))
        plt.savefig(filename)
class TestBestLineSearch(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    x0 = np.array([0, 0])
    # no need for `extra` for this simple function
    oracle = QuadraticOracle(A, b)

    def test_line_search(self):
        ls_tool = LineSearchTool(method='Best')
        x_k = np.array([2.0, 2.0])
        d_k = np.array([-1.0, 1.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 1.0
        self.assertAlmostEqual(alpha_real, alpha_test)

        x_k = np.array([2.0, 2.0])
        d_k = np.array([-1.0, 0.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 1.0
        self.assertAlmostEqual(alpha_real, alpha_test)

        x_k = np.array([10.0, 10.0])
        d_k = np.array([-1.0, -1.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 7.666666666666667
        self.assertAlmostEqual(alpha_real, alpha_test)
Exemple #3
0
class TestHFN(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    f_star = -9.5
    x0 = np.array([0, 0])
    # no need for `extra` for this simple function
    oracle = QuadraticOracle(A, b)
    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        with Capturing() as output:
            x_min, message, _ = hessian_free_newton(self.oracle, self.x0)

        assert_equal(message, 'success')
        self.assertTrue(len(output) == 0, 'You should not print anything by default.')

    def test_tolerance(self):
        """Check if argument `tolerance` is supported."""
        hessian_free_newton(self.oracle, self.x0, tolerance=1e-5)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        hessian_free_newton(self.oracle, self.x0, max_iter=15)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        hessian_free_newton(self.oracle, self.x0, line_search_options={'method': 'Wolfe', 'c1': 1e-4, 'c2': 0.9})

    def test_display(self):
        """Check if something is printed when `display` is True."""
        with Capturing() as output:
            hessian_free_newton(self.oracle, self.x0, display=True)

        self.assertTrue(len(output) > 0, 'You should print the progress when `display` is True.')

    def test_quality(self):
        x_min, message, _ = hessian_free_newton(self.oracle, self.x0, tolerance=1e-5)
        f_min = self.oracle.func(x_min)

        g_k_norm_sqr = norm(self.A.dot(x_min) - self.b, 2)**2
        g_0_norm_sqr = norm(self.A.dot(self.x0) - self.b, 2)**2
        self.assertLessEqual(g_k_norm_sqr, 1e-5 * g_0_norm_sqr)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-5 * g_0_norm_sqr)

    def test_history(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = hessian_free_newton(self.oracle, x0, trace=True, line_search_options={'method': 'Constant', 'c': 1.0},
                                                      tolerance=1e-6)

        func_steps = [25.635, -9.5]
        grad_norm_steps = [11.629703349613008, 0.0]
        time_steps = [0.0] * 2  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([1., 3.])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        check_equal_histories(history, true_history)
Exemple #4
0
def experiment_2():
    np.random.seed(31415)
    kappas = np.linspace(1., 1000., 50)
    plt.figure()
    colors = ['red', 'green', 'blue', 'orange']
    labels = ['n = 2', 'n = 10', 'n = 100', 'n = 1000']

    repeat_times = 100
    runs = pd.DataFrame()
    for i, n in enumerate([2, 10, 100, 1000]):
        for j in range(repeat_times):
            iter_num_arr = []
            for kappa in kappas:
                D = np.random.uniform(1, kappa, n)
                D[0] = 1
                D[-1] = kappa
                A = diags(D)
                b = np.random.uniform(-1, 1, (n, ))
                x_0 = np.zeros((n, ))
                oracle = QuadraticOracle(A, b)
                x_opt, message, history = gradient_descent(oracle,
                                                           x_0,
                                                           trace=True,
                                                           max_iter=10**6)
                iter_num = len(history['func'])
                iter_num_arr.append(iter_num)

            runs['run_%s' % j] = iter_num_arr

        means = runs.mean(axis=1)
        stds = runs.std(axis=1)

        plt.plot(kappas, means, color=colors[i], label=labels[i], alpha=1.0)
        plt.fill_between(kappas,
                         means - stds,
                         means + stds,
                         color=colors[i],
                         alpha=0.3)
        plt.plot(kappas,
                 means - stds,
                 color=colors[i],
                 alpha=0.7,
                 linewidth=0.1)
        plt.plot(kappas,
                 means + stds,
                 color=colors[i],
                 alpha=0.7,
                 linewidth=0.1)

    plt.legend()
    plt.grid()
    plt.xlabel('Число обуcловленности')
    plt.ylabel('Число итераций до сходимости')
    plt.savefig("pics/iterations_vs_condition_number.pdf")
class TestHessVec(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    x0 = np.array([0, 0])
    # no need for `extra` for this simple function
    oracle = QuadraticOracle(A, b)

    def test_hess_vec(self):
        # f(x, y) = x^3 + y^2
        func = lambda x: x[0] ** 3 + x[1] ** 2
        x = np.array([2.0, 3.0])
        v = np.array([1.0, 0.1])
        hess_vec_test = hess_vec_finite_diff(func, x, v, eps=1e-5)
        hess_vec_real = np.array([12, 0.2])
        assert_array_almost_equal(hess_vec_real, hess_vec_test, decimal=3)

        v = np.array([1.0, -0.1])
        hess_vec_test = hess_vec_finite_diff(func, x, v, eps=1e-5)
        hess_vec_real = np.array([12, -0.2])
        assert_array_almost_equal(hess_vec_real, hess_vec_test, decimal=3)
class TestLBFGS(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    oracle = QuadraticOracle(A, b)

    f_star = -9.5
    x0 = np.array([0, 0])
    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def check_equal_histories(self, history1, history2, atol=1e-3):
        if history1 is None or history2 is None:
            self.assertEqual(history1, history2)
            return
        self.assertTrue('func' in history1 and 'func' in history2)
        self.assertTrue(np.allclose(history1['func'], history2['func'], atol=atol))
        self.assertTrue('grad_norm' in history1 and 'grad_norm' in history2)
        self.assertTrue(np.allclose(history1['grad_norm'], history2['grad_norm'], atol=atol))
        self.assertTrue('time' in history1 and 'time' in history2)
        self.assertTrue(len(history1['time']), len(history2['time']))
        self.assertTrue('x' in history1, 'x' in history2)
        if 'x' in history1:
            self.assertTrue(np.allclose(history1['x'], history2['x'], atol=atol))

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        with Capturing() as output:
            x_min, message, _ = lbfgs(self.oracle, self.x0)

        assert_equal(message, 'success')
        self.assertEqual(len(output), 0, 'You should not print anything by default.')

    def test_tol(self):
        """Check if argument `tol` is supported."""
        lbfgs(self.oracle, self.x0, tolerance=1e-6)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        lbfgs(self.oracle, self.x0, max_iter=15)

    def test_memory_size(self):
        """Check if argument `memory_size` is supported."""
        lbfgs(self.oracle, self.x0, memory_size=1)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        lbfgs(self.oracle, self.x0, line_search_options={'method': 'Wolfe', 'c1': 1e-4, 'c2': 0.9})

    def test_disp(self):
        """Check if something is printed when `disp` is True."""
        with Capturing() as output:
            lbfgs(self.oracle, self.x0, display=True)

        self.assertTrue(len(output) > 0, 'You should print the progress when `display` is True.')

    def test_trace(self):
        """Check if the history is returned correctly when `trace` is True."""
        x_min, message, hist = lbfgs(self.oracle, self.x0, trace=True)

        self.assertEqual(len(hist['grad_norm']), len(hist['func']))
        self.assertEqual(len(hist['time']), len(hist['func']))
        self.assertEqual(len(hist['x']), len(hist['func']))

        x_min, message, hist = lbfgs(self.oracle, self.x0, trace=False)
        self.assertTrue(hist is None)


    def test_quality(self):
        x_min, message, _ = lbfgs(self.oracle, self.x0, tolerance=1e-10)
        f_min = self.oracle.func(x_min)

        g_k_norm = norm(self.A.dot(x_min) - self.b, 2)
        self.assertLessEqual(abs(g_k_norm), 1e-3)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-3)

    def test_histories(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = lbfgs(self.oracle, x0, trace=True, memory_size=10, line_search_options={'method': 'Constant', 'c': 1.0},
                                        tolerance=1e-6)
        func_steps = [25.635000000000005,
                      22.99,
                      -9.3476294733722725,
                      -9.4641732176886055,
                      -9.5]
        grad_norm_steps = [11.629703349613008,
                           11.4,
                           0.55751193505619512,
                           0.26830541958992876,
                           0.0]
        time_steps = [0.0] * 5  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([1.0,  8.7]),
                   np.array([0.45349973,  3.05512941]),
                   np.array([0.73294321,  3.01292737]),
                   np.array([0.99999642,  2.99998814])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        self.check_equal_histories(history, true_history)
        self.assertEqual(message, "success")
        assert_array_almost_equal(x_min, np.array([1.0, 3.0]), decimal=3)
class TestBonus(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    x0 = np.array([0, 0])
    # no need for `extra` for this simple function
    oracle = QuadraticOracle(A, b)

    def check_equal_histories(self, history1, history2, atol=1e-3):
        if history1 is None or history2 is None:
            self.assertEqual(history1, history2)
            return
        self.assertTrue('func' in history1 and 'func' in history2)
        self.assertTrue(np.allclose(history1['func'], history2['func'], atol=atol))
        self.assertTrue('grad_norm' in history1 and 'grad_norm' in history2)
        self.assertTrue(np.allclose(history1['grad_norm'], history2['grad_norm'], atol=atol))
        self.assertTrue('time' in history1 and 'time' in history2)
        self.assertTrue(len(history1['time']), len(history2['time']))
        self.assertTrue('x' in history1, 'x' in history2)
        if 'x' in history1:
            self.assertTrue(np.allclose(history1['x'], history2['x'], atol=atol))

    def test_line_search(self):
        ls_tool = LineSearchTool(method='Best')
        x_k = np.array([2.0, 2.0])
        d_k = np.array([-1.0, 1.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 1.0
        self.assertAlmostEqual(alpha_real, alpha_test)

        x_k = np.array([2.0, 2.0])
        d_k = np.array([-1.0, 0.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 1.0
        self.assertAlmostEqual(alpha_real, alpha_test)

        x_k = np.array([10.0, 10.0])
        d_k = np.array([-1.0, -1.0])
        alpha_test = ls_tool.line_search(self.oracle, x_k, d_k)
        alpha_real = 7.666666666666667
        self.assertAlmostEqual(alpha_real, alpha_test)

    def test_lbfgs_history(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = lbfgs(self.oracle, x0, trace=True, memory_size=10, line_search_options={'method': 'Best'}, tolerance=1e-6)
        func_steps = [25.635000000000005,
                      -8.8519395950378961,
                      -9.5]
        grad_norm_steps = [11.629703349613008,
                           1.1497712070693149,
                           0]
        time_steps = [0.0] * 3  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([-0.12706157,  3.11369481]),
                   np.array([1.,  3.])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        self.check_equal_histories(history, true_history)
        self.assertEqual(message, "success")
        assert_array_almost_equal(x_min, np.array([1.0, 3.0]), decimal=3)

    def test_hfn_history(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = hessian_free_newton(self.oracle, x0, trace=True, line_search_options={'method': 'Best'}, tolerance=1e-6)

        func_steps = [25.635, -9.5]
        grad_norm_steps = [11.629703349613008, 0.0]
        time_steps = [0.0] * 2  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([1., 3.])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        self.check_equal_histories(history, true_history)
        self.assertEqual(message, "success")
        assert_array_almost_equal(x_min, np.array([1.0, 3.0]), decimal=3)
class TestHFN(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    f_star = -9.5
    x0 = np.array([0, 0])
    # no need for `extra` for this simple function
    oracle = QuadraticOracle(A, b)
    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def check_equal_histories(self, history1, history2, atol=1e-3):
        if history1 is None or history2 is None:
            self.assertEqual(history1, history2)
            return
        self.assertTrue('func' in history1 and 'func' in history2)
        self.assertTrue(np.allclose(history1['func'], history2['func'], atol=atol))
        self.assertTrue('grad_norm' in history1 and 'grad_norm' in history2)
        self.assertTrue(np.allclose(history1['grad_norm'], history2['grad_norm'], atol=atol))
        self.assertTrue('time' in history1 and 'time' in history2)
        self.assertTrue(len(history1['time']), len(history2['time']))
        self.assertTrue('x' in history1, 'x' in history2)
        if 'x' in history1:
            self.assertTrue(np.allclose(history1['x'], history2['x'], atol=atol))

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        with Capturing() as output:
            x_min, message, _ = hessian_free_newton(self.oracle, self.x0)

        assert_equal(message, 'success')
        self.assertTrue(len(output) == 0, 'You should not print anything by default.')

    def test_tol(self):
        """Check if argument `tol` is supported."""
        hessian_free_newton(self.oracle, self.x0, tolerance=1e-6)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        hessian_free_newton(self.oracle, self.x0, max_iter=15)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        hessian_free_newton(self.oracle, self.x0, line_search_options={'method': 'Wolfe', 'c1': 1e-4, 'c2': 0.9})

    def test_disp(self):
        """Check if something is printed when `disp` is True."""
        with Capturing() as output:
            hessian_free_newton(self.oracle, self.x0, display=True)

        self.assertTrue(len(output) > 0, 'You should print the progress when `display` is True.')

    def test_trace(self):
        """Check if the history is returned correctly when `trace` is True."""
        x_min, message, hist = hessian_free_newton(self.oracle, self.x0, trace=True)

        self.assertEqual(len(hist['grad_norm']), len(hist['func']))
        self.assertEqual(len(hist['time']), len(hist['func']))
        self.assertEqual(len(hist['x']), len(hist['func']))

        x_min, message, hist = hessian_free_newton(self.oracle, self.x0, trace=False)
        self.assertTrue(hist is None)

    def test_quality(self):
        x_min, message, _ = hessian_free_newton(self.oracle, self.x0, tolerance=1e-10)
        f_min = self.oracle.func(x_min)

        g_k_norm = norm(self.A.dot(x_min) - self.b, 2)
        self.assertLessEqual(abs(g_k_norm), 1e-3)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-3)

    def test_histories(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = hessian_free_newton(self.oracle, x0, trace=True, line_search_options={'method': 'Constant', 'c': 1.0},
                                                      tolerance=1e-6)

        func_steps = [25.635, -9.5]
        grad_norm_steps = [11.629703349613008, 0.0]
        time_steps = [0.0] * 2  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([1., 3.])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        self.check_equal_histories(history, true_history)
        self.assertEqual(message, "success")
        assert_array_almost_equal(x_min, np.array([1.0, 3.0]), decimal=3)
class TestLBFGS(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    oracle = QuadraticOracle(A, b)

    f_star = -9.5
    x0 = np.array([0, 0])

    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        opt = LBFGS(self.oracle, self.x0)
        opt.run()

    def test_tolerance(self):
        """Check if argument `tolerance` is supported."""
        LBFGS(self.oracle, self.x0, tolerance=1e-5)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        opt = LBFGS(self.oracle, self.x0)
        opt.run(max_iter=0)

    def test_memory_size(self):
        """Check if argument `memory_size` is supported."""
        LBFGS(self.oracle, self.x0, memory_size=1)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        LBFGS(self.oracle,
              self.x0,
              line_search_options={
                  'method': 'Wolfe',
                  'c1': 1e-4,
                  'c2': 0.9
              })

    def test_quality(self):
        opt = LBFGS(self.oracle, self.x0, tolerance=1e-5)
        opt.run(5)
        x_min = opt.hist['x_star']
        # x_min, message, _ = LBFGS(self.oracle, self.x0, tolerance=1e-5)
        f_min = self.oracle.func(x_min)

        g_k_norm_sqr = norm(self.A.dot(x_min) - self.b, 2)**2
        g_0_norm_sqr = norm(self.A.dot(self.x0) - self.b, 2)**2
        self.assertLessEqual(g_k_norm_sqr, 1e-5 * g_0_norm_sqr)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-5 * g_0_norm_sqr)

    def test_history(self):
        x0 = -np.array([1.3, 2.7])
        opt = LBFGS(self.oracle,
                    x0,
                    memory_size=10,
                    line_search_options={
                        'method': 'Constant',
                        'c': 1.0
                    },
                    tolerance=1e-6)
        opt.run(10)
        x_min = opt.hist['x_star']
        func_steps = [
            25.635000000000005, 22.99, -9.3476294733722725,
            -9.4641732176886055, -9.5
        ]
        grad_norm_steps = [
            11.629703349613008, 11.4, 0.55751193505619512, 0.26830541958992876,
            0.0
        ]
        time_steps = [0.0] * 5  # Dummy values
        x_steps = [
            np.array([-1.3, -2.7]),
            np.array([1.0, 8.7]),
            np.array([0.45349973, 3.05512941]),
            np.array([0.73294321, 3.01292737]),
            np.array([0.99999642, 2.99998814])
        ]
        true_history = dict(grad_norm=grad_norm_steps,
                            time=time_steps,
                            x=x_steps,
                            func=func_steps)
        check_equal_histories(opt.hist, true_history)
class TestBFGS(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]], dtype=np.float64)
    b = np.array([1, 6], dtype=np.float64)
    oracle = QuadraticOracle(A, b)

    f_star = -9.5
    x0 = np.array([0, 0], dtype=np.float64)

    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        opt = BFGS(self.oracle, self.x0)
        opt.run()

    def test_tolerance(self):
        """Check if argument `tolerance` is supported."""
        BFGS(self.oracle, self.x0, tolerance=1e-5)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        opt = BFGS(self.oracle, self.x0)
        opt.run(max_iter=0)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        BFGS(self.oracle,
             self.x0,
             line_search_options={
                 'method': 'Wolfe',
                 'c1': 1e-4,
                 'c2': 0.9
             })

    def test_quality(self):
        opt = BFGS(self.oracle, self.x0, tolerance=1e-5)
        opt.run(5)
        x_min = opt.hist['x_star']
        # x_min, message, _ = LBFGS(self.oracle, self.x0, tolerance=1e-5)
        f_min = self.oracle.func(x_min)

        g_k_norm_sqr = norm(self.A.dot(x_min) - self.b, 2)**2
        g_0_norm_sqr = norm(self.A.dot(self.x0) - self.b, 2)**2
        self.assertLessEqual(g_k_norm_sqr, 1e-5 * g_0_norm_sqr)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-5 * g_0_norm_sqr)

    def test_history(self):
        x0 = -np.array([1.3, 2.7])
        opt = BFGS(self.oracle,
                   x0,
                   line_search_options={
                       'method': 'Constant',
                       'c': 1.0
                   },
                   tolerance=1e-6)
        opt.run(10)
        x_min = opt.hist['x_star']
        func_steps = [25.635000000000005, 22.99, -9.48707349065929, -9.5]
        grad_norm_steps = [11.629703349613008, 11.4, 0.22738961577617722, 0.0]
        time_steps = [0.0] * 4  # Dummy values
        x_steps = [
            np.array([-1.3, -2.7]),
            np.array([1.0, 8.7]),
            np.array([1.0, 2.88630519]),
            np.array([1., 3.])
        ]
        true_history = dict(grad_norm=grad_norm_steps,
                            time=time_steps,
                            x=x_steps,
                            func=func_steps)
        check_equal_histories(opt.hist, true_history)
class TestLBFGS(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    oracle = QuadraticOracle(A, b)

    f_star = -9.5
    x0 = np.array([0, 0])

    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        with Capturing() as output:
            x_min, message, _ = lbfgs(self.oracle, self.x0)

        assert_equal(message, 'success')
        self.assertEqual(len(output), 0,
                         'You should not print anything by default.')

    def test_tolerance(self):
        """Check if argument `tolerance` is supported."""
        lbfgs(self.oracle, self.x0, tolerance=1e-5)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        lbfgs(self.oracle, self.x0, max_iter=15)

    def test_memory_size(self):
        """Check if argument `memory_size` is supported."""
        lbfgs(self.oracle, self.x0, memory_size=1)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        lbfgs(self.oracle,
              self.x0,
              line_search_options={
                  'method': 'Wolfe',
                  'c1': 1e-4,
                  'c2': 0.9
              })

    def test_display(self):
        """Check if something is printed when `display` is True."""
        with Capturing() as output:
            lbfgs(self.oracle, self.x0, display=True)

        self.assertTrue(
            len(output) > 0,
            'You should print the progress when `display` is True.')

    def test_quality(self):
        x_min, message, _ = lbfgs(self.oracle, self.x0, tolerance=1e-5)
        f_min = self.oracle.func(x_min)

        g_k_norm_sqr = norm(self.A.dot(x_min) - self.b, 2)**2
        g_0_norm_sqr = norm(self.A.dot(self.x0) - self.b, 2)**2
        self.assertLessEqual(g_k_norm_sqr, 1e-5 * g_0_norm_sqr)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-5 * g_0_norm_sqr)

    def test_history(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = lbfgs(self.oracle,
                                        x0,
                                        trace=True,
                                        memory_size=10,
                                        line_search_options={
                                            'method': 'Constant',
                                            'c': 1.0
                                        },
                                        tolerance=1e-6)
        func_steps = [
            25.635000000000005, 22.99, -9.3476294733722725,
            -9.4641732176886055, -9.5
        ]
        grad_norm_steps = [
            11.629703349613008, 11.4, 0.55751193505619512, 0.26830541958992876,
            0.0
        ]
        time_steps = [0.0] * 5  # Dummy values
        x_steps = [
            np.array([-1.3, -2.7]),
            np.array([1.0, 8.7]),
            np.array([0.45349973, 3.05512941]),
            np.array([0.73294321, 3.01292737]),
            np.array([0.99999642, 2.99998814])
        ]
        true_history = dict(grad_norm=grad_norm_steps,
                            time=time_steps,
                            x=x_steps,
                            func=func_steps)
        check_equal_histories(history, true_history)

    @unittest.skipUnless(test_bonus, 'Skipping bonus test...')
    def test_history_best(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = lbfgs(self.oracle,
                                        x0,
                                        trace=True,
                                        memory_size=10,
                                        line_search_options={'method': 'Best'},
                                        tolerance=1e-6)
        func_steps = [25.635000000000005, -8.8519395950378961, -9.5]
        grad_norm_steps = [11.629703349613008, 1.1497712070693149, 0]
        time_steps = [0.0] * 3  # Dummy values
        x_steps = [
            np.array([-1.3, -2.7]),
            np.array([-0.12706157, 3.11369481]),
            np.array([1., 3.])
        ]
        true_history = dict(grad_norm=grad_norm_steps,
                            time=time_steps,
                            x=x_steps,
                            func=func_steps)
        check_equal_histories(history, true_history)
Exemple #12
0
def experiment_5_and_6(algo='gd'):
    np.random.seed(31415)
    m, n = 2000, 1000
    A = np.random.randn(m, n)
    b = np.sign(np.random.randn(m))
    regcoef = 1 / m

    logreg_oracle = create_log_reg_oracle(A,
                                          b,
                                          regcoef,
                                          oracle_type='optimized')

    line_search_options = [
        {
            'method': 'Constant',
            'c': 1.0
        },
        {
            'method': 'Constant',
            'c': 0.95
        },
        {
            'method': 'Constant',
            'c': 0.9
        },
        {
            'method': 'Constant',
            'c': 0.85
        },
        {
            'method': 'Armijo',
            'c1': 1e-8
        },
        {
            'method': 'Armijo',
            'c1': 1e-6
        },
        {
            'method': 'Armijo',
            'c1': 1e-4
        },
        {
            'method': 'Armijo',
            'c1': 1e-1
        },
        {
            'method': 'Wolfe',
            'c2': 1.5
        },
        {
            'method': 'Wolfe',
            'c2': 0.9
        },
        {
            'method': 'Wolfe',
            'c2': 0.1
        },
        {
            'method': 'Wolfe',
            'c2': 0.01
        },
    ]

    colors = ['#e66101', '#fdb863', '#b2abd2', '#5e3c99']
    styles = {
        'Constant': {
            'linestyle': '--',
            'dashes': (2, 5),
            'linewidth': 2
        },
        'Armijo': {
            'linestyle': '--',
            'dashes': (5, 2)
        },
        'Wolfe': {
            'linestyle': 'solid'
        },
    }

    x_0_list = [None] * 3
    x_0_list[0] = np.zeros((n, ))
    x_0_list[1] = np.random.uniform(-1, 1, (n, ))
    x_0_list[2] = np.ones((n, ))

    for k, x_0 in enumerate(x_0_list):
        plt.figure(figsize=(12, 9))
        for i, options in tqdm(enumerate(line_search_options)):
            if algo == 'GD':
                x_opt, message, history = gradient_descent(
                    logreg_oracle,
                    x_0,
                    trace=True,
                    line_search_options=options)
            else:
                x_opt, message, history = newton(logreg_oracle,
                                                 x_0,
                                                 trace=True,
                                                 line_search_options=options)
            args = list(options.keys()) + list(options.values())
            label = "{} ({}={}, {}={})".format(algo, args[0], args[2], args[1],
                                               args[3])
            values = 2 * np.log(
                (history['grad_norm'] / history['grad_norm'][0]))
            method = args[2]
            plt.plot(values + np.random.randn(values.size) * 0.05,
                     color=colors[i % len(colors)],
                     label=label,
                     alpha=0.7,
                     **styles[method])
        plt.xlabel('Номер итерации')
        plt.ylabel('Логарифм относительного квадрата нормы градиента')
        plt.legend(loc='upper right')
        plt.grid()

        Path("pics/logreg_{}_linear_search_strategies".format(algo)).mkdir(
            parents=True, exist_ok=True)
        plt.savefig(
            "pics/logreg_{}_linear_search_strategies/x_0_{}.png".format(
                algo, k))

    np.random.seed(31415)
    n = 2000
    C = ortho_group.rvs(n)
    A = C.T @ np.diag(np.random.uniform(1, 20, (n, ))) @ C
    b = np.random.randn(n)
    x_0 = np.zeros((n, ))

    quadratic_oracle = QuadraticOracle(A, b)
    x_opt = np.linalg.solve(A, b)
    f_opt = quadratic_oracle.func(x_opt)

    line_search_options = [
        {
            'method': 'Constant',
            'c': 0.09
        },
        {
            'method': 'Constant',
            'c': 0.085
        },
        {
            'method': 'Constant',
            'c': 0.08
        },
        {
            'method': 'Constant',
            'c': 0.075
        },
        {
            'method': 'Armijo',
            'c1': 1e-10
        },
        {
            'method': 'Armijo',
            'c1': 1e-7
        },
        {
            'method': 'Armijo',
            'c1': 1e-4
        },
        {
            'method': 'Armijo',
            'c1': 1e-1
        },
        {
            'method': 'Wolfe',
            'c2': 1.5
        },
        {
            'method': 'Wolfe',
            'c2': 0.9
        },
        {
            'method': 'Wolfe',
            'c2': 0.1
        },
        {
            'method': 'Wolfe',
            'c2': 0.01
        },
    ]

    x_0_list = [None] * 3
    x_0_list[0] = np.zeros((n, ))
    x_0_list[1] = np.random.uniform(-1, 1, (n, ))
    x_0_list[2] = x_opt + np.random.randn(n, ) * 0.2

    for k, x_0 in enumerate(x_0_list):
        plt.figure(figsize=(12, 9))
        for i, options in tqdm(enumerate(line_search_options)):
            if algo == 'GD':
                x_opt, message, history = gradient_descent(
                    quadratic_oracle,
                    x_0,
                    trace=True,
                    line_search_options=options)
            else:
                x_opt, message, history = newton(quadratic_oracle,
                                                 x_0,
                                                 trace=True,
                                                 line_search_options=options)
            args = list(options.keys()) + list(options.values())
            label = "{} ({}={}, {}={})".format(algo, args[0], args[2], args[1],
                                               args[3])
            values = np.log(np.abs((history['func'] - f_opt) / f_opt) + 1e-16)
            method = args[2]
            plt.plot(values + np.random.randn(values.size) * 0.05,
                     color=colors[i % len(colors)],
                     label=label,
                     alpha=0.7,
                     **styles[method])
        plt.xlabel('Номер итерации')
        plt.ylabel('Логарифм относительной невязки')
        plt.legend(loc='upper right')
        plt.grid()
        Path("pics/quadratic_{}_linear_search_strategies".format(algo)).mkdir(
            parents=True, exist_ok=True)
        plt.savefig(
            "pics/quadratic_{}_linear_search_strategies/x_0_{}.png".format(
                algo, k))
Exemple #13
0
class TestNCG(unittest.TestCase):
    # Define a simple quadratic function for testing
    A = np.array([[1, 0], [0, 2]])
    b = np.array([1, 6])
    oracle = QuadraticOracle(A, b)

    f_star = -9.5
    x0 = np.array([0, 0])
    # For this func |nabla f(x)| < tol ensures |f(x) - f(x^*)| < tol^2

    def test_default(self):
        """Check if everything works correctly with default parameters."""
        with Capturing() as output:
            x_min, message, _ = nonlinear_conjugate_gradients(self.oracle, self.x0)

        assert_equal(message, 'success')
        self.assertEqual(len(output), 0, 'You should not print anything by default.')

    def test_tolerance(self):
        """Check if argument `tolerance` is supported."""
        nonlinear_conjugate_gradients(self.oracle, self.x0, tolerance=1e-5)

    def test_max_iter(self):
        """Check if argument `max_iter` is supported."""
        nonlinear_conjugate_gradients(self.oracle, self.x0, max_iter=15)

    def test_line_search_options(self):
        """Check if argument `line_search_options` is supported."""
        nonlinear_conjugate_gradients(self.oracle, self.x0, line_search_options={'method': 'Wolfe', 'c1': 0.01, 'c2': 0.01})

    def test_display(self):
        """Check if something is printed when `display` is True."""
        with Capturing() as output:
            nonlinear_conjugate_gradients(self.oracle, self.x0, display=True)

        self.assertTrue(len(output) > 0, 'You should print the progress when `display` is True.')

    def test_quality(self):
        x_min, message, _ = nonlinear_conjugate_gradients(self.oracle, self.x0, tolerance=1e-5)
        f_min = self.oracle.func(x_min)

        g_k_norm_sqr = norm(self.A.dot(x_min) - self.b, 2)**2
        g_0_norm_sqr = norm(self.A.dot(self.x0) - self.b, 2)**2
        self.assertLessEqual(g_k_norm_sqr, 1e-5 * g_0_norm_sqr)
        self.assertLessEqual(abs(f_min - self.f_star), 1e-5 * g_0_norm_sqr)

    def test_history(self):
        x0 = -np.array([1.3, 2.7])
        x_min, message, history = nonlinear_conjugate_gradients(self.oracle, x0, trace=True,
                                        line_search_options={'method': 'Constant', 'c': 0.6},
                                        tolerance=1e-3)
        func_steps = [25.635000000000005,
                      -7.777199999999997,
                      -7.8463333368073584,
                      -9.439531896665148,
                      -9.41251357036308,
                      -9.4977531453388693]
        grad_norm_steps = [11.629703349613008,
                           2.4586174977006889,
                           2.5711348318091276,
                           0.48633577943739081,
                           0.58855118960609565,
                           0.092585266951596912]
        time_steps = [0.0] * 6  # Dummy values
        x_steps = [np.array([-1.3, -2.7]),
                   np.array([0.08, 4.14]),
                   np.array([0.93729171, 4.28518501]),
                   np.array([1.07314317, 2.75959796]),
                   np.array([1.05960886, 2.7072376]),
                   np.array([1.02038104, 3.04515707])]
        true_history = dict(grad_norm=grad_norm_steps, time=time_steps, x=x_steps, func=func_steps)
        check_equal_histories(history, true_history)