PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/python/dcgeig/tests/test_solvers.py

https://gitlab.com/christoph-conrads/DCGeig
Python | 486 lines | 297 code | 180 blank | 9 comment | 30 complexity | 3816501dd637a747170daab425978795 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. # Copyright 2015-2016 Christoph Conrads
  4. #
  5. # This Source Code Form is subject to the terms of the Mozilla Public
  6. # License, v. 2.0. If a copy of the MPL was not distributed with this
  7. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. import unittest
  9. import ctypes
  10. import numpy as NP
  11. import numpy.linalg as NL
  12. import numpy.matlib as M
  13. import numpy.random as R
  14. import dcgeig.solvers as gep_solvers
  15. from dcgeig.error_analysis import compute_backward_error
  16. import dcgeig.utils as U
  17. def check_return_values(self, dtype, d, X):
  18. self.assertEqual( type(X), M.matrix )
  19. self.assertEqual( X.dtype, dtype )
  20. self.assertEqual( type(d), NP.ndarray )
  21. self.assertEqual( d.dtype, dtype )
  22. self.assertEqual( d.size, X.shape[1] )
  23. def rotate_matrix(A):
  24. assert U.is_hermitian(A)
  25. dtype = A.dtype
  26. n = len(A)
  27. r = R.RandomState(seed=0)
  28. B = r.uniform(low=-1, high=+1, size=[n,n])
  29. Q, _ = NL.qr(B)
  30. Q = M.matrix( Q.astype(dtype) )
  31. QAQH = U.force_hermiticity( Q * A * Q.H )
  32. return QAQH
  33. def test_simple(self, f):
  34. n = 4;
  35. for dtype in self.dtypes:
  36. I = M.eye(n, dtype=dtype)
  37. d, X = f(I, I)
  38. check_return_values(self, dtype, d, X)
  39. eta = compute_backward_error(I, I, d, X)
  40. epsilon = NP.finfo(dtype).eps
  41. self.assertTrue( NP.all(eta <= n * epsilon) )
  42. def test_random(self, f, reltol=1):
  43. n = 8;
  44. for dtype in self.dtypes:
  45. r = R.RandomState(seed=0)
  46. for i in range(16):
  47. L_A = M.matrix( r.random_sample([n,n]), dtype=dtype )
  48. L_B = M.matrix( r.random_sample([n,n]), dtype=dtype )
  49. A = U.force_hermiticity(L_A * L_A.H)
  50. B = U.force_hermiticity(L_B * L_B.H)
  51. d, X = f(A, B)
  52. check_return_values(self, dtype, d, X)
  53. eta = compute_backward_error(A, B, d, X)
  54. epsilon = NP.finfo(dtype).eps
  55. self.assertTrue( NP.all(eta <= reltol * n * epsilon) )
  56. def test_random_singular(self, f, reltol=1):
  57. n = 8;
  58. for dtype in self.dtypes:
  59. r = R.RandomState(seed=0)
  60. for i in range(16):
  61. L_A = M.matrix( NP.tril(r.random_sample([n,n])), dtype=dtype )
  62. L_B = M.matrix( NP.tril(r.random_sample([n,n])), dtype=dtype )
  63. L_A[0,0] = 0
  64. L_B[-1,-1] = 0
  65. A = U.force_hermiticity(L_A * L_A.H)
  66. B = U.force_hermiticity(L_B * L_B.H)
  67. d, X = f(A, B)
  68. check_return_values(self, dtype, d, X)
  69. eta = compute_backward_error(A, B, d, X)
  70. epsilon = NP.finfo(dtype).eps
  71. self.assertTrue( NP.all(eta <= reltol * n * epsilon) )
  72. def test_checks(self, f):
  73. n = 4
  74. with self.assertRaises(ValueError):
  75. f( M.eye(n, dtype=NP.float32), M.eye(n, dtype=NP.float64) )
  76. with self.assertRaises(ValueError):
  77. f( M.eye(n, dtype=NP.float64), M.eye(n, dtype=NP.float32) )
  78. for dtype in self.dtypes:
  79. I = M.eye(n, dtype=dtype)
  80. with self.assertRaises(ValueError):
  81. Z = M.eye(0, dtype=dtype)
  82. d, X = f(Z, Z)
  83. with self.assertRaises(TypeError):
  84. I = M.eye(n, dtype=dtype)
  85. A = NP.eye(n, dtype=dtype)
  86. d, X = f(I, A)
  87. with self.assertRaises(TypeError):
  88. I = M.eye(n, dtype=dtype)
  89. A = NP.eye(n, dtype=dtype)
  90. d, X = f(A, I)
  91. with self.assertRaises(ValueError):
  92. J = M.eye(2*n, dtype=dtype)
  93. d, X = f(I, J)
  94. with self.assertRaises(ValueError):
  95. J = M.eye(2*n, dtype=dtype)
  96. d, X = f(J, I)
  97. with self.assertRaises(ValueError):
  98. A = M.matrix(range(n*n)).reshape([n,n])
  99. d, X = f(A, I)
  100. with self.assertRaises(ValueError):
  101. A = M.matrix(range(n*n)).reshape([n,n])
  102. d, X = f(I, A)
  103. def test_small_dimensions(self, f):
  104. for dtype in self.dtypes:
  105. for n in [1,2,3]:
  106. A = dtype(NP.pi) * M.eye(n, dtype=dtype)
  107. B = dtype(NP.e) * M.eye(n, dtype=dtype)
  108. d, X = f(A, B)
  109. check_return_values(self, dtype, d, X)
  110. eta = compute_backward_error(A, B, d, X)
  111. epsilon = NP.finfo(dtype).eps
  112. self.assertTrue( NP.all(eta <= 2*n * epsilon) )
  113. def test_singular_matrix_2by2(self, f):
  114. n = 2
  115. for dtype in self.dtypes:
  116. epsilon = NP.finfo(dtype).eps
  117. F = rotate_matrix( M.eye(n, dtype=dtype) )
  118. S = rotate_matrix( M.matrix(NP.diag([1,0]), dtype=dtype) )
  119. d, X = f(F, S)
  120. check_return_values(self, dtype, d, X)
  121. eta = compute_backward_error(F, S, d, X)
  122. self.assertTrue( NP.all(eta <= M.sqrt(2) * n * epsilon) )
  123. d, X = f(S, F)
  124. check_return_values(self, dtype, d, X)
  125. eta = compute_backward_error(S, F, d, X)
  126. self.assertTrue( NP.all(eta <= M.sqrt(2) * n * epsilon) )
  127. def test_singular_matrix_3by3(self, f):
  128. n = 3
  129. for dtype in self.dtypes:
  130. epsilon = NP.finfo(dtype).eps
  131. A = M.eye(n, dtype=dtype)
  132. B = M.eye(n, dtype=dtype)
  133. A[0,0] = 0
  134. B[1,1] = 0
  135. A[2,2] = 0
  136. B[2,2] = 0
  137. A = rotate_matrix(A)
  138. B = rotate_matrix(B)
  139. d, X = f(A, B)
  140. check_return_values(self, dtype, d, X)
  141. eta = compute_backward_error(A, B, d, X)
  142. self.assertTrue( NP.all(eta <= M.sqrt(2) * n * epsilon) )
  143. def test_zero_matrix(self, f):
  144. n = 4;
  145. for dtype in self.dtypes:
  146. epsilon = NP.finfo(dtype).eps
  147. A = M.eye(n, dtype=dtype)
  148. B = M.zeros([n,n], dtype=dtype)
  149. d, X = f(A, B)
  150. check_return_values(self, dtype, d, X)
  151. eta = compute_backward_error(A, B, d, X)
  152. self.assertTrue( NP.all(eta <= n * epsilon) )
  153. d, X = f(B, A)
  154. check_return_values(self, dtype, d, X)
  155. eta = compute_backward_error(B, A, d, X)
  156. self.assertTrue( NP.all(eta <= n * epsilon) )
  157. class Test_solve_with_qr_csd(unittest.TestCase):
  158. dtypes = [NP.float32, NP.float64]
  159. solver = gep_solvers.qr_csd
  160. def setUp(self):
  161. self.numpy_warnings = NP.seterr(invalid='ignore')
  162. def tearDown(self):
  163. NP.seterr(**self.numpy_warnings)
  164. def test_simple(self):
  165. test_simple(self, self.solver)
  166. def test_random(self):
  167. test_random(self, self.solver, NP.sqrt(2))
  168. def test_random_singular(self):
  169. test_random_singular(self, self.solver, 2)
  170. def test_checks(self):
  171. test_checks(self, self.solver)
  172. def test_small_dimensions(self):
  173. test_small_dimensions(self, self.solver)
  174. def test_singular_matrix_2by2(self):
  175. test_singular_matrix_2by2(self, self.solver)
  176. def test_singular_matrix_3by3(self):
  177. test_singular_matrix_3by3(self, self.solver)
  178. def test_zero_matrix(self):
  179. test_zero_matrix(self, self.solver)
  180. def test_workspace_query(self):
  181. for n in [1,2,3,10,100,1000,10000]:
  182. minimum = 2*n*n + max(18, 17*n - 4)
  183. opt = gep_solvers.qr_csd_workspace_query(n)
  184. self.assertTrue( opt > 0 )
  185. self.assertTrue( opt >= minimum )
  186. class Test_solve_with_gsvd(unittest.TestCase):
  187. dtypes = [NP.float32, NP.float64]
  188. solver = gep_solvers.gsvd
  189. def setUp(self):
  190. self.numpy_warnings = NP.seterr(invalid='ignore')
  191. def tearDown(self):
  192. NP.seterr(**self.numpy_warnings)
  193. def test_simple(self):
  194. test_simple(self, self.solver)
  195. def test_random(self):
  196. test_random(self, self.solver)
  197. def test_random_singular(self):
  198. test_random_singular(self, self.solver)
  199. def test_checks(self):
  200. test_checks(self, self.solver)
  201. def test_small_dimensions(self):
  202. test_small_dimensions(self, self.solver)
  203. def test_singular_matrix_2by2(self):
  204. test_singular_matrix_2by2(self, self.solver)
  205. def test_singular_matrix_3by3(self):
  206. test_singular_matrix_3by3(self, self.solver)
  207. def test_zero_matrix(self):
  208. test_zero_matrix(self, self.solver)
  209. def test_workspace_query(self):
  210. for n in [1,2,3,10,100,1000,10000]:
  211. minimum = 3*n
  212. opt = gep_solvers.gsvd_workspace_query(n)
  213. self.assertTrue( opt > 0 )
  214. self.assertTrue( opt >= minimum )
  215. class Test_deflate_gep(unittest.TestCase):
  216. dtypes = [NP.float32, NP.float64]
  217. def check_return_values(self, n, dtype, A, B, X, Q):
  218. self.assertEqual( type(A), M.matrix )
  219. self.assertEqual( A.shape[0], A.shape[1] );
  220. self.assertTrue( U.is_hermitian(A) )
  221. self.assertEqual( type(B), M.matrix )
  222. self.assertEqual( B.shape[0], B.shape[1] );
  223. self.assertTrue( U.is_hermitian(B) )
  224. self.assertEqual( type(X), M.matrix )
  225. self.assertEqual( X.shape[0], X.shape[1] );
  226. self.assertEqual( type(Q), M.matrix )
  227. self.assertEqual( Q.shape[0], Q.shape[1] );
  228. self.assertEqual( A.shape[0], B.shape[0] )
  229. self.assertTrue( A.shape[0] >= 0 )
  230. self.assertTrue( A.shape[0] <= n )
  231. self.assertEqual( X.shape[0], n )
  232. self.assertEqual( Q.shape[0], n )
  233. def test_mass_matrix_full_rank(self):
  234. n = 4
  235. for dtype in self.dtypes:
  236. A = M.eye( n, dtype=dtype )
  237. B = M.eye( n, dtype=dtype )
  238. A0, B0, X, Q = gep_solvers.deflate_gep(A, B)
  239. self.check_return_values(n, dtype, A0, B0, X, Q)
  240. self.assertEqual( A0.shape[0], n )
  241. self.assertEqual( B0.shape[0], n )
  242. self.assertTrue( NP.all(A0 == A) )
  243. self.assertTrue( NP.all(B0 == B) )
  244. def test_mass_matrix_singular(self):
  245. n = 4
  246. for dtype in self.dtypes:
  247. A = M.eye( n, dtype=dtype )
  248. B = M.eye( n, dtype=dtype )
  249. B[0,0] = 0
  250. A0, B0, X, Q = gep_solvers.deflate_gep(A, B)
  251. self.check_return_values(n, dtype, A0, B0, X, Q)
  252. self.assertEqual( A0.shape[0], n-1 )
  253. self.assertEqual( B0.shape[0], n-1 )
  254. def test_error_detection(self):
  255. n = 4
  256. for dtype in self.dtypes:
  257. # mass matrix indefinite
  258. with self.assertRaises(ValueError):
  259. A = M.eye( n, dtype=dtype )
  260. B = M.eye( n, dtype=dtype )
  261. B[0,0] = -1
  262. A0, B0, X, Q = gep_solvers.deflate_gep(A, B)
  263. # matrix pencil nonregular
  264. with self.assertRaises(ValueError):
  265. A = M.eye( n, dtype=dtype )
  266. B = M.eye( n, dtype=dtype )
  267. A[0,0] = 0
  268. B[0,0] = 0
  269. A0, B0, X, Q = gep_solvers.deflate_gep(A, B)
  270. def test_workspace_query(self):
  271. for n in [2,3,10,100,1000,10000]:
  272. minimum = 2*n*n + 6*n + 1
  273. lwork, liwork = gep_solvers.deflate_gep_workspace_query(n)
  274. self.assertTrue( lwork > 0 )
  275. self.assertTrue( lwork >= minimum )
  276. self.assertTrue( liwork >= 5*n + 3 )
  277. class Test_solve_with_deflation(unittest.TestCase):
  278. dtypes = [NP.float32, NP.float64]
  279. solver = gep_solvers.deflation
  280. def setUp(self):
  281. self.numpy_warnings = NP.seterr(invalid='ignore')
  282. def tearDown(self):
  283. NP.seterr(**self.numpy_warnings)
  284. def test_simple(self):
  285. test_simple(self, self.solver)
  286. def test_random(self):
  287. test_random(self, self.solver, 10)
  288. def test_checks(self):
  289. test_checks(self, self.solver)
  290. def test_small_dimensions(self):
  291. test_small_dimensions(self, self.solver)
  292. def test_singular_matrix_2by2(self):
  293. test_singular_matrix_2by2(self, self.solver)
  294. def test_zero_matrix(self):
  295. test_zero_matrix(self, self.solver)
  296. def test_workspace_query(self):
  297. for n in [2,3,10,100,1000,10000]:
  298. lwork_min = 4*n*n + 6*n + 1
  299. liwork_min = 5*n + 3
  300. lwork, liwork = gep_solvers.deflation_workspace_query(n)
  301. self.assertTrue( lwork > 0 )
  302. self.assertTrue( lwork >= lwork_min )
  303. self.assertTrue( liwork > 0 )
  304. self.assertTrue( liwork >= liwork_min )
  305. if __name__ == '__main__':
  306. unittest.main()