int main (void) { cs_cl *T, *A, *Eye, *AT, *C, *D ; cs_long_t i, m ; T = cs_cl_load (stdin) ; /* load triplet matrix T from stdin */ printf ("T:\n") ; cs_cl_print (T, 0) ; /* print T */ A = cs_cl_compress (T) ; /* A = compressed-column form of T */ printf ("A:\n") ; cs_cl_print (A, 0) ; /* print A */ cs_cl_spfree (T) ; /* clear T */ AT = cs_cl_transpose (A, 1) ; /* AT = A' */ printf ("AT:\n") ; cs_cl_print (AT, 0) ; /* print AT */ m = A ? A->m : 0 ; /* m = # of rows of A */ T = cs_cl_spalloc (m, m, m, 1, 1) ; /* create triplet identity matrix */ for (i = 0 ; i < m ; i++) cs_cl_entry (T, i, i, 1) ; Eye = cs_cl_compress (T) ; /* Eye = speye (m) */ cs_cl_spfree (T) ; C = cs_cl_multiply (A, AT) ; /* C = A*A' */ D = cs_cl_add (C, Eye, 1, cs_cl_norm (C)) ; /* D = C + Eye*norm (C,1) */ printf ("D:\n") ; cs_cl_print (D, 0) ; /* print D */ cs_cl_spfree (A) ; /* clear A AT C D Eye */ cs_cl_spfree (AT) ; cs_cl_spfree (C) ; cs_cl_spfree (D) ; cs_cl_spfree (Eye) ; return (0) ; }
/* cs_updown: sparse Cholesky update/downdate (rank-1 or multiple rank) */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT ignore, j, k, n, lnz, *parent, sigma = 1, cp [2], ok ; char sigma_string [20] ; if (nargout > 1 || nargin < 3 || nargin > 4) { mexErrMsgTxt ("Usage: L = cs_updown(L,C,parent,sigma)") ; } if (nargin > 3 && mxIsChar (pargin [3])) { mxGetString (pargin [3], sigma_string, 8) ; sigma = (sigma_string [0] == '-') ? (-1) : 1 ; } n = mxGetN (pargin [0]) ; parent = cs_dl_mex_get_int (n, pargin [2], &ignore, 0) ; /* get parent*/ if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl Lmatrix, *Lin, Cmatrix, *C, *L, Cvector, *Cvec ; /* get input L, and copy MATLAB complex to C complex type */ Lin = cs_cl_mex_get_sparse (&Lmatrix, 1, pargin [0]) ; /* make a copy of L (this can take more work than updating L itself) */ lnz = Lin->p [n] ; L = cs_cl_spalloc (n, n, lnz, 0, 0) ; for (j = 0 ; j <= n ; j++) L->p [j] = Lin->p [j] ; for (k = 0 ; k < lnz ; k++) L->i [k] = Lin->i [k] ; /* complex values already copied into Lin->x, use shallow copy for L */ L->x = Lin->x ; cs_mex_check (0, n, -1, 0, 1, 1, pargin [1]) ; /* get C */ C = cs_cl_mex_get_sparse (&Cmatrix, 0, pargin [1]) ; /* do the update one column at a time */ Cvec = &Cvector ; Cvec->m = n ; Cvec->n = 1 ; Cvec->p = cp ; Cvec->nz = -1 ; cp [0] = 0 ; for (k = 0 ; k < C->n ; k++) { /* extract C(:,k) */ cp [1] = C->p [k+1] - C->p [k] ; Cvec->nzmax = cp [1] ; Cvec->i = C->i + C->p [k] ; Cvec->x = C->x + C->p [k] ; /* update/downdate */ ok = cs_cl_updown (L, sigma, Cvec, parent) ; if (!ok) mexErrMsgTxt ("matrix is not positive definite") ; } /* return new L */ pargout [0] = cs_cl_mex_put_sparse (&L) ; cs_free (C->x) ; /* free complex copy of C */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl Lmatrix, *Lin, Cmatrix, *C, *L, Cvector, *Cvec ; /* get input L */ Lin = cs_dl_mex_get_sparse (&Lmatrix, 1, 1, pargin [0]) ; /* make a copy of L (this can take more work than updating L itself) */ lnz = Lin->p [n] ; L = cs_dl_spalloc (n, n, lnz, 1, 0) ; for (j = 0 ; j <= n ; j++) L->p [j] = Lin->p [j] ; for (k = 0 ; k < lnz ; k++) L->i [k] = Lin->i [k] ; for (k = 0 ; k < lnz ; k++) L->x [k] = Lin->x [k] ; cs_mex_check (0, n, -1, 0, 1, 1, pargin [1]) ; /* get C */ C = cs_dl_mex_get_sparse (&Cmatrix, 0, 1, pargin [1]) ; /* do the update one column at a time */ Cvec = &Cvector ; Cvec->m = n ; Cvec->n = 1 ; Cvec->p = cp ; Cvec->nz = -1 ; cp [0] = 0 ; for (k = 0 ; k < C->n ; k++) { /* extract C(:,k) */ cp [1] = C->p [k+1] - C->p [k] ; Cvec->nzmax = cp [1] ; Cvec->i = C->i + C->p [k] ; Cvec->x = C->x + C->p [k] ; /* update/downdate */ ok = cs_dl_updown (L, sigma, Cvec, parent) ; if (!ok) mexErrMsgTxt ("matrix is not positive definite") ; } /* return new L */ pargout [0] = cs_dl_mex_put_sparse (&L) ; } }
/* Cholesky update/downdate */ cs_long_t demo3 (problem *Prob) { cs_cl *A, *C, *W = NULL, *WW, *WT, *E = NULL, *W2 ; cs_long_t n, k, *Li, *Lp, *Wi, *Wp, p1, p2, *p = NULL, ok ; cs_complex_t *b, *x, *resid, *y = NULL, *Lx, *Wx, s ; double t, t1 ; cs_cls *S = NULL ; cs_cln *N = NULL ; if (!Prob || !Prob->sym || Prob->A->n == 0) return (0) ; A = Prob->A ; C = Prob->C ; b = Prob->b ; x = Prob->x ; resid = Prob->resid; n = A->n ; if (!Prob->sym || n == 0) return (1) ; rhs (x, b, n) ; /* compute right-hand side */ printf ("\nchol then update/downdate ") ; print_order (1) ; y = cs_cl_malloc (n, sizeof (cs_complex_t)) ; t = tic () ; S = cs_cl_schol (1, C) ; /* symbolic Chol, amd(A+A') */ printf ("\nsymbolic chol time %8.2f\n", toc (t)) ; t = tic () ; N = cs_cl_chol (C, S) ; /* numeric Cholesky */ printf ("numeric chol time %8.2f\n", toc (t)) ; if (!S || !N || !y) return (done3 (0, S, N, y, W, E, p)) ; t = tic () ; cs_cl_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_cl_lsolve (N->L, y) ; /* y = L\y */ cs_cl_ltsolve (N->L, y) ; /* y = L'\y */ cs_cl_pvec (S->pinv, y, x, n) ; /* x = P'*y */ printf ("solve chol time %8.2f\n", toc (t)) ; printf ("original: ") ; print_resid (1, C, x, b, resid) ; /* print residual */ k = n/2 ; /* construct W */ W = cs_cl_spalloc (n, 1, n, 1, 0) ; if (!W) return (done3 (0, S, N, y, W, E, p)) ; Lp = N->L->p ; Li = N->L->i ; Lx = N->L->x ; Wp = W->p ; Wi = W->i ; Wx = W->x ; Wp [0] = 0 ; p1 = Lp [k] ; Wp [1] = Lp [k+1] - p1 ; s = Lx [p1] ; srand (1) ; for ( ; p1 < Lp [k+1] ; p1++) { p2 = p1 - Lp [k] ; Wi [p2] = Li [p1] ; Wx [p2] = s * rand () / ((double) RAND_MAX) ; } t = tic () ; ok = cs_cl_updown (N->L, +1, W, S->parent) ; /* update: L*L'+W*W' */ t1 = toc (t) ; printf ("update: time: %8.2f\n", t1) ; if (!ok) return (done3 (0, S, N, y, W, E, p)) ; t = tic () ; cs_cl_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_cl_lsolve (N->L, y) ; /* y = L\y */ cs_cl_ltsolve (N->L, y) ; /* y = L'\y */ cs_cl_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; p = cs_cl_pinv (S->pinv, n) ; W2 = cs_cl_permute (W, p, NULL, 1) ; /* E = C + (P'W)*(P'W)' */ WT = cs_cl_transpose (W2,1) ; WW = cs_cl_multiply (W2, WT) ; cs_cl_spfree (WT) ; cs_cl_spfree (W2) ; E = cs_cl_add (C, WW, 1, 1) ; cs_cl_spfree (WW) ; if (!E || !p) return (done3 (0, S, N, y, W, E, p)) ; printf ("update: time: %8.2f (incl solve) ", t1+t) ; print_resid (1, E, x, b, resid) ; /* print residual */ cs_cl_nfree (N) ; /* clear N */ t = tic () ; N = cs_cl_chol (E, S) ; /* numeric Cholesky */ if (!N) return (done3 (0, S, N, y, W, E, p)) ; cs_cl_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_cl_lsolve (N->L, y) ; /* y = L\y */ cs_cl_ltsolve (N->L, y) ; /* y = L'\y */ cs_cl_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; printf ("rechol: time: %8.2f (incl solve) ", t) ; print_resid (1, E, x, b, resid) ; /* print residual */ t = tic () ; ok = cs_cl_updown (N->L, -1, W, S->parent) ; /* downdate: L*L'-W*W' */ t1 = toc (t) ; if (!ok) return (done3 (0, S, N, y, W, E, p)) ; printf ("downdate: time: %8.2f\n", t1) ; t = tic () ; cs_cl_ipvec (S->pinv, b, y, n) ; /* y = P*b */ cs_cl_lsolve (N->L, y) ; /* y = L\y */ cs_cl_ltsolve (N->L, y) ; /* y = L'\y */ cs_cl_pvec (S->pinv, y, x, n) ; /* x = P'*y */ t = toc (t) ; printf ("downdate: time: %8.2f (incl solve) ", t1+t) ; print_resid (1, C, x, b, resid) ; /* print residual */ return (done3 (1, S, N, y, W, E, p)) ; }