def test_pow3(): x = X(2, 'x') y = X(2, 'y') f = (5 * x)**(2 * y) assert f.val == [10000] assert f.der['x'] == [20000] assert f.der['y'] == [20000 * np.log(10)]
def test_add2(): x = X(2, 'x') y = X(3, 'y') f = (5 * x) + (8 * y) assert f.val == [34] assert f.der['x'] == [5] assert f.der['y'] == [8]
def test_mul2(): x = X(4, 'x') y = X(5, 'y') f = (2 * x) * (3 * y) assert f.val == [120] assert f.der['x'] == [30] assert f.der['y'] == [24]
def test_multiple_variables_and_values(): # f(x, y) = 2xy^2, evaluate at f(8, 9) and f(4, 12) x = X([8, 4], 'x') y = X([9, 12], 'y') f_xy = 2 * x * (y**2) assert f_xy.val == [1296, 1152] assert f_xy.der['x'] == [162, 288] assert f_xy.der['y'] == [288, 192]
def test_multiple_variables(): # f(x, y) = x^2 * y^3, evaluate at f(3, 4) x = X(3, 'x') y = X(4, 'y') f_xy = (x**2) * (y**3) assert f_xy.val == [576] assert f_xy.der['x'] == [384] assert f_xy.der['y'] == [432]
def test_cal_gradient_2d(): def foo(x, y): fx = x**2 + y**2 return fx.val, fx.der p = GD(max_iter=10000, step_size=0.01, precision=0.0001) x = X(10, 'x') y = X(10, 'y') val = p.cal_gradient_2d(foo, x, y) assert (abs(0 - val[0][0]) < 0.01) assert (abs(0 - val[1][0]) < 0.01)
def test_scalar_jacobian(): # This is basically just calculating the gradient of f(x, y) = x^2 * y^2 # since the Jacobian for a scalar function is the gradient. x = X(3, 'x') y = X(4, 'y') fx = x * x * y * y allVars, jacs = fx.jacobian() assert 'x' in allVars assert 'y' in allVars xIdx = allVars.index('x') yIdx = allVars.index('y') jac = jacs[0] assert jac[0, xIdx] == 96 assert jac[0, yIdx] == 72
def test_cal_gradient_nd(): def foo(vars): fx = vars[0]**2 + vars[1]**2 + vars[2]**2 + vars[3]**2 return fx.val, fx.der x = X(10, 'x') y = X(10, 'y') z = X(10, 'z') a = X(10, 'a') p = GD(max_iter=10000, step_size=0.01, precision=0.0001) val = p.cal_gradient_nd(foo, [x, y, z, a]) assert (abs(0 - val[0][0]) < 0.01) assert (abs(0 - val[1][0]) < 0.01) assert (abs(0 - val[2][0]) < 0.01) assert (abs(0 - val[3][0]) < 0.01)
def test_vector1(): xV, yV = 2, 3 x, y = X(xV, 'x'), X(yV, 'y') f1, f2 = 2 * (x**2) * y, 3 * (x**2) + (y**3) v = Vector([f1, f2]) assert v.val[0][0, 0] == 2 * (xV**2) * yV assert v.val[0][1, 0] == 3 * (xV**2) + (yV**3) allVars, jac = v.jacobian() jac = jac[0] xIdx = allVars.index('x') yIdx = allVars.index('y') assert jac[0, xIdx] == 4 * xV * yV assert jac[0, yIdx] == 2 * (xV**2) assert jac[1, xIdx] == 6 * xV assert jac[1, yIdx] == 3 * (yV**2)
def test_vector2(): xV, yV = 2, 3 x, y = X(xV, 'x'), X(yV, 'y') f1, f2 = (x**2) + (2 * x) + 3, 3 * (y**2) + (4 * y) + 8 v = Vector([f1, f2]) assert v.val[0][0, 0] == (xV**2) + (2 * xV) + 3 assert v.val[0][1, 0] == 3 * (yV**2) + (4 * yV) + 8 allVars, jac = v.jacobian() jac = jac[0] xIdx = allVars.index('x') yIdx = allVars.index('y') assert jac[0, xIdx] == 2 * xV + 2 assert jac[0, yIdx] == 0 assert jac[1, xIdx] == 0 assert jac[1, yIdx] == 6 * yV + 4
def test_cal_gradient_1d(): def foo(x): fx = x**2 + x return fx.val, fx.der p = GD(max_iter=10000, step_size=0.001, precision=0.0000001) x = X(0) val = p.cal_gradient_1d(foo, x) assert (abs(-0.5 - val) < 0.01)
def cal_gradient_2d(self, f, x0, y0): next_x = x0.val[0] next_y = y0.val[0] next_val = np.array([[next_x], [next_y]]) for _ in range(self.max_iter): cur_val = next_val cur_x = float(cur_val[0][0]) cur_y = float(cur_val[1][0]) x = X(cur_x, 'x') y = X(cur_y, 'y') val, der = f(x, y) self.obj.append(val[0]) der_vec = dic_to_vec(der) next_val = cur_val - self.step_size * der_vec if np.linalg.norm(cur_val - next_val) <= self.precision: break return next_val
def cal_gradient_1d(self, f, x0): next_x = x0.val[0] for _ in range(self.max_iter): cur_x = next_x x = X(cur_x) val, der = f(x) self.obj.append(val[0]) next_x = cur_x - self.step_size * der['x'][0] if abs(cur_x - next_x) <= self.precision: break return next_x
def test_vector_operators(): x1 = X(3) v1 = Vector([x1]) x2 = X(4) v2 = Vector([x2]) assert v1 < v2 assert v1 <= v2 assert not v1 > v2 assert not v1 >= v2 assert v1 > 2 assert v1 >= 2 assert v1 < 4 assert v1 <= 4 assert v1 == v1 assert v1 != v2 x3 = X(5, 'x3') v3 = Vector([x1, x3]) assert v1 != v3
def test_newton1(): f1 = lambda x: Sin(x[0]) f = [f1] init_x = [1.0] n = Newton(f, init_x) x = X(n[0]) f11= Sin(x) assert f11.val[0] < 1e-8
def cal_gradient_nd(self, f, args): next_val = [] for arg in args: next_val.append(arg.val[0]) next_val = np.expand_dims(next_val, axis=0).T for _ in range(self.max_iter): cur_val = next_val var_list = [float(num[0]) for num in cur_val] input_list = [X(var_list[i], str(i)) for i in range(len(var_list))] val, der = f(input_list) self.obj.append(val[0]) der_vec = dic_to_vec(der) next_val = cur_val - self.step_size * der_vec if np.linalg.norm(cur_val - next_val) <= self.precision: break return next_val
def bgfs(f, init_x, accuracy=1e-8, alphas=[ .00001, .00005, .0001, .0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5 ], max_iter=1000, verbose=False): x_current = [X(init_x[i], 'x' + str(i)) for i in range(len(init_x))] B = np.eye(len(init_x)) for i_iter in range(max_iter): func = f(x_current) f_jac = func.jacobian()[1][0].T p = -np.linalg.pinv(B) @ f_jac f_minmin = 10**13 alpha_minmin = .00001 for alpha in alphas: f_min = f([ x_current[i] + alpha * p[i, 0] for i in range(len(x_current)) ]) if f_min.val[0] < f_minmin: f_minmin = f_min.val[0] alpha_minmin = alpha if math.isnan(float(p[0])): print( "It doesn't converge using bgfs! Please use some other methods or check if a maximum/minimum exists!" ) return [x_current[i].val[0] for i in range(len(x_current))] s = alpha_minmin * p if np.linalg.norm(s) <= accuracy: print( 'Since the shifted distance is smaller than {}, we stop the loop at {}th iteration.' .format(accuracy, i_iter)) break x_current = [ x_current[i] + alpha_minmin * p[i, 0] for i in range(len(x_current)) ] if verbose: print('At {}th iteration, current x value is: '.format(i_iter), [x_current[i].val[0] for i in range(len(x_current))], ', the step taken is: ', s, '.\n') y_current = f(x_current).jacobian()[1][0].T - f_jac B += y_current.dot(y_current.T) / (y_current.T.dot(s)) - B.dot(s).dot( s.T).dot(B.T) / (s.T.dot(B).dot(s)) final_del = [x_current[i].val[0] for i in range(len(x_current))] if i_iter == max_iter - 1: print( "Notice that the change in distance of x is still larger than input accuracy! It probably doesn't converge using bgfs! " ) if verbose: print('The final value we get is', final_del, '.') return final_del
from superdifferentiator.forward.functions import X, Log, Sin, Cos, Tan from superdifferentiator.forward.Vector import Vector x = X(3) sx = Sin(x) cx = Cos(x) fx = sx + cx fx = 3 + Cos(x) fx = Tan(x) + 3 ''' x = X(3, 'x') y = X(4, 'y') fx = x * x * y * y allVars, jacs = fx.jacobian() print('f(x, y) = x^2 * y^2 for f(3, 4)') print(allVars) print(jacs[0]) print() xV = [3, 5] x = X(xV) f1 = (x ** 2) + (2 * x) + 3 f2 = (2 ** x) v = Vector([f1, f2]) vals = v.val allVars, jacs = v.jacobian() print('g(x) = x^2 + 2x + 3 for x = 3, 5 =', f1.val) print('h(x) = 2^x for x = 3, 5 =', f2.val)
def rpow_invalid(): x = X(2) f = 'hello'**x
def test_create_cos(): x = X(2) x1 = Cos(x) assert x1.val == [np.cos(2)] assert x1.der['x'] == [-np.sin(2)]
def rdiv_invalid(): x = X(2) f = 'hello' / x
def div_invalid(): x = X(2) f = x / 'hello'
def rsub_invalid(): x = X(2) f = 'hello' - x
def mul_invalid(): x = X(2) f = x * 'hello'
def test_create_tan(): x = X(2) x1 = Tan(x) assert x1.val == [np.tan(2)] assert x1.der['x'] == [1 / np.cos(2)**2]
def test_create_sin(): x = X(2) x1 = Sin(x) assert x1.val == [np.sin(2)] assert x1.der['x'] == [np.cos(2)]
def add_invalid(): x = X(2) f = x + 'hello'
def pow_invalid(): x = X(2) f = x**'hello'
def sub_invalid(): x = X(2) f = x - 'hello'
def test_neq(): x1 = X(3) x2 = X(4) assert x1 != x2