I'm working on a project using CHOLMOD in C++ to do Cholesky factorization updating. The only reference I can find is the User Guide. And cholmod_updown_solve()
seems to be the right function for me. But there is no example on this function and I can't get a correct result.
Below is the essential part of my code. According to the user guide, the only thing to notice seems to be sorting the update matrix C
in advance. But that doesn't work. Could anyone tell me if there's any important step I missed?
Also, I'm confused because the user guide says that the solution phi
will be given "in the permuted ordering, not your original ordering". How could I restore the order without knowing the permutation matrix? (L->Perm
doesn't work.)
// The original system is At*A*phi = At*b
// Updates: C*Ct is added to At*A (Here C is a sparse column vector)
size_t n = m_pMesh->numVertices();
double w = 1e3;
cholmod_sparse *C;
cholmod_triplet *C_coefficients;
cholmod_dense *Delta_Atb;
cholmod_common common;
cholmod_common *cm = &common;
cholmod_start(cm);
C_coefficients = cholmod_allocate_triplet(n, 1, 2, 0, CHOLMOD_REAL, cm);
Delta_Atb = cholmod_zeros(n, 1, CHOLMOD_REAL, cm);
// updates: two more constraints
CViewerVertex *pNew = stroke_ends.start;
CViewerVertex *qNew = stroke_ends.end;
cholmodEntry(C_coefficients, pNew->sid(), pNew->sid(), w, cm);
cholmodEntry(C_coefficients, qNew->sid(), qNew->sid(), w, cm);
// change to At*b is Delta_Atb
((double*)Delta_Atb->x)[pNew->sid()] = w * w;
C = cholmod_triplet_to_sparse(C_coefficients, C_coefficients->nnz, cm);
cholmod_sort(C, cm);
// phi is the given solution to the original system At*A*phi = At*b
// L is the Cholesky factor to modify
// Both phi and L should be overwritten here
cholmod_updown_solve(1, C, L, phi, Delta_Atb, cm);
cholmod_free_sparse(&C, cm);
cholmod_free_triplet(&C_coefficients, cm);
cholmod_free_dense(&Delta_Atb, cm);
cholmod_finish(cm);
I also had several issues in getting a correct implementation using
cholmod_updown_solve()
. First of all, it might help understanding what the advantage of using this function is. A typical implementation usingcholmod_updown()
will look like this:Running
cholmod_solve()
for the systemCHOLMOD_A
will run both the forward and backward subsitution algorithms, each requiring2nnz(L)
float point operations.Alternatively, you can compute an initial solution to the
Ly=Pb
system as follows and reuse it later:This will be faster as
cholmod_solve()
for the systemCHOLMOD_DLt
will only run the backward substitution algorithm so if your update changes a small number of the columns ofL
you could get a speed improvement of almost 2x.You have to be careful though, as
cholmod_updown_solve()
will convert any supernodal orLL'
factorization into a simplicialLDL'
factorization so before you initialize a solution forLy=Pb
you need to make sure you are working with anLDL'
factorization. This can be achieved by running:before calling
cholmod_solve()
to initialize a solution to theLy=Pb
system.As for constructing the update sparse matrix
C
to your matrixA=P'LDL'P
, as explained in the source code, you have to actually providecholmod_updown()
orcholmod_updown_solve()
with the sparse matrixPC
which can be generated with the command:Alternatively you can build an inverse permutation array:
And then update the row indexes of
C
usingIPerm
: