def test_eval(): def f1(x): return x def f2(x, y): return x + y ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) pos1 = 3 pos2 = [3, 4] assert (ad1._eval(pos1, wrt_variables=False).val == pos1) assert (ad1._eval(pos1, wrt_variables=False).der == 1) assert (ad1._eval(pos1, wrt_variables=False).der2 == 0) assert (ad1._eval(pos1, wrt_variables=True).val == pos1) assert (ad1._eval(pos1, wrt_variables=True).der == 1) assert (ad1._eval(pos1, wrt_variables=True).der2 == 0) assert (ad2._eval(pos2, wrt_variables=False).val == pos2[0] + pos2[1]) assert (ad2._eval(pos2, wrt_variables=False).der == 2) assert (ad2._eval(pos2, wrt_variables=False).der2 == 0) assert (ad2._eval(pos2, wrt_variables=True).val == pos2[0] + pos2[1]) assert (all(ad2._eval(pos2, wrt_variables=True).der == [1, 1])) assert (all(ad2._eval(pos2, wrt_variables=True).der2 == [0, 0]))
def test_divide_add_simple(): alpha = 2 pos = 2 def f1(x): return alpha / x + 3 def f2(x): return 3 + alpha / x def f3(x): return x / alpha + 3 def f4(x): return 3 + x / alpha ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) ad3 = pydif.autodiff(f3) ad4 = pydif.autodiff(f4) assert (ad1.get_val(pos) == 4) assert (ad2.get_val(pos) == 4) assert (ad3.get_val(pos) == 4) assert (ad4.get_val(pos) == 4) assert (ad1.get_der(pos) == -0.5) assert (ad2.get_der(pos) == -0.5) assert (ad3.get_der(pos) == 0.5) assert (ad4.get_der(pos) == 0.5) assert (ad1.get_der(pos, order=2) == 0.5) assert (ad2.get_der(pos, order=2) == 0.5) assert (ad3.get_der(pos, order=2) == 0) assert (ad4.get_der(pos, order=2) == 0)
def test_composite(): pos = (1, 2, 3) def f1(x, y, z): return (1 / (x * y * z)) + el.sin((1 / x) + (1 / y) + (1 / z)) def f2(x, y, z): return (1 / (x * y * z)) ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) expected_val = (1 / 6) + np.sin(11 / 6) assert (ad1.get_val(pos) == expected_val) der1 = -(1 / 6) - np.cos(11 / 6) #d/dx der2 = -(1 / 12) - (np.cos(11 / 6) / 4) #d/dy der3 = -(1 / 18) - (np.cos(11 / 6) / 9) #d/dz assert (np.allclose(ad1.get_der(pos, wrt_variables=True), [der1, der2, der3])) assert (ad2.get_val(pos) == 1 / (1 * 2 * 3)) #http://www.wolframalpha.com/input/?i=d%2Fda+(1%2F(x(a)*y(a)*z(a)) expected_der = -((2 * 3 + 1 * 3 + 1 * 2) / ((1**2) * (2**2) * (3**2))) assert (np.isclose(float(ad2.get_der(pos)), expected_der)) der2_1 = 2 / (1 * 2 * 3) #d/dx^2 der2_2 = 2 / (1 * ((2)**3) * 3) #d/dy^2 der2_3 = 2 / (1 * 2 * ((3)**3)) #d/dz^2 assert (np.allclose(ad2.get_der(pos, wrt_variables=True, order=2), [der2_1, der2_2, der2_3]))
def test_multiply_add_simple(): alpha = 2 pos = 2 def f1(x): return alpha * x + 3 def f2(x): return x * alpha + 3 def f3(x): return 3 + x * alpha def f4(x): return 3 + alpha * x ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) ad3 = pydif.autodiff(f3) ad4 = pydif.autodiff(f4) assert (ad1.get_val(pos) == 7) assert (ad2.get_val(pos) == 7) assert (ad3.get_val(pos) == 7) assert (ad4.get_val(pos) == 7) assert (ad1.get_der(pos) == 2) assert (ad2.get_der(pos) == 2) assert (ad3.get_der(pos) == 2) assert (ad4.get_der(pos) == 2) assert (ad1.get_der(pos, order=2) == 0) assert (ad1.get_der(pos, order=2) == 0) assert (ad1.get_der(pos, order=2) == 0) assert (ad1.get_der(pos, order=2) == 0)
def test_init(): def f1(x): return x def f2(x, y): return x + y ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) assert (ad1.func == f1) assert (ad2.func == f2) assert (ad1.num_params == 1) assert (ad2.num_params == 2)
def BFGS(self, init_pos, max_iters=100, precision=10**-8, return_hist=False): #set original values coord = init_pos hist = [coord] #preallocate array #set inital conditions s = 0 iterations = 0 step = 10000 B = np.identity(self.num_params) dfdx = autodiff(self.func) #set conditions for while loop while ((iterations <= max_iters) and (step >= precision)): s = np.linalg.solve( B, -dfdx.get_der(coord, wrt_variables=True)) #step step = np.linalg.norm(s) #step size y = dfdx.get_der(coord + s, wrt_variables=True) - dfdx.get_der( coord, wrt_variables=True) #new y coord = coord + s #new coord B = B + self.delta_B(y, s, B) #get new B iterations += 1 hist.append(coord) hist = np.array(hist) if return_hist: return coord, hist else: return coord
def test_derorder(): def f1(x): return x ad1 = pydif.autodiff(f1) assert (ad1.get_der(2, order=1) == 1) assert (ad1.get_der(2, order=2) == 0) with pytest.raises(NotImplementedError): ad1.get_der(2, order=3)
def test_get_val(): def f1(x): return x def f2(x, y): return x, y ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) pos1 = 3 pos2 = [3, 4] dir1 = [1] dir2 = [0, 1] assert (ad1.get_val(pos1, direction=None) == pos1) assert (ad1.get_val(pos1, direction=dir1) == pos1) assert (ad2.get_val(pos2, direction=None) == pos2) assert (ad2.get_val(pos2, direction=dir2) == pos2[1])
def test_check_dim(): def f1(x): return x def f2(x, y): return x + y ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) with pytest.raises(ValueError): ad1._check_dim([0, 0]) ad1._check_dim([0]) ad1._check_dim(0) with pytest.raises(ValueError): ad2._check_dim([0]) with pytest.raises(ValueError): ad2._check_dim(0) ad2._check_dim([0, 0])
def test_get_der2(): def f1(x): return x def f2(x, y): return x, y ad1 = pydif.autodiff(f1) ad2 = pydif.autodiff(f2) pos1 = 3 pos2 = [3, 4] dir1 = [1] dir2 = [0, 1] assert (ad1.get_der(pos1, direction=None, order=2) == 0) assert (ad1.get_der(pos1, direction=dir1, order=2) == 0) assert (ad2.get_der(pos2, direction=None, order=2) == [0, 0]) assert (ad2.get_der(pos2, direction=dir2, order=2) == 0)
def test_enforce_unitvector(): def f1(x): return x dir1 = np.array([1]) dir2 = np.array([0.5]) dir3 = np.array([0, 1]) dir4 = np.array([1, -1]) dir5 = np.array([0, 0]) ad1 = pydif.autodiff(f1) assert (np.isclose(ad1._enforce_unitvector(dir1), np.array([1]))) assert (np.isclose(ad1._enforce_unitvector(dir2), np.array([1]))) assert (all(np.isclose(ad1._enforce_unitvector(dir3), np.array([0, 1])))) assert (all( np.isclose(ad1._enforce_unitvector(dir4), np.array([np.sqrt(1 / 2), -np.sqrt(1 / 2)])))) with pytest.raises(ValueError): ad1._enforce_unitvector(dir5)
def gradient_descent(self, init_pos, step_size=0.1, max_iters=100, precision=0.001, return_hist=False): num_params = len(signature(self.func).parameters) badDimentionsMsg = 'poorly formatted initial position. should be of length {}.'.format( num_params) if num_params != len(init_pos): raise ValueError(badDimentionsMsg) cur_pos = init_pos iters = 0 dfdx = autodiff(self.func) val = dfdx.get_val(init_pos) if isinstance(val, Iterable): raise ValueError( "The optimize class only optimizes scalar valued functions") # pre allocate history array hist = [cur_pos] prev_step_size = 100 + precision while (prev_step_size > precision and iters < max_iters): jac = dfdx.get_der(cur_pos, wrt_variables=True) prev_pos = cur_pos cur_pos = cur_pos - step_size * jac prev_step_size = np.linalg.norm(abs(cur_pos - prev_pos)) iters += 1 hist.append(cur_pos) #store history np.array(hist) if return_hist: return cur_pos, hist else: return cur_pos
def newton(self, init_pos, step_size=0.1, max_iters=100, precision=0.001, return_hist=False): num_params = len(signature(self.func).parameters) badDimentionsMsg = 'poorly formatted initial position. should be of length {}.'.format( num_params) if num_params != len(init_pos): raise ValueError(badDimentionsMsg) cur_pos = init_pos iters = 0 dfdx = autodiff(self.func) val = dfdx.get_val(init_pos) # if isinstance(val, Iterable): # raise ValueError("The optimize class only optimizes scalar valued functions") #preallocate arrays hist = [cur_pos] #set inital conditions iters = 0 s_k = 0 step = 10000 #define conditions to break loop while ((iters <= max_iters) and (np.linalg.norm(step) >= precision)): step = np.linalg.solve( dfdx.get_der(cur_pos, wrt_variables=True, order=1), -self.func(*cur_pos)) cur_pos = cur_pos + step iters += 1 hist.append(cur_pos) hist = np.array(hist) if return_hist: return cur_pos, hist else: return cur_pos
import numpy as np import sys import os sys.path.append(os.path.join(os.getcwd(), 'code', 'pydif')) from pydif.pydif import autodiff from pydif.elementary import elementary as el #adapted from lecture 9 slides from CS207 def f(x): return x - el.exp(-2.0 * el.sin(4.0 * x) * el.sin(4.0 * x)) dfdx = autodiff(f) # Start Newton algorithm xk = 1.0 # Initial guess tol = 1.0e-08 # Some tolerance max_it = 100 # Just stop if a root isn't found after 100 iterations root = None # Initialize root for k in range(max_it): delta_xk = -f(xk) / dfdx.get_der(xk, wrt_variables=True)[ 0] #there is only 1 partial derivative that we care about if (abs(delta_xk) <= tol): # Stop iteration if solution found root = xk + delta_xk print("Found root at x = {0:17.16f} after {1} iteratons.".format( root, k + 1)) break print("At iteration {0}, Delta x = {1:17.16f}".format(k + 1, delta_xk)) xk += delta_xk # Update xk