cholupdates.rank_1.update
- cholupdates.rank_1.update(L, v, check_diag=True, overwrite_L=False, overwrite_v=False, method='seeger', **method_kwargs)
Update a Cholesky factorization after addition of a positive-semidefinite symmetric rank-1 matrix.
In other words, given \(A = L L^T \in \mathbb{R}^{N \times N}\) and \(v \in \mathbb{R}^N\), compute \(L^+\) such that
\[A^+ := A + v v^T = L^+ (L^+)^T.\]- Parameters
L ((N, N) numpy.ndarray) – Lower-triangular Cholesky factor of \(A\). Must have a non-zero diagonal. The entries in the strict upper-triangular part of
Lcan contain arbitrary values, since the algorithm neither reads from nor writes to this part of the matrix. This behavior is useful when using the Cholesky factors returned byscipy.linalg.cho_factor()which contain arbitrary values on the irrelevant triangular part of the matrix.v ((N,) numpy.ndarray) – The vector \(v\) with shape
(N,)defining the symmetric rank-1 update matrix \(v v^T\).check_diag (bool) – If set to
True, the function will check whether the diagonal of the given Cholesky factorLis non-zero and raise aValueErrorif this is not the case. Settingcheck_diagtoFalsecan be used to speed up computations if it is clear that the Cholesky factor can not have zeros on its diagonal. Caution: If this argument is set toFalseand the Cholesky factor does contain zeros on its diagonal, the behavior of the function will be undefined.overwrite_L (bool) – If set to
True, the function may overwrite the arrayLwith the upper Cholesky factor \(L^+\) of \(A^+\), i.e. the result is computed in-place. PassingFalsehere ensures that the arrayLis not modified.overwrite_v (bool) – If set to
True, the function may reuse the arrayvas an internal computation buffer, which will modifyv. PassingFalsehere ensures that the arrayvis not modified.method (str) –
Algorithm to be used to compute the updated Cholesky factor. Must be one of
- ”cho_factor”
Directly uses
scipy.linalg.cho_factor()on \(L L^T + v v^T\). This is just here for convenience and should be slower than all other methods.
- ”seeger”
Defaults to “seeger”.
method_kwargs – Additional keyword arguments which will be passed to the function selected by
method.
- Returns
Lower triangular Cholesky factor \(L^+\) of \(A + v v^T\). The diagonal entries of this matrix are guaranteed to be positive. The strict upper-triangular part of this matrix will contain the values from the upper-triangular part of
L.- Return type
(N, N) numpy.ndarray, dtype=L.dtype
- Raises
ValueError – If
Ldoes not have shape(N, N)for someN.numpy.linalg.LinAlgError – If the diagonal of
Lcontains zeros andcheck_diagis set toTrue.ValueError – If
vdoes not have shape(N,), whileLhas shape(N, N).Exception – Any exception raised by the function specified by
method.
See also
cholupdates.rank_1.downdateA similar function which performs a symmetric rank 1 downdate instead of an update.
Examples
Consider the following matrix-vector pair
>>> A = np.diag([1.0, 2.0, 3.0]) + 0.1 >>> A array([[1.1, 0.1, 0.1], [0.1, 2.1, 0.1], [0.1, 0.1, 3.1]]) >>> v = np.array([1.0, 25.0, 10.0]) >>> v array([ 1., 25., 10.])
We want to compute the lower triangular Cholesky factor
L_udof>>> A_ud = A + np.outer(v, v) >>> A_ud array([[ 2.1, 25.1, 10.1], [ 25.1, 627.1, 250.1], [ 10.1, 250.1, 103.1]])
We assume that the lower triangular Cholesky factor of
Ais given>>> import scipy.linalg >>> L = scipy.linalg.cho_factor(A, lower=True)[0] >>> np.tril(L) array([[1.04880885, 0. , 0. ], [0.09534626, 1.44599761, 0. ], [0.09534626, 0.06286946, 1.75697368]])
The function
cholupdates.rank_1.update()can computeL_udfromLefficiently>>> import cholupdates >>> L_ud = cholupdates.rank_1.update(L, v, method="seeger") >>> np.tril(L_ud) array([[ 1.44913767, 0. , 0. ], [17.32064554, 18.08577447, 0. ], [ 6.96966215, 7.15374133, 1.82969791]])
Did it work?
>>> np.allclose(A_ud, np.tril(L_ud) @ np.tril(L_ud).T) True
We could also compute
L_udby directly computing the Cholesky factorization ofA_ud(which is however less efficient)>>> L_ud_cho = cholupdates.rank_1.update(L, v, method="cho_factor") >>> np.tril(L_ud_cho) array([[ 1.44913767, 0. , 0. ], [17.32064554, 18.08577447, 0. ], [ 6.96966215, 7.15374133, 1.82969791]]) >>> np.allclose(np.tril(L_ud), np.tril(L_ud_cho)) True