_decomp_cholesky.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. """Cholesky decomposition functions."""
  2. import numpy as np
  3. from numpy import asarray_chkfinite, asarray, atleast_2d, empty_like
  4. # Local imports
  5. from scipy._lib._util import _apply_over_batch
  6. from ._misc import LinAlgError, _datacopied
  7. from .lapack import get_lapack_funcs
  8. __all__ = ['cholesky', 'cho_factor', 'cho_solve', 'cholesky_banded',
  9. 'cho_solve_banded']
  10. def _cholesky(a, lower=False, overwrite_a=False, clean=True,
  11. check_finite=True):
  12. """Common code for cholesky() and cho_factor()."""
  13. a1 = asarray_chkfinite(a) if check_finite else asarray(a)
  14. a1 = atleast_2d(a1)
  15. # Dimension check
  16. if a1.ndim != 2:
  17. raise ValueError(f'Input array needs to be 2D but received a {a1.ndim}d-array.')
  18. # Squareness check
  19. if a1.shape[0] != a1.shape[1]:
  20. raise ValueError('Input array is expected to be square but has '
  21. f'the shape: {a1.shape}.')
  22. # Quick return for square empty array
  23. if a1.size == 0:
  24. dt = cholesky(np.eye(1, dtype=a1.dtype)).dtype
  25. return empty_like(a1, dtype=dt), lower
  26. overwrite_a = overwrite_a or _datacopied(a1, a)
  27. potrf, = get_lapack_funcs(('potrf',), (a1,))
  28. c, info = potrf(a1, lower=lower, overwrite_a=overwrite_a, clean=clean)
  29. if info > 0:
  30. raise LinAlgError(
  31. f"{info}-th leading minor of the array is not positive definite"
  32. )
  33. if info < 0:
  34. raise ValueError(
  35. f'LAPACK reported an illegal value in {-info}-th argument '
  36. f'on entry to "POTRF".'
  37. )
  38. return c, lower
  39. @_apply_over_batch(('a', 2))
  40. def cholesky(a, lower=False, overwrite_a=False, check_finite=True):
  41. """
  42. Compute the Cholesky decomposition of a matrix.
  43. Returns the Cholesky decomposition, :math:`A = L L^*` or
  44. :math:`A = U^* U` of a Hermitian positive-definite matrix A.
  45. Parameters
  46. ----------
  47. a : (M, M) array_like
  48. Matrix to be decomposed
  49. lower : bool, optional
  50. Whether to compute the upper- or lower-triangular Cholesky
  51. factorization. During decomposition, only the selected half of the
  52. matrix is referenced. Default is upper-triangular.
  53. overwrite_a : bool, optional
  54. Whether to overwrite data in `a` (may improve performance).
  55. check_finite : bool, optional
  56. Whether to check that the entire input matrix contains only finite numbers.
  57. Disabling may give a performance gain, but may result in problems
  58. (crashes, non-termination) if the inputs do contain infinities or NaNs.
  59. Returns
  60. -------
  61. c : (M, M) ndarray
  62. Upper- or lower-triangular Cholesky factor of `a`.
  63. Raises
  64. ------
  65. LinAlgError : if decomposition fails.
  66. Notes
  67. -----
  68. During the finiteness check (if selected), the entire matrix `a` is
  69. checked. During decomposition, `a` is assumed to be symmetric or Hermitian
  70. (as applicable), and only the half selected by option `lower` is referenced.
  71. Consequently, if `a` is asymmetric/non-Hermitian, `cholesky` may still
  72. succeed if the symmetric/Hermitian matrix represented by the selected half
  73. is positive definite, yet it may fail if an element in the other half is
  74. non-finite.
  75. Examples
  76. --------
  77. >>> import numpy as np
  78. >>> from scipy.linalg import cholesky
  79. >>> a = np.array([[1,-2j],[2j,5]])
  80. >>> L = cholesky(a, lower=True)
  81. >>> L
  82. array([[ 1.+0.j, 0.+0.j],
  83. [ 0.+2.j, 1.+0.j]])
  84. >>> L @ L.T.conj()
  85. array([[ 1.+0.j, 0.-2.j],
  86. [ 0.+2.j, 5.+0.j]])
  87. """
  88. c, lower = _cholesky(a, lower=lower, overwrite_a=overwrite_a, clean=True,
  89. check_finite=check_finite)
  90. return c
  91. @_apply_over_batch(("a", 2))
  92. def cho_factor(a, lower=False, overwrite_a=False, check_finite=True):
  93. """
  94. Compute the Cholesky decomposition of a matrix, to use in cho_solve
  95. Returns a matrix containing the Cholesky decomposition,
  96. ``A = L L*`` or ``A = U* U`` of a Hermitian positive-definite matrix `a`.
  97. The return value can be directly used as the first parameter to cho_solve.
  98. .. warning::
  99. The returned matrix also contains random data in the entries not
  100. used by the Cholesky decomposition. If you need to zero these
  101. entries, use the function `cholesky` instead.
  102. Parameters
  103. ----------
  104. a : (M, M) array_like
  105. Matrix to be decomposed
  106. lower : bool, optional
  107. Whether to compute the upper or lower triangular Cholesky factorization.
  108. During decomposition, only the selected half of the matrix is referenced.
  109. (Default: upper-triangular)
  110. overwrite_a : bool, optional
  111. Whether to overwrite data in a (may improve performance)
  112. check_finite : bool, optional
  113. Whether to check that the entire input matrix contains only finite numbers.
  114. Disabling may give a performance gain, but may result in problems
  115. (crashes, non-termination) if the inputs do contain infinities or NaNs.
  116. Returns
  117. -------
  118. c : (M, M) ndarray
  119. Matrix whose upper or lower triangle contains the Cholesky factor
  120. of `a`. Other parts of the matrix contain random data.
  121. lower : bool
  122. Flag indicating whether the factor is in the lower or upper triangle
  123. Raises
  124. ------
  125. LinAlgError
  126. Raised if decomposition fails.
  127. See Also
  128. --------
  129. cho_solve : Solve a linear set equations using the Cholesky factorization
  130. of a matrix.
  131. Notes
  132. -----
  133. During the finiteness check (if selected), the entire matrix `a` is
  134. checked. During decomposition, `a` is assumed to be symmetric or Hermitian
  135. (as applicable), and only the half selected by option `lower` is referenced.
  136. Consequently, if `a` is asymmetric/non-Hermitian, `cholesky` may still
  137. succeed if the symmetric/Hermitian matrix represented by the selected half
  138. is positive definite, yet it may fail if an element in the other half is
  139. non-finite.
  140. Examples
  141. --------
  142. >>> import numpy as np
  143. >>> from scipy.linalg import cho_factor
  144. >>> A = np.array([[9, 3, 1, 5], [3, 7, 5, 1], [1, 5, 9, 2], [5, 1, 2, 6]])
  145. >>> c, low = cho_factor(A)
  146. >>> c
  147. array([[3. , 1. , 0.33333333, 1.66666667],
  148. [3. , 2.44948974, 1.90515869, -0.27216553],
  149. [1. , 5. , 2.29330749, 0.8559528 ],
  150. [5. , 1. , 2. , 1.55418563]])
  151. >>> np.allclose(np.triu(c).T @ np. triu(c) - A, np.zeros((4, 4)))
  152. True
  153. """
  154. c, lower = _cholesky(a, lower=lower, overwrite_a=overwrite_a, clean=False,
  155. check_finite=check_finite)
  156. return c, lower
  157. def cho_solve(c_and_lower, b, overwrite_b=False, check_finite=True):
  158. """Solve the linear equations A x = b, given the Cholesky factorization of A.
  159. The documentation is written assuming array arguments are of specified
  160. "core" shapes. However, array argument(s) of this function may have additional
  161. "batch" dimensions prepended to the core shape. In this case, the array is treated
  162. as a batch of lower-dimensional slices; see :ref:`linalg_batch` for details.
  163. Parameters
  164. ----------
  165. (c, lower) : tuple, (array, bool)
  166. Cholesky factorization of a, as given by cho_factor
  167. b : array
  168. Right-hand side
  169. overwrite_b : bool, optional
  170. Whether to overwrite data in b (may improve performance)
  171. check_finite : bool, optional
  172. Whether to check that the input matrices contain only finite numbers.
  173. Disabling may give a performance gain, but may result in problems
  174. (crashes, non-termination) if the inputs do contain infinities or NaNs.
  175. Returns
  176. -------
  177. x : array
  178. The solution to the system A x = b
  179. See Also
  180. --------
  181. cho_factor : Cholesky factorization of a matrix
  182. Examples
  183. --------
  184. >>> import numpy as np
  185. >>> from scipy.linalg import cho_factor, cho_solve
  186. >>> A = np.array([[9, 3, 1, 5], [3, 7, 5, 1], [1, 5, 9, 2], [5, 1, 2, 6]])
  187. >>> c, low = cho_factor(A)
  188. >>> x = cho_solve((c, low), [1, 1, 1, 1])
  189. >>> np.allclose(A @ x - [1, 1, 1, 1], np.zeros(4))
  190. True
  191. """
  192. c, lower = c_and_lower
  193. return _cho_solve(c, b, lower, overwrite_b=overwrite_b, check_finite=check_finite)
  194. @_apply_over_batch(('c', 2), ('b', '1|2'))
  195. def _cho_solve(c, b, lower, overwrite_b, check_finite):
  196. if check_finite:
  197. b1 = asarray_chkfinite(b)
  198. c = asarray_chkfinite(c)
  199. else:
  200. b1 = asarray(b)
  201. c = asarray(c)
  202. if c.ndim != 2 or c.shape[0] != c.shape[1]:
  203. raise ValueError("The factored matrix c is not square.")
  204. if c.shape[1] != b1.shape[0]:
  205. raise ValueError(f"incompatible dimensions ({c.shape} and {b1.shape})")
  206. # accommodate empty arrays
  207. if b1.size == 0:
  208. dt = cho_solve((np.eye(2, dtype=b1.dtype), True),
  209. np.ones(2, dtype=c.dtype)).dtype
  210. return empty_like(b1, dtype=dt)
  211. overwrite_b = overwrite_b or _datacopied(b1, b)
  212. potrs, = get_lapack_funcs(('potrs',), (c, b1))
  213. x, info = potrs(c, b1, lower=lower, overwrite_b=overwrite_b)
  214. if info != 0:
  215. raise ValueError(f'illegal value in {-info}th argument of internal potrs')
  216. return x
  217. @_apply_over_batch(("ab", 2))
  218. def cholesky_banded(ab, overwrite_ab=False, lower=False, check_finite=True):
  219. """
  220. Cholesky decompose a banded Hermitian positive-definite matrix
  221. The matrix a is stored in ab either in lower-diagonal or upper-
  222. diagonal ordered form::
  223. ab[u + i - j, j] == a[i,j] (if upper form; i <= j)
  224. ab[ i - j, j] == a[i,j] (if lower form; i >= j)
  225. Example of ab (shape of a is (6,6), u=2)::
  226. upper form:
  227. * * a02 a13 a24 a35
  228. * a01 a12 a23 a34 a45
  229. a00 a11 a22 a33 a44 a55
  230. lower form:
  231. a00 a11 a22 a33 a44 a55
  232. a10 a21 a32 a43 a54 *
  233. a20 a31 a42 a53 * *
  234. Parameters
  235. ----------
  236. ab : (u + 1, M) array_like
  237. Banded matrix
  238. overwrite_ab : bool, optional
  239. Discard data in ab (may enhance performance)
  240. lower : bool, optional
  241. Is the matrix in the lower form. (Default is upper form)
  242. check_finite : bool, optional
  243. Whether to check that the input matrix contains only finite numbers.
  244. Disabling may give a performance gain, but may result in problems
  245. (crashes, non-termination) if the inputs do contain infinities or NaNs.
  246. Returns
  247. -------
  248. c : (u + 1, M) ndarray
  249. Cholesky factorization of a, in the same banded format as ab
  250. See Also
  251. --------
  252. cho_solve_banded :
  253. Solve a linear set equations, given the Cholesky factorization
  254. of a banded Hermitian.
  255. Examples
  256. --------
  257. >>> import numpy as np
  258. >>> from scipy.linalg import cholesky_banded
  259. >>> from numpy import allclose, zeros, diag
  260. >>> Ab = np.array([[0, 0, 1j, 2, 3j], [0, -1, -2, 3, 4], [9, 8, 7, 6, 9]])
  261. >>> A = np.diag(Ab[0,2:], k=2) + np.diag(Ab[1,1:], k=1)
  262. >>> A = A + A.conj().T + np.diag(Ab[2, :])
  263. >>> c = cholesky_banded(Ab)
  264. >>> C = np.diag(c[0, 2:], k=2) + np.diag(c[1, 1:], k=1) + np.diag(c[2, :])
  265. >>> np.allclose(C.conj().T @ C - A, np.zeros((5, 5)))
  266. True
  267. """
  268. if check_finite:
  269. ab = asarray_chkfinite(ab)
  270. else:
  271. ab = asarray(ab)
  272. # accommodate square empty matrices
  273. if ab.size == 0:
  274. dt = cholesky_banded(np.array([[0, 0], [1, 1]], dtype=ab.dtype)).dtype
  275. return empty_like(ab, dtype=dt)
  276. pbtrf, = get_lapack_funcs(('pbtrf',), (ab,))
  277. c, info = pbtrf(ab, lower=lower, overwrite_ab=overwrite_ab)
  278. if info > 0:
  279. raise LinAlgError(f"{info}-th leading minor not positive definite")
  280. if info < 0:
  281. raise ValueError(f'illegal value in {info}-th argument of internal pbtrf')
  282. return c
  283. def cho_solve_banded(cb_and_lower, b, overwrite_b=False, check_finite=True):
  284. """
  285. Solve the linear equations ``A x = b``, given the Cholesky factorization of
  286. the banded Hermitian ``A``.
  287. The documentation is written assuming array arguments are of specified
  288. "core" shapes. However, array argument(s) of this function may have additional
  289. "batch" dimensions prepended to the core shape. In this case, the array is treated
  290. as a batch of lower-dimensional slices; see :ref:`linalg_batch` for details.
  291. Parameters
  292. ----------
  293. (cb, lower) : tuple, (ndarray, bool)
  294. `cb` is the Cholesky factorization of A, as given by cholesky_banded.
  295. `lower` must be the same value that was given to cholesky_banded.
  296. b : array_like
  297. Right-hand side
  298. overwrite_b : bool, optional
  299. If True, the function will overwrite the values in `b`.
  300. check_finite : bool, optional
  301. Whether to check that the input matrices contain only finite numbers.
  302. Disabling may give a performance gain, but may result in problems
  303. (crashes, non-termination) if the inputs do contain infinities or NaNs.
  304. Returns
  305. -------
  306. x : array
  307. The solution to the system A x = b
  308. See Also
  309. --------
  310. cholesky_banded : Cholesky factorization of a banded matrix
  311. Notes
  312. -----
  313. .. versionadded:: 0.8.0
  314. Examples
  315. --------
  316. >>> import numpy as np
  317. >>> from scipy.linalg import cholesky_banded, cho_solve_banded
  318. >>> Ab = np.array([[0, 0, 1j, 2, 3j], [0, -1, -2, 3, 4], [9, 8, 7, 6, 9]])
  319. >>> A = np.diag(Ab[0,2:], k=2) + np.diag(Ab[1,1:], k=1)
  320. >>> A = A + A.conj().T + np.diag(Ab[2, :])
  321. >>> c = cholesky_banded(Ab)
  322. >>> x = cho_solve_banded((c, False), np.ones(5))
  323. >>> np.allclose(A @ x - np.ones(5), np.zeros(5))
  324. True
  325. """
  326. (cb, lower) = cb_and_lower
  327. return _cho_solve_banded(cb, b, lower, overwrite_b=overwrite_b,
  328. check_finite=check_finite)
  329. @_apply_over_batch(('cb', 2), ('b', '1|2'))
  330. def _cho_solve_banded(cb, b, lower, overwrite_b, check_finite):
  331. if check_finite:
  332. cb = asarray_chkfinite(cb)
  333. b = asarray_chkfinite(b)
  334. else:
  335. cb = asarray(cb)
  336. b = asarray(b)
  337. # Validate shapes.
  338. if cb.shape[-1] != b.shape[0]:
  339. raise ValueError("shapes of cb and b are not compatible.")
  340. # accommodate empty arrays
  341. if b.size == 0:
  342. m = cholesky_banded(np.array([[0, 0], [1, 1]], dtype=cb.dtype))
  343. dt = cho_solve_banded((m, True), np.ones(2, dtype=b.dtype)).dtype
  344. return empty_like(b, dtype=dt)
  345. pbtrs, = get_lapack_funcs(('pbtrs',), (cb, b))
  346. x, info = pbtrs(cb, b, lower=lower, overwrite_b=overwrite_b)
  347. if info > 0:
  348. raise LinAlgError(f"{info}th leading minor not positive definite")
  349. if info < 0:
  350. raise ValueError(f'illegal value in {-info}th argument of internal pbtrs')
  351. return x