def test_newtons_method_quad1(): """Test newtons_method for a single variable quadratic. Notes ----- The test function is: 5x^2 - 2x + 3 The test gradient is: 10x - 2 The test hessian is: 10 The test point is: [0.25] Expect result of newtons_method to be: (2.8, [0.2], 0.0, 0) Returns ------- None """ quad = MultiVarFunction({5: [2], -2: [1], 3: [0]}, 1) grad = quad.construct_grad() hess = quad.construct_hess() ip = [0.25] # initial point res = newtons_method.newtons_opt(quad, grad, hess, ip) # check results assert res[0] == 2.8, "Incorrect value of test function at minimum." assert res[1] == [0.2], "Incorrect minimum found for test function." assert res[ 2] == 0.0, "Incorrect value for the gradient at the minimum found." assert res[ 3] == 1, "Incorrect number of iterations for the test function. Should be one."
def test_newtons_method_quad2(): """Test newtons_method for a 2 variable quadratic. Notes ----- The test function is: 3x^2y - 7yx - 9 The test gradient [df/dx, df/dy] is: [6xy-7y, 3x^2-7x] The test hessian ([d2f/dx2, d2f/dxdy], [d2f/dydx, d2f/dy2]) is: [6y, 6x-7], [6x-7, 0] The test point is: [-6,0] Expect result of newtons_method to be: ? Returns ------- None """ # original function quad2 = MultiVarFunction({3: [2, 1], -7: [1, 1], -9: [0, 0]}, 2) grad2 = quad2.construct_grad() hess2 = quad2.construct_hess() # initial point ip2 = [-6, 0] res = newtons_method.newtons_opt(quad2, grad2, hess2, ip2) # positive number of iterations assert res[-1] > 0
def test_update_hessian_sr1(): """Test the update_hessian_bfgs function.""" func = MultiVarFunction({4: [2, 1], 5: [0, 1], -6: [0, 0]}, 2) grad = func.construct_grad() hess = func.construct_hess() hess_eval = hess([1, 2]) point = np.array([2, 3]) point1 = np.array([4, 3]) sk = point1 - point yk = grad(point1) - grad(point) assert np.equal(sk, np.array([2, 0])).all() assert np.equal(yk, np.array([48., 48.])).all() assert np.equal(hess_eval, np.array([[16, 8], [8, 0]])).all() # check regular (non-inverted) result1 = quasi_newton.update_hessian_sr1(hess_eval, grad, point, point1, False) assert np.equal( result1, np.array([[16 + 256 / 32, 8 + 512 / 32], [8 + 512 / 32, 1024 / 32]])).all() # check inverted result2 = quasi_newton.update_hessian_sr1(hess_eval, grad, point, point1, True) top_left = 16 + 1322500 / -73632 top_right = 8 + 441600 / -73632 lower_left = 8 + 441600 / -73632 lower_right = 147456 / -73632 assert np.equal( result2, np.array([[top_left, top_right], [lower_left, lower_right]])).all()
def test_update_hessian_bfgs(): """Test the update_hessian_bfgs function. Makes sure that the gradient and hessians are evaluated properly by MultiVarFunction. Makes sure that the function returns a valid hessian of the correct value and shape. """ # make the test function # 2xy^2 + 3x^2 + 7 func = MultiVarFunction({2: [1, 2], 3: [2, 0], 7: [0, 0]}, 2) # make the gradient grad = func.construct_grad() # check df/dx (partial wrt x) assert grad[0].structure == {2: [0, 2], 6: [1, 0]} # check df/dy (partial wrt y) assert grad[1].structure == {4: [1, 1]} # make the hessian hess = func.construct_hess() # check d2f/dx2 assert hess[0][0].structure == {6: [0, 0]} # check d2f/dxdy assert hess[0][1].structure == {4: [0, 1]} # check d2f/dydx assert hess[1][0].structure == {4: [0, 1]} # check d2f/dy2 assert hess[1][1].structure == {4: [1, 0]} # evaluate hessian at arbitrary point hess_eval = hess([1, 2]) # check evaluation of hessian at point (1,2) assert np.equal(hess_eval, np.array([[6., 8.], [8., 4.]])).all() # choose some arbitrary points pk = np.array([2, 3]) pk1 = np.array([3, 4]) result1 = quasi_newton.update_hessian_bfgs(hess_eval, grad, pk, pk1, False) # check the resulting array (non-inverse) assert np.equal( result1, np.array([[-190 + 400 / 44, -160 + 480 / 44], [-160 + 480 / 44, -140 + 576 / 44]])).all() # check inverted hessian version result2 = quasi_newton.update_hessian_bfgs(hess_eval, grad, pk, pk1, True) a = np.array([[1 - 20 / 44, -24 / 44], [-20 / 44, 1 - 24 / 44]]) b = np.array([[6, 8], [8, 4]]) c = np.array([[1 - 20 / 44, -20 / 44], [-24 / 44, 1 - 24 / 44]]) d = np.array([[1 / 44, 1 / 44], [1 / 44, 1 / 44]]) res = np.dot(np.dot(a, b), c) + d assert np.equal(result2, res).all()
def test_update_hessian_dfp(): """Test dfp approximation.""" quad2 = MultiVarFunction({3: [2, 1], +7: [1, 1]}, 2) grad2 = quad2.construct_grad() hess2 = quad2.construct_hess() val = np.array([-0.1, 0.1]) hess = hess2(val) step = np.dot(-grad2(val), np.linalg.inv(hess)) val1 = val + step new_hess = quasi_newton.update_hessian_dfp(hess, grad2, val, val1) answer_is = np.array([[0.19, 6.64], [6.64, -0.072]]) assert_array_almost_equal(new_hess, answer_is, decimal=2)
def test_update_hessian_broyden(): """Test broyden approximation.""" quad2 = MultiVarFunction({3: [2, 1], -7: [1, 1], -9: [0, 0]}, 2) grad2 = quad2.construct_grad() hess2 = quad2.construct_hess() val = np.array([-6, 0]) hess = hess2(val) step = np.dot(-grad2(val), np.linalg.inv(hess)) val1 = val + step new_hess = quasi_newton.update_hessian_broyden(hess, grad2, val, val1) answer_is = np.array([[0, -43], [-32.53, 0]]) assert_array_almost_equal(new_hess, answer_is, decimal=2)
def test_quasi_newton_quad2(): """Test newtons_method for a 2 variable quadratic. Notes ----- The test function is: 3x^2y - 7yx - 9 The test gradient [df/dx, df/dy] is: [6xy-7y, 3x^2-7x] The test hessian ([d2f/dx2, d2f/dxdy], [d2f/dydx, d2f/dy2]) is: [6y, 6x-7], [6x-7, 0] The test point is: [-6,0] Expect result of newtons_method to be: ? Returns ------- None """ quad2 = MultiVarFunction({3: [2, 0], +7: [0, 2], +19: [0, 0]}, 2) grad2 = quad2.construct_grad() hess2 = quad2.construct_hess() val = np.array([1, 0.1]) res1 = quasi_newton.quasi_newtons_opt(quad2, grad2, hess2, val, update=None) res2 = quasi_newton.quasi_newtons_opt(quad2, grad2, hess2, val, quasi_newton.update_hessian_broyden, inv=True) res3 = quasi_newton.quasi_newtons_opt(quad2, grad2, hess2, val, quasi_newton.update_hessian_bfgs) res4 = quasi_newton.quasi_newtons_opt(quad2, grad2, hess2, val, quasi_newton.update_hessian_dfp, inv=True)
def test_multivarfunction_quad2(): """Test the MultiVarFunction object against hand-built functions.""" def f(x): """Test function. x : np.array((N,)) f(x) : np.array((1)) """ return np.array([3 * x[1] * x[0]**2 - 7 * x[0] * x[1] - 9]) def g(x): """Test gradient. x = np.array((N,)) g(x) = np.array((N,)) """ return np.array([6 * x[0] * x[1] - 7 * x[1], 3 * x[0]**2 - 7 * x[0]]) def h(x): """Test hessian. x = np.array((N,)) h(x) = np.array((N,N)) """ return np.array([[6 * x[1], 6 * x[0] - 7], [6 * x[0] - 7, 0.]]) # test multivarfunction quad2 = MultiVarFunction({3: [2, 1], -7: [1, 1], -9: [0, 0]}, 2) grad2 = quad2.construct_grad() hess2 = quad2.construct_hess() val = np.array([-6, 0]) assert_equal(quad2(val), f(val)) assert_equal(grad2(val), g(val)) assert_equal(hess2(val), h(val)) # check function returns assert_equal(quad2(val), np.array([-9])) assert_equal(grad2(val), np.array([0, 150])) assert_equal(hess2(val), np.array([[0, -43], [-43, 0]]))
def test_update_hessian_dfp_inverse(): """Test the update_hessian_dfp function for inverted Hessians.""" # inverse test func = MultiVarFunction({2: [1, 2], -9: [1, 0], 8: [2, 0]}, 2) grad = func.construct_grad() hess = func.construct_hess() point1 = np.array([3, 2]) point = np.array([1, 1]) hess_eval = hess([4, 3]) yk = grad(point1) - grad(point) sk = point1 - point assert np.equal(hess_eval, np.array([[16, 12], [12, 16]])).all() assert np.equal(yk, np.array([38, 20])).all() assert np.equal(sk, np.array([2, 1])).all() result = quasi_newton.update_hessian_dfp(hess_eval, grad, point, point1, True) a = np.array([[16, 12], [12, 16]]) b = np.array([[4 / 96, 2 / 96], [2 / 96, 1 / 96]]) c = np.array([[1444, 760], [760, 400]]) d = np.dot(np.dot(a, c), a) / 47744 res = a + b - d assert np.equal(result, res).all()