def test_abs(): x = VAD([-1, 2, 3]) f = abs(x) print(f.der) print(f.der2) assert np.sum(f.val == np.array( [[1], [2], [3]])) == 3, "Error: abs didn't apply properly on VAD." assert np.sum( f.der == np.array([[-1., 0., 0.], [0., 1., 0.], [0., 0., 1.] ])) == 9, "Error: der1 for abs(VAD) is not correct." x = AD.AD(-1, tag=0) f = abs(x) assert f.val == 1, "Error: abs didn't apply properly on AD." assert f.der == -1, "Error: der1 for abs(AD) is not correct." assert abs(-5) == 5, "Error: abs didn't apply properly on numbers." x = AD.AD(0, tag=0) with pytest.raises(Exception): f = abs(x) with pytest.raises(TypeError): f = admath.abs('error') xv = AD.AD(-2, tag=0, order=3) f = admath.abs(xv) assert f.higherdiff(3) == 0, "Error: abs didn't apply on higher properly" [x] = VAD([-5], order=3) f = abs(x) print(f.der) print(f.der2) print(f.higher)
def test_AD_init_hw(): with pytest.raises(TypeError): x = ad.AD(-1, tag=0, size=1.5) x = ad.AD(-1, tag=0, order=1.5) x = ad.AD(-1, tag=0, order='error') x = VAD([-1], order='error') with pytest.raises(ValueError): x = ad.AD(-1, order=0) with pytest.raises(Exception): x = VAD([1, 2, 3], order=5) x = ad.AD([1, 2, 3], order=5)
def __init__(self, val, der=None, der2=None, order=2, higher=None): """ Overwrites the __init__ dunder method to create a new VAD object with initial value and derivatives. Parameters: val (int or float or list or np.array): the initial value of the new VAD object. der (int or float or list or np.array): first-order derivatives of the new AD object. der2 (int or float or list or np.array): second-order derivatives of the new AD object. Returns: None, but initializes AD object(s) when called Example: >>> x, y = VAD([1,2]) >>> x AD(value: [1], derivatives: [1., 0.]) >>> fs = VAD([1,2]) >>> fs VAD(value: [1 2], derivatives: [[1. 0.] [0. 1.]]) """ self.val = np.array(val) if der is None: self.der = np.eye(len(self)) self.der2 = np.zeros((len(self),len(self),len(self))) else: self.der = der self.der2 = der2 self.tag = np.array([i for i in range(len(self))]) self.size = len(self) if not isinstance(order, numbers.Integral): raise TypeError("Highest order of derivatives must be a positive integer.") elif order < 1: raise ValueError("Highest order of derivatives must be at least 1.") elif order > 2 and self.size > 1: raise Exception("We cannot handle derivatives of order > 2 for more than one scalar variables.") self.order = order self.higher = higher if self.size > 1: arr_ad = np.array([None]*len(self)) for i in range(len(self)): arr_ad[i] = ad.AD(val=self.val[i], tag=self.tag[i], size = self.size, der=self.der[i], der2=self.der2[i]) self.variables = arr_ad else: arr_ad = np.array([None]*len(self)) arr_ad[0] = ad.AD(val=self.val[0], tag=self.tag[0], size = 1, der=self.der[0], der2=self.der2[0], order=self.order, higher = self.higher) self.variables = arr_ad
def test_AD_pow_hw(): x = ad.AD(val=1, order=10, size=1, tag=0) f = x**5 assert np.abs(f.val - 1) < 1e-8, "rpow not working for AD" x = ad.AD(val=0, order=10, size=1, tag=0) with pytest.raises(ValueError): f = x**5 f = x**2 with pytest.raises(TypeError): f = x**'a'
def test_higher_hw(): x = ad.AD(val=1, order=10, size=1, tag=0) f = x**5 assert f.higherdiff(1) == 5, "higherdiff not working" with pytest.raises(TypeError): f.higherdiff('error') with pytest.raises(ValueError): f.higherdiff(0) f.higherdiff(15) with pytest.raises(Exception): x = ad.AD(val=1, size=1, tag=0) f = x**5 f.higherdiff(10)
def test_log(): x = AD.AD(1, tag=0, order=5) f = log(x) assert f.val[0] == np.log(1), "Error: log didn't apply properly on AD." assert np.allclose(f.der, 1), "Error: der1 for log(AD) is not correct." assert np.allclose(f.der2, -1), "Error: der2 for log(AD) is not correct." higherarr = np.array([1, -1, 2, -6, 24]) assert np.allclose( f.higher, higherarr), "Error: higherder for log(AD) is not correct." y = VAD([1, 2, 3]) g = log(y) assert np.allclose(g.val, np.log([1, 2, 3])), "Error: log didn't apply properly on VAD." dertest = np.zeros((3, 3)) dertest[0, 0] = 1 dertest[1, 1] = 1 / 2 dertest[2, 2] = 1 / 3 assert np.allclose(g.der, dertest), "Error: der1 for log(VAD) is not correct." der2test = np.zeros((3, 3, 3)) der2test[0, 0, 0] = -1**-2 der2test[1, 1, 1] = -2**-2 der2test[2, 2, 2] = -3**-2 assert np.allclose(g.der2, der2test), "Error: der2 for log(VAD) is not correct." assert log(5) == np.log(5), "Error: log didn't apply properly on number." with pytest.raises(TypeError): f = admath.log('error') x, y = VAD([2, 3]) p = log(x, base=y) assert np.allclose(p.val[0], np.log(2) / np.log(3))
def test_exp(): x = AD.AD(1, tag=0, order=5) f = exp(x) assert f.val[0] == np.exp(1), "Error: exp didn't apply properly on AD." assert np.allclose(f.der, np.exp(1)), "Error: der1 for exp(AD) is not correct." assert np.allclose(f.der2, np.exp(1)), "Error: der2 for exp(AD) is not correct." higherarr = np.array( [np.exp(1), np.exp(1), np.exp(1), np.exp(1), np.exp(1)]) assert np.allclose( f.higher, higherarr), "Error: higherder for exp(AD) is not correct." y = VAD([1, 2, 3]) g = exp(y) assert np.allclose(g.val, np.exp([1, 2, 3])), "Error: exp didn't apply properly on VAD." dertest = np.zeros((3, 3)) dertest[0, 0] = np.exp(1) dertest[1, 1] = np.exp(2) dertest[2, 2] = np.exp(3) assert np.allclose(g.der, dertest), "Error: der1 for exp(VAD) is not correct." der2test = np.zeros((3, 3, 3)) der2test[0, 0, 0] = np.exp(1) der2test[1, 1, 1] = np.exp(2) der2test[2, 2, 2] = np.exp(3) assert np.allclose(g.der2, der2test), "Error: der2 for exp(VAD) is not correct." assert exp(5) == np.exp(5), "Error: exp didn't apply properly on number." with pytest.raises(TypeError): f = admath.exp('error')
def test_sqrt(): x = AD.AD(2, tag=0, order=3) f = sqrt(x) assert f.val[0] == np.sqrt(2), "Error: sqrt didn't apply properly on AD." assert np.allclose(f.der, 0.5 * 1 / np.sqrt(2)), "Error: der1 for sqrt(AD) is not correct." assert np.allclose(f.der2, -0.25 / 2 / np.sqrt(2)), "Error: der2 for sqrt(AD) is not correct." assert np.abs(f.higherdiff(3) - 3 / 32 / np.sqrt(2) ) < 1e-8, "Error: higherder for sqrt(AD) is not correct." y = VAD([1, 2]) g = sqrt(y) assert np.allclose(g.val, np.sqrt( [1, 2])), "Error: sqrt didn't apply properly on VAD." dertest = np.zeros((2, 2)) dertest[0, 0] = 0.5 dertest[1, 1] = 0.5 * 1 / np.sqrt(2) assert np.allclose(g.der, dertest), "Error: der1 for sqrt(VAD) is not correct." der2test = np.zeros((2, 2, 2)) der2test[0, 0, 0] = -0.25 der2test[1, 1, 1] = -0.25 / 2 / np.sqrt(2) assert np.allclose(g.der2, der2test), "Error: der2 for sqrt(VAD) is not correct." assert sqrt(5) == np.sqrt( 5), "Error: sqrt didn't apply properly on number." with pytest.raises(TypeError): f = admath.sqrt('error')
def test_AD_ueq_hw(): x = ad.AD([1], tag=0, der=[1], order=5) y = 2 * x assert x != y, "Error: ne not working for AD" assert x < y, "Error: ne not working for AD" assert y > x, "Error: ne not working for AD" assert x <= y, "Error: ne not working for AD" assert y >= x, "Error: ne not working for AD"
def test_chain_rule(): x = AD.AD(2, order=5) newad = 5 * x**3 + 2 higherde = np.array([60, 60, 30, 0, 0]) adres = admath.chain_rule(x, 42, 60, 60, higher_der=higherde) assert newad == adres, "Error: chain rule doesn't apply to AD object properly." assert np.allclose( newad.higher, adres.higher ), "Error: chain rule doesn't carry higher derivatives properly."
def chain_rule(ad, new_val, der, der2, higher_der=None): """ Applies chain rule to returns a new AD object with correct value and derivatives. Parameters: ad (AD): An AD object new_val (float): Value of the new AD object der (float): Derivative of the outer function in chain rule Returns: new_ad (AD): a new AD object with correct value and derivatives Example: >>> import AD as AD >>> x = AD.AD(2,order=5) >>> newad = 5*x**3+2 >>> higherde = np.array([60,60,30,0,0]) >>> chain_rule(x, 42, 60, 60, higher_der=higherde) AD(value: [42], derivatives: [60.]) """ new_der = der * ad.der new_der2 = der * ad.der2 + der2 * np.matmul( np.array([ad.der]).T, np.array([ad.der])) if ad.higher is None: new_ad = AD.AD(new_val, tag=ad.tag, der=new_der, der2=new_der2) else: new_higher_der = np.array([0.0] * len(ad.higher)) new_higher_der[0] = new_der new_higher_der[1] = new_der2 for i in range(2, len(ad.higher)): n = i + 1 sum = 0 for k in range(1, n + 1): sum += higher_der[k - 1] * sp.bell(n, k, ad.higher[0:n - k + 1]) new_higher_der[i] = sum new_ad = AD.AD(new_val, tag=ad.tag, der=new_der, der2=new_der2, order=len(ad.higher)) new_ad.higher = new_higher_der return new_ad
def test_AD_eq_hw(): x = ad.AD([1], tag=0, der=[1], order=5) y = VAD([1]) with pytest.raises(TypeError): x == y x.fullequal(y) x < y x > y x <= y x >= y y = VAD([1]) y = 0 with pytest.raises(TypeError): x == y x.fullequal(y) x < y x > y x <= y x >= y
def test_AD_rpow_hw(): x = ad.AD(val=1, order=10, size=1, tag=0) f = 5**x assert np.abs(f.val - 5) < 1e-8, "rpow not working for AD"
def test_set_VAD(): x = ad.AD(1, tag=0, size=2) y = ad.AD(2, tag=1, size=2) ADs = np.array([x, y]) assert set_VAD(ADs) == VAD([1, 2]), "Error: set_VAD is wrong."
def test_AD_add_hw(): x = ad.AD([1], tag=0, der=[1], order=5) y = ad.AD([1], tag=0, der=[1], order=7) f = x + x with pytest.raises(Exception): f = x + y
def test_AD_ne_hw(): x = ad.AD([1], tag=0, der=[1], order=5) assert not x != x, "Error: ne not working for AD"
def test_AD_repr_hw(): x = ad.AD([1], tag=0, der=[1], order=5) assert x.__repr__( ) == 'AD(value: [[1]], derivatives: [1.])', "Error: repr is not working" assert x.__str__( ) == 'AD(value: [[1]], derivatives: [1.])', "Error: str is not working"