| |
| |
| """ |
| Author(s): Matthew Loper |
| |
| See LICENCE.txt for licensing and contact information. |
| """ |
|
|
| import numpy as np |
| import unittest |
|
|
| from .ch import Ch |
|
|
|
|
|
|
|
|
| class TestLinalg(unittest.TestCase): |
|
|
| def setUp(self): |
| np.random.seed(0) |
|
|
|
|
| def test_slogdet(self): |
| from . import ch |
| tmp = ch.random.randn(100).reshape((10,10)) |
| |
| |
|
|
| eps = 1e-10 |
| diff = np.random.rand(100) * eps |
| diff_reshaped = diff.reshape((10,10)) |
| gt = np.linalg.slogdet(tmp.r+diff_reshaped)[1] - np.linalg.slogdet(tmp.r)[1] |
| pred = ch.linalg.slogdet(tmp)[1].dr_wrt(tmp).dot(diff) |
| |
| |
| diff = gt - pred |
| |
| self.assertTrue(np.max(np.abs(diff)) < 1e-12) |
|
|
| sgn_gt = np.linalg.slogdet(tmp.r)[0] |
| sgn_pred = ch.linalg.slogdet(tmp)[0] |
|
|
| |
| |
| diff = sgn_gt - sgn_pred.r |
| self.assertTrue(np.max(np.abs(diff)) < 1e-12) |
| |
|
|
| def test_lstsq(self): |
| from .linalg import lstsq |
| |
| shapes = ([10, 3], [3, 10]) |
| |
| for shape in shapes: |
| for b2d in True, False: |
| A = (np.random.rand(np.prod(shape))-.5).reshape(shape) |
| if b2d: |
| b = np.random.randn(shape[0],2) |
| else: |
| b = np.random.randn(shape[0]) |
| |
| x1, residuals1, rank1, s1 = lstsq(A, b) |
| x2, residuals2, rank2, s2 = np.linalg.lstsq(A, b) |
| |
| |
| |
| |
| |
| self.assertTrue(np.max(np.abs(x1.r-x2)) < 1e-14) |
| if len(residuals2) > 0: |
| self.assertTrue(np.max(np.abs(residuals1.r-residuals2)) < 1e-14) |
| |
| |
| |
|
|
| def test_pinv(self): |
| from .linalg import Pinv |
| |
| data = (np.random.rand(12)-.5).reshape((3, 4)) |
| pc_tall = Pinv(data) |
| pc_wide = Pinv(data.T) |
| |
| pn_tall = np.linalg.pinv(data) |
| pn_wide = np.linalg.pinv(data.T) |
| |
| tall_correct = np.max(np.abs(pc_tall.r - pn_tall)) < 1e-12 |
| wide_correct = np.max(np.abs(pc_wide.r - pn_wide)) < 1e-12 |
| |
| |
| |
| |
| self.assertTrue(tall_correct) |
| self.assertTrue(wide_correct) |
| |
| return |
| |
| for pc in [pc_tall, pc_wide]: |
| |
| self.chkd(pc, pc.mtx) |
| import pdb; pdb.set_trace() |
| |
| |
|
|
| def test_svd(self): |
| from .linalg import Svd |
| eps = 1e-3 |
| idx = 10 |
|
|
| data = np.sin(np.arange(300)*100+10).reshape((-1,3)) |
| data[3,:] = data[3,:]*0+10 |
| data[:,1] *= 2 |
| data[:,2] *= 4 |
| data = data.copy() |
| u,s,v = np.linalg.svd(data, full_matrices=False) |
| data = Ch(data) |
| data2 = data.r.copy() |
| data2.ravel()[idx] += eps |
| u2,s2,v2 = np.linalg.svd(data2, full_matrices=False) |
|
|
|
|
| svdu, svdd, svdv = Svd(x=data) |
|
|
| |
| diff_emp = (s2-s) / eps |
| diff_pred = svdd.dr_wrt(data)[:,idx] |
| |
| |
| ratio = diff_emp / diff_pred |
| |
| self.assertTrue(np.max(np.abs(ratio - 1.)) < 1e-4) |
| |
| |
| diff_emp = (v2 - v) / eps |
| diff_pred = svdv.dr_wrt(data)[:,idx].reshape(diff_emp.shape) |
| ratio = diff_emp / diff_pred |
| |
| self.assertTrue(np.max(np.abs(ratio - 1.)) < 1e-2) |
|
|
| |
| diff_emp = (u2 - u) / eps |
| diff_pred = svdu.dr_wrt(data)[:,idx].reshape(diff_emp.shape) |
| ratio = diff_emp / diff_pred |
| |
| self.assertTrue(np.max(np.abs(ratio - 1.)) < 1e-2) |
| |
| |
| def test_det(self): |
| from .linalg import Det |
| |
| mtx1 = Ch(np.sin(2**np.arange(9)).reshape((3,3))) |
| mtx1_det = Det(mtx1) |
| dr = mtx1_det.dr_wrt(mtx1) |
|
|
| eps = 1e-5 |
| mtx2 = mtx1.r.copy() |
| input_diff = np.sin(np.arange(mtx2.size)).reshape(mtx2.shape) * eps |
| mtx2 += input_diff |
| mtx2_det = Det(mtx2) |
|
|
| output_diff_emp = (np.linalg.det(mtx2) - np.linalg.det(mtx1.r)).ravel() |
| |
| output_diff_pred = Det(mtx1).dr_wrt(mtx1).dot(input_diff.ravel()) |
|
|
| |
| |
|
|
| self.assertTrue(np.max(np.abs(output_diff_emp - output_diff_pred)) < eps*1e-4) |
| self.assertTrue(np.max(np.abs(mtx1_det.r - np.linalg.det(mtx1.r)).ravel()) == 0) |
| |
| |
| |
| def test_inv1(self): |
| from .linalg import Inv |
|
|
| mtx1 = Ch(np.sin(2**np.arange(9)).reshape((3,3))) |
| mtx1_inv = Inv(mtx1) |
| dr = mtx1_inv.dr_wrt(mtx1) |
|
|
| eps = 1e-5 |
| mtx2 = mtx1.r.copy() |
| input_diff = np.sin(np.arange(mtx2.size)).reshape(mtx2.shape) * eps |
| mtx2 += input_diff |
| mtx2_inv = Inv(mtx2) |
|
|
| output_diff_emp = (np.linalg.inv(mtx2) - np.linalg.inv(mtx1.r)).ravel() |
| output_diff_pred = Inv(mtx1).dr_wrt(mtx1).dot(input_diff.ravel()) |
|
|
| |
| |
|
|
| self.assertTrue(np.max(np.abs(output_diff_emp - output_diff_pred)) < eps*1e-4) |
| self.assertTrue(np.max(np.abs(mtx1_inv.r - np.linalg.inv(mtx1.r)).ravel()) == 0) |
|
|
| def test_inv2(self): |
| from .linalg import Inv |
| |
| eps = 1e-8 |
| idx = 13 |
|
|
| mtx1 = np.random.rand(100).reshape((10,10)) |
| mtx2 = mtx1.copy() |
| mtx2.ravel()[idx] += eps |
| |
| diff_emp = (np.linalg.inv(mtx2) - np.linalg.inv(mtx1)) / eps |
| |
| mtx1 = Ch(mtx1) |
| diff_pred = Inv(mtx1).dr_wrt(mtx1)[:,13].reshape(diff_emp.shape) |
| |
| |
| |
| self.assertTrue(np.max(np.abs(diff_pred.ravel()-diff_emp.ravel())) < 1e-4) |
| |
| @unittest.skipIf(np.__version__ < '1.8', |
| "broadcasting for matrix inverse not supported in numpy < 1.8") |
| def test_inv3(self): |
| """Test linalg.inv with broadcasting support.""" |
| |
| from .linalg import Inv |
|
|
| mtx1 = Ch(np.sin(2**np.arange(12)).reshape((3,2,2))) |
| mtx1_inv = Inv(mtx1) |
| dr = mtx1_inv.dr_wrt(mtx1) |
|
|
| eps = 1e-5 |
| mtx2 = mtx1.r.copy() |
| input_diff = np.sin(np.arange(mtx2.size)).reshape(mtx2.shape) * eps |
| mtx2 += input_diff |
| mtx2_inv = Inv(mtx2) |
|
|
| output_diff_emp = (np.linalg.inv(mtx2) - np.linalg.inv(mtx1.r)).ravel() |
| output_diff_pred = Inv(mtx1).dr_wrt(mtx1).dot(input_diff.ravel()) |
|
|
| |
| |
|
|
| self.assertTrue(np.max(np.abs(output_diff_emp.ravel() - output_diff_pred.ravel())) < eps*1e-3) |
| self.assertTrue(np.max(np.abs(mtx1_inv.r - np.linalg.inv(mtx1.r)).ravel()) == 0) |
|
|
| def chkd(self, obj, parm, eps=1e-14): |
| backed_up = parm.x |
|
|
| if True: |
| diff = (np.random.rand(parm.size)-.5).reshape(parm.shape) |
| else: |
| diff = np.zeros(parm.shape) |
| diff.ravel()[4] = 2. |
|
|
| dr = obj.dr_wrt(parm) |
|
|
| parm.x = backed_up - diff*eps |
| r_lower = obj.r |
|
|
| parm.x = backed_up + diff*eps |
| r_upper = obj.r |
|
|
| diff_emp = (r_upper - r_lower) / (eps*2.) |
| diff_pred = dr.dot(diff.ravel()).reshape(diff_emp.shape) |
|
|
| |
| |
| print(diff_emp / diff_pred) |
| print(diff_emp - diff_pred) |
|
|
| parm.x = backed_up |
|
|
| |
|
|
| suite = unittest.TestLoader().loadTestsFromTestCase(TestLinalg) |
|
|
| if __name__ == '__main__': |
| unittest.main() |
|
|
|
|