cholupdates.rank_1.update_seeger¶
- cholupdates.rank_1.update_seeger(L, v, check_diag=True, overwrite_L=False, overwrite_v=False, impl=None)¶
Update a Cholesky factorization after addition of a positive semidefinite symmetric rank-1 matrix using the algorithm from section 2 of [Seeger, 2008].
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.\]This function computes the Cholesky factorization of \(A^+\) from \(L\) in \(O(N^2)\) time, which is faster than the \(O(N^3)\) time complexity of naively applying a Cholesky algorithm to \(A^+\) directly.
- Parameters
L ((N, N) numpy.ndarray, dtype=numpy.single or numpy.double) – Lower-triangular Cholesky factor of \(A\). Must have a non-zero diagonal. Must have the same dtype as
v. Must be a contiguous array (either Fortran- or C-contiguous). The algorithm is most efficient if this array is given in column-major layout, a.k.a. Fortran-contiguous or f-contiguous memory order. Hint: Lower-triangular Cholesky factors in column-major memory layout can be obtained efficiently (i.e. without requiring an additional copy) fromscipy.linalg.cho_factor(). The entries in the strict upper-triangular part ofLcan 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, dtype=numpy.single or numpy.double) – The vector \(v\) which defines the symmetric rank-1 update matrix \(v v^T\). Must have the same dtype as
L. Must be a contiguous array.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 will 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 will reuse the arrayvas an internal computation buffer, which will modifyv. PassingFalsehere ensures that the arrayvis not modified. In this case, an additional array of shape(N,)and dtypenumpy.doublemust be allocated.impl (Optional[str]) –
Defines which implementation of the algorithm to use. Must be one of
NoneChoose the Cython implementation if it is available, otherwise use the Python implementation.
- ”cython”
Use the Cython implementation. Throws a
ValueErrorif the Cython implementation is not available.
- ”python”
Use the Python implementation.
Defaults to None.
- Returns
Lower-triangular Cholesky factor \(L^+\) of \(A + v v^T\) with shape
(N, N). 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 ofL. The matrix will inherit dtype and memory order fromL.- 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 to true.ValueError – If
vdoes not have shape(N,), whileLhas shape(N, N).TypeError – If
Ldoes not have dtypenumpy.singleornumpy.double.TypeError – If
vdoes not have dtypenumpy.singleornumpy.double.TypeError – If
Landvdon’t have the same dtype.ValueError – If
Lorvis not contiguous in memory.ValueError – If
implwas set to"cython", but the Cython implementation is not available.
See also
cholupdates.rank_1.updateInterface function for all rank-1 update methods. Can be used to call this function conveniently.
Notes
This function implements the algorithm from 1, section 2. In the following, we will briefly summarize the theory behind the algorithm. Let \(A \in \mathbb{R}^{n \times n}\) be symmetric and positive-definite, and \(v \in \mathbb{R}^n\). The vector \(v\) defines a symmetric rank-1 update \(v v^T\) to \(A\), i.e.
\[A^+ := A + v v^T.\]Assume that the Cholesky factorization of \(A\), i.e. a lower-triangular matrix \(L \in \mathbb{R}^{n \times n}\) with \(A = L L^T\), is given. We want to find a fast and stable method to update the Cholesky factorization \(L L^T\) of \(A\) to the Cholesky factorization of the updated matrix \(A^+\).
To this end, we rewrite the update equation as
\[\begin{split}A^+ = \underbrace{L L^T}_{= A} + v v^T = \begin{pmatrix} L & v \end{pmatrix} \begin{pmatrix} L^T \\ v^T \end{pmatrix}.\end{split}\]We can now construct a sequence of orthogonal transformations \(Q := Q_1 \dotsb Q_n \in \mathbb{R}^{(n + 1) \times (n + 1)}\), in this case Givens rotations, such that
\[\begin{pmatrix} L & v \end{pmatrix} Q = \begin{pmatrix} L^+ & 0 \end{pmatrix},\]where \(L^+ \in \mathbb{R}^{n \times n}\) is lower-triangular. In other words, \(Q\) eliminates the last column, i.e. \(v\), from the augmented matrix \((L \mid v)\), while preserving the lower-triangular structure of the left block. But now we have
\[\begin{split}L^+ (L^+)^T & = \begin{pmatrix} L^+ & 0 \end{pmatrix} \begin{pmatrix} L^+ & 0 \end{pmatrix}^T \\ & = \begin{pmatrix} L & v \end{pmatrix} \underbrace{Q Q^T}_{= I} \begin{pmatrix} L^T \\ v^T \end{pmatrix} \\ & = \underbrace{L L^T}_{= A} + v v^T \\ & = A^+,\end{split}\]so \(L^+\) is already the lower-triangular Cholesky factor of \(A^+\).
As mentioned above, we need to multiply \(n\) Givens rotation matrices to \((L \mid v)\) which takes \(O(n)\) arithmetic operations for each rotation matrix. Hence, we end up with a total time complexity of \(O(n^2)\).
Note that this algorithm is a minor modification of the LINPACK 2 routine
dchud. The exact modifications are described in 1.References