test_decomp_cholesky.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. import pytest
  2. import numpy as np
  3. from numpy.testing import assert_array_almost_equal
  4. from pytest import raises as assert_raises
  5. from numpy import array, transpose, dot, conjugate, zeros_like, empty
  6. from numpy.random import random
  7. from scipy.linalg import (cholesky, cholesky_banded, cho_solve_banded,
  8. cho_factor, cho_solve)
  9. from scipy.linalg._testutils import assert_no_overwrite
  10. class TestCholesky:
  11. def test_simple(self):
  12. a = [[8, 2, 3], [2, 9, 3], [3, 3, 6]]
  13. c = cholesky(a)
  14. assert_array_almost_equal(dot(transpose(c), c), a)
  15. c = transpose(c)
  16. a = dot(c, transpose(c))
  17. assert_array_almost_equal(cholesky(a, lower=1), c)
  18. def test_check_finite(self):
  19. a = [[8, 2, 3], [2, 9, 3], [3, 3, 6]]
  20. c = cholesky(a, check_finite=False)
  21. assert_array_almost_equal(dot(transpose(c), c), a)
  22. c = transpose(c)
  23. a = dot(c, transpose(c))
  24. assert_array_almost_equal(cholesky(a, lower=1, check_finite=False), c)
  25. def test_simple_complex(self):
  26. m = array([[3+1j, 3+4j, 5], [0, 2+2j, 2+7j], [0, 0, 7+4j]])
  27. a = dot(transpose(conjugate(m)), m)
  28. c = cholesky(a)
  29. a1 = dot(transpose(conjugate(c)), c)
  30. assert_array_almost_equal(a, a1)
  31. c = transpose(c)
  32. a = dot(c, transpose(conjugate(c)))
  33. assert_array_almost_equal(cholesky(a, lower=1), c)
  34. def test_random(self):
  35. n = 20
  36. for k in range(2):
  37. m = random([n, n])
  38. for i in range(n):
  39. m[i, i] = 20*(.1+m[i, i])
  40. a = dot(transpose(m), m)
  41. c = cholesky(a)
  42. a1 = dot(transpose(c), c)
  43. assert_array_almost_equal(a, a1)
  44. c = transpose(c)
  45. a = dot(c, transpose(c))
  46. assert_array_almost_equal(cholesky(a, lower=1), c)
  47. def test_random_complex(self):
  48. n = 20
  49. for k in range(2):
  50. m = random([n, n])+1j*random([n, n])
  51. for i in range(n):
  52. m[i, i] = 20*(.1+abs(m[i, i]))
  53. a = dot(transpose(conjugate(m)), m)
  54. c = cholesky(a)
  55. a1 = dot(transpose(conjugate(c)), c)
  56. assert_array_almost_equal(a, a1)
  57. c = transpose(c)
  58. a = dot(c, transpose(conjugate(c)))
  59. assert_array_almost_equal(cholesky(a, lower=1), c)
  60. @pytest.mark.xslow
  61. def test_int_overflow(self):
  62. # regression test for
  63. # https://github.com/scipy/scipy/issues/17436
  64. # the problem was an int overflow in zeroing out
  65. # the unused triangular part
  66. n = 47_000
  67. x = np.eye(n, dtype=np.float64, order='F')
  68. x[:4, :4] = np.array([[4, -2, 3, -1],
  69. [-2, 4, -3, 1],
  70. [3, -3, 5, 0],
  71. [-1, 1, 0, 5]])
  72. cholesky(x, check_finite=False, overwrite_a=True) # should not segfault
  73. @pytest.mark.parametrize('dt', [int, float, np.float32, complex, np.complex64])
  74. @pytest.mark.parametrize('dt_b', [int, float, np.float32, complex, np.complex64])
  75. def test_empty(self, dt, dt_b):
  76. a = empty((0, 0), dtype=dt)
  77. c = cholesky(a)
  78. assert c.shape == (0, 0)
  79. assert c.dtype == cholesky(np.eye(2, dtype=dt)).dtype
  80. c_and_lower = (c, True)
  81. b = np.asarray([], dtype=dt_b)
  82. x = cho_solve(c_and_lower, b)
  83. assert x.shape == (0,)
  84. assert x.dtype == cho_solve((np.eye(2, dtype=dt), True),
  85. np.ones(2, dtype=dt_b)).dtype
  86. b = empty((0, 0), dtype=dt_b)
  87. x = cho_solve(c_and_lower, b)
  88. assert x.shape == (0, 0)
  89. assert x.dtype == cho_solve((np.eye(2, dtype=dt), True),
  90. np.ones(2, dtype=dt_b)).dtype
  91. a1 = array([])
  92. a2 = array([[]])
  93. a3 = []
  94. a4 = [[]]
  95. for x in ([a1, a2, a3, a4]):
  96. assert_raises(ValueError, cholesky, x)
  97. class TestCholeskyBanded:
  98. """Tests for cholesky_banded() and cho_solve_banded."""
  99. def test_check_finite(self):
  100. # Symmetric positive definite banded matrix `a`
  101. a = array([[4.0, 1.0, 0.0, 0.0],
  102. [1.0, 4.0, 0.5, 0.0],
  103. [0.0, 0.5, 4.0, 0.2],
  104. [0.0, 0.0, 0.2, 4.0]])
  105. # Banded storage form of `a`.
  106. ab = array([[-1.0, 1.0, 0.5, 0.2],
  107. [4.0, 4.0, 4.0, 4.0]])
  108. c = cholesky_banded(ab, lower=False, check_finite=False)
  109. ufac = zeros_like(a)
  110. ufac[list(range(4)), list(range(4))] = c[-1]
  111. ufac[(0, 1, 2), (1, 2, 3)] = c[0, 1:]
  112. assert_array_almost_equal(a, dot(ufac.T, ufac))
  113. b = array([0.0, 0.5, 4.2, 4.2])
  114. x = cho_solve_banded((c, False), b, check_finite=False)
  115. assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
  116. def test_upper_real(self):
  117. # Symmetric positive definite banded matrix `a`
  118. a = array([[4.0, 1.0, 0.0, 0.0],
  119. [1.0, 4.0, 0.5, 0.0],
  120. [0.0, 0.5, 4.0, 0.2],
  121. [0.0, 0.0, 0.2, 4.0]])
  122. # Banded storage form of `a`.
  123. ab = array([[-1.0, 1.0, 0.5, 0.2],
  124. [4.0, 4.0, 4.0, 4.0]])
  125. c = cholesky_banded(ab, lower=False)
  126. ufac = zeros_like(a)
  127. ufac[list(range(4)), list(range(4))] = c[-1]
  128. ufac[(0, 1, 2), (1, 2, 3)] = c[0, 1:]
  129. assert_array_almost_equal(a, dot(ufac.T, ufac))
  130. b = array([0.0, 0.5, 4.2, 4.2])
  131. x = cho_solve_banded((c, False), b)
  132. assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
  133. def test_upper_complex(self):
  134. # Hermitian positive definite banded matrix `a`
  135. a = array([[4.0, 1.0, 0.0, 0.0],
  136. [1.0, 4.0, 0.5, 0.0],
  137. [0.0, 0.5, 4.0, -0.2j],
  138. [0.0, 0.0, 0.2j, 4.0]])
  139. # Banded storage form of `a`.
  140. ab = array([[-1.0, 1.0, 0.5, -0.2j],
  141. [4.0, 4.0, 4.0, 4.0]])
  142. c = cholesky_banded(ab, lower=False)
  143. ufac = zeros_like(a)
  144. ufac[list(range(4)), list(range(4))] = c[-1]
  145. ufac[(0, 1, 2), (1, 2, 3)] = c[0, 1:]
  146. assert_array_almost_equal(a, dot(ufac.conj().T, ufac))
  147. b = array([0.0, 0.5, 4.0-0.2j, 0.2j + 4.0])
  148. x = cho_solve_banded((c, False), b)
  149. assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
  150. def test_lower_real(self):
  151. # Symmetric positive definite banded matrix `a`
  152. a = array([[4.0, 1.0, 0.0, 0.0],
  153. [1.0, 4.0, 0.5, 0.0],
  154. [0.0, 0.5, 4.0, 0.2],
  155. [0.0, 0.0, 0.2, 4.0]])
  156. # Banded storage form of `a`.
  157. ab = array([[4.0, 4.0, 4.0, 4.0],
  158. [1.0, 0.5, 0.2, -1.0]])
  159. c = cholesky_banded(ab, lower=True)
  160. lfac = zeros_like(a)
  161. lfac[list(range(4)), list(range(4))] = c[0]
  162. lfac[(1, 2, 3), (0, 1, 2)] = c[1, :3]
  163. assert_array_almost_equal(a, dot(lfac, lfac.T))
  164. b = array([0.0, 0.5, 4.2, 4.2])
  165. x = cho_solve_banded((c, True), b)
  166. assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
  167. def test_lower_complex(self):
  168. # Hermitian positive definite banded matrix `a`
  169. a = array([[4.0, 1.0, 0.0, 0.0],
  170. [1.0, 4.0, 0.5, 0.0],
  171. [0.0, 0.5, 4.0, -0.2j],
  172. [0.0, 0.0, 0.2j, 4.0]])
  173. # Banded storage form of `a`.
  174. ab = array([[4.0, 4.0, 4.0, 4.0],
  175. [1.0, 0.5, 0.2j, -1.0]])
  176. c = cholesky_banded(ab, lower=True)
  177. lfac = zeros_like(a)
  178. lfac[list(range(4)), list(range(4))] = c[0]
  179. lfac[(1, 2, 3), (0, 1, 2)] = c[1, :3]
  180. assert_array_almost_equal(a, dot(lfac, lfac.conj().T))
  181. b = array([0.0, 0.5j, 3.8j, 3.8])
  182. x = cho_solve_banded((c, True), b)
  183. assert_array_almost_equal(x, [0.0, 0.0, 1.0j, 1.0])
  184. @pytest.mark.parametrize('dt', [int, float, np.float32, complex, np.complex64])
  185. @pytest.mark.parametrize('dt_b', [int, float, np.float32, complex, np.complex64])
  186. def test_empty(self, dt, dt_b):
  187. ab = empty((0, 0), dtype=dt)
  188. cb = cholesky_banded(ab)
  189. assert cb.shape == (0, 0)
  190. m = cholesky_banded(np.array([[0, 0], [1, 1]], dtype=dt))
  191. assert cb.dtype == m.dtype
  192. cb_and_lower = (cb, True)
  193. b = np.asarray([], dtype=dt_b)
  194. x = cho_solve_banded(cb_and_lower, b)
  195. assert x.shape == (0,)
  196. dtype_nonempty = cho_solve_banded((m, True), np.ones(2, dtype=dt_b)).dtype
  197. assert x.dtype == dtype_nonempty
  198. b = empty((0, 0), dtype=dt_b)
  199. x = cho_solve_banded(cb_and_lower, b)
  200. assert x.shape == (0, 0)
  201. assert x.dtype == dtype_nonempty
  202. class TestOverwrite:
  203. def test_cholesky(self):
  204. assert_no_overwrite(cholesky, [(3, 3)])
  205. def test_cho_factor(self):
  206. assert_no_overwrite(cho_factor, [(3, 3)])
  207. def test_cho_solve(self):
  208. x = array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
  209. xcho = cho_factor(x)
  210. assert_no_overwrite(lambda b: cho_solve(xcho, b), [(3,)])
  211. def test_cholesky_banded(self):
  212. assert_no_overwrite(cholesky_banded, [(2, 3)])
  213. def test_cho_solve_banded(self):
  214. x = array([[0, -1, -1], [2, 2, 2]])
  215. xcho = cholesky_banded(x)
  216. assert_no_overwrite(lambda b: cho_solve_banded((xcho, False), b),
  217. [(3,)])
  218. class TestChoFactor:
  219. @pytest.mark.parametrize('dt', [int, float, np.float32, complex, np.complex64])
  220. def test_empty(self, dt):
  221. a = np.empty((0, 0), dtype=dt)
  222. x, lower = cho_factor(a)
  223. assert x.shape == (0, 0)
  224. xx, lower = cho_factor(np.eye(2, dtype=dt))
  225. assert x.dtype == xx.dtype