Rev 4428 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === Modify/cholmod_rowdel ================================================ *//* ========================================================================== *//* -----------------------------------------------------------------------------* CHOLMOD/Modify Module.* Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager.* The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU* General Public License. See gpl.txt for a text of the license.* CHOLMOD is also available under other licenses; contact authors for details.* http://www.cise.ufl.edu/research/sparse* -------------------------------------------------------------------------- *//* Deletes a row and column from an LDL' factorization. The row and column k* is set to the kth row and column of the identity matrix. Optionally* downdates the solution to Lx=b.** workspace: Flag (nrow), Head (nrow+1), W (nrow*2), Iwork (2*nrow)** Only real matrices are supported (exception: since only the pattern of R* is used, it can have any valid xtype).*/#ifndef NMODIFY#include "cholmod_internal.h"#include "cholmod_modify.h"/* ========================================================================== *//* === cholmod_rowdel ======================================================= *//* ========================================================================== *//* Sets the kth row and column of L to be the kth row and column of the identity* matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time,* the caller can optionally provide the nonzero pattern (or an upper bound) of* kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want* CHOLMOD to determine this itself, which is easier for the caller, but takes* a little more time.*/int CHOLMOD(rowdel)(/* ---- input ---- */size_t k, /* row/column index to delete */cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L *//* ---- in/out --- */cholmod_factor *L, /* factor to modify *//* --------------- */cholmod_common *Common){double yk [2] ;yk [0] = 0. ;yk [1] = 0. ;return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, NULL, NULL, Common)) ;}/* ========================================================================== *//* === cholmod_rowdel_solve ================================================= *//* ========================================================================== *//* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b.* When row/column k of A is "deleted" from the system A*y=b, this can induce* a change to x, in addition to changes arising when L and b are modified.* If this is the case, the kth entry of y is required as input (yk) */int CHOLMOD(rowdel_solve)(/* ---- input ---- */size_t k, /* row/column index to delete */cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */double yk [2], /* kth entry in the solution to A*y=b *//* ---- in/out --- */cholmod_factor *L, /* factor to modify */cholmod_dense *X, /* solution to Lx=b (size n-by-1) */cholmod_dense *DeltaB, /* change in b, zero on output *//* --------------- */cholmod_common *Common){return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, X, DeltaB, Common)) ;}/* ========================================================================== *//* === cholmod_rowdel_mark ================================================== *//* ========================================================================== *//* Does the same as cholmod_rowdel_solve, except only part of L is used in* the update/downdate of the solution to Lx=b. This routine is an "expert"* routine. It is meant for use in LPDASA only.** if R == NULL then columns 0:k-1 of L are searched for row k. Otherwise, it* searches columns in the set defined by the pattern of the first column of R.* This is meant to be the pattern of row k of L (a superset of that pattern is* OK too). R must be a permutation of a subset of 0:k-1.*/int CHOLMOD(rowdel_mark)(/* ---- input ---- */size_t kdel, /* row/column index to delete */cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */double yk [2], /* kth entry in the solution to A*y=b */Int *colmark, /* Int array of size 1. See cholmod_updown.c *//* ---- in/out --- */cholmod_factor *L, /* factor to modify */cholmod_dense *X, /* solution to Lx=b (size n-by-1) */cholmod_dense *DeltaB, /* change in b, zero on output *//* --------------- */cholmod_common *Common){double dk, sqrt_dk, xk, dj, fl ;double *Lx, *Cx, *W, *Xx, *Nx ;Int *Li, *Lp, *Lnz, *Ci, *Rj, *Rp, *Iwork ;cholmod_sparse *C, Cmatrix ;Int j, p, pend, kk, lnz, n, Cp [2], do_solve, do_update, left, k,right, middle, i, klast, given_row, rnz ;size_t s ;int ok = TRUE ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (FALSE) ;RETURN_IF_NULL (L, FALSE) ;RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ;n = L->n ;k = kdel ;if (kdel >= L->n || k < 0){ERROR (CHOLMOD_INVALID, "k invalid") ;return (FALSE) ;}if (R == NULL){Rj = NULL ;rnz = EMPTY ;}else{RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;if (R->ncol != 1 || R->nrow != L->n){ERROR (CHOLMOD_INVALID, "R invalid") ;return (FALSE) ;}Rj = R->i ;Rp = R->p ;rnz = Rp [1] ;}do_solve = (X != NULL) && (DeltaB != NULL) ;if (do_solve){RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;Xx = X->x ;Nx = DeltaB->x ;if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n ||DeltaB->ncol != 1 || Xx == NULL || Nx == NULL){ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ;return (FALSE) ;}}else{Xx = NULL ;Nx = NULL ;}Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* allocate workspace *//* ---------------------------------------------------------------------- *//* s = 2*n */s = CHOLMOD(mult_size_t) (n, 2, &ok) ;if (!ok){ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;return (FALSE) ;}CHOLMOD(allocate_work) (n, s, s, Common) ;if (Common->status < CHOLMOD_OK){return (FALSE) ;}ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;/* ---------------------------------------------------------------------- *//* convert to simplicial numeric LDL' factor, if not already *//* ---------------------------------------------------------------------- */if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll){/* can only update/downdate a simplicial LDL' factorization */CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L,Common) ;if (Common->status < CHOLMOD_OK){/* out of memory, L is returned unchanged */return (FALSE) ;}}/* ---------------------------------------------------------------------- *//* get inputs *//* ---------------------------------------------------------------------- *//* inputs, not modified on output: */Lp = L->p ; /* size n+1 *//* outputs, contents defined on input for incremental case only: */Lnz = L->nz ; /* size n */Li = L->i ; /* size L->nzmax. Can change in size. */Lx = L->x ; /* size L->nzmax. Can change in size. */ASSERT (L->nz != NULL) ;/* ---------------------------------------------------------------------- *//* get workspace *//* ---------------------------------------------------------------------- */W = Common->Xwork ; /* size n, used only in cholmod_updown */Cx = W + n ; /* use 2nd column of Xwork for C (size n) */Iwork = Common->Iwork ;Ci = Iwork + n ; /* size n (i/i/l) *//* NOTE: cholmod_updown uses Iwork [0..n-1] (i/i/l) as Stack *//* ---------------------------------------------------------------------- *//* prune row k from all columns of L *//* ---------------------------------------------------------------------- */given_row = (rnz >= 0) ;klast = given_row ? rnz : k ;PRINT2 (("given_row "ID"\n", given_row)) ;for (kk = 0 ; kk < klast ; kk++){/* either search j = 0:k-1 or j = Rj [0:rnz-1] */j = given_row ? (Rj [kk]) : (kk) ;if (j < 0 || j >= k){ERROR (CHOLMOD_INVALID, "R invalid") ;return (FALSE) ;}PRINT2 (("Prune col j = "ID":\n", j)) ;lnz = Lnz [j] ;dj = Lx [Lp [j]] ;ASSERT (Lnz [j] > 0 && Li [Lp [j]] == j) ;if (lnz > 1){left = Lp [j] ;pend = left + lnz ;right = pend - 1 ;i = Li [right] ;if (i < k){/* row k is not in column j */continue ;}else if (i == k){/* k is the last row index in this column (quick delete) */if (do_solve){Xx [j] -= yk [0] * dj * Lx [right] ;}Lx [right] = 0 ;}else{/* binary search for row k in column j */PRINT2 (("\nBinary search: lnz "ID" k = "ID"\n", lnz, k)) ;while (left < right){middle = (left + right) / 2 ;PRINT2 (("left "ID" right "ID" middle "ID": ["ID" "ID""""ID"]\n", left, right, middle,Li [left], Li [middle], Li [right])) ;if (k > Li [middle]){left = middle + 1 ;}else{right = middle ;}}ASSERT (left >= Lp [j] && left < pend) ;#ifndef NDEBUG/* brute force, linear-time search */{Int p3 = Lp [j] ;i = EMPTY ;PRINT2 (("Brute force:\n")) ;for ( ; p3 < pend ; p3++){i = Li [p3] ;PRINT2 (("p "ID" ["ID"]\n", p3, i)) ;if (i >= k){break ;}}if (i == k){ASSERT (k == Li [p3]) ;ASSERT (p3 == left) ;}}#endifif (k == Li [left]){if (do_solve){Xx [j] -= yk [0] * dj * Lx [left] ;}/* found row k in column j. Prune it from the column.*/Lx [left] = 0 ;}}}}#ifndef NDEBUG/* ensure that row k has been deleted from the matrix L */for (j = 0 ; j < k ; j++){Int lasti ;lasti = EMPTY ;p = Lp [j] ;pend = p + Lnz [j] ;/* look for row k in column j */PRINT1 (("Pruned column "ID"\n", j)) ;for ( ; p < pend ; p++){i = Li [p] ;PRINT2 ((" "ID"", i)) ;PRINT2 ((" %g\n", Lx [p])) ;ASSERT (IMPLIES (i == k, Lx [p] == 0)) ;ASSERT (i > lasti) ;lasti = i ;}PRINT1 (("\n")) ;}#endif/* ---------------------------------------------------------------------- *//* set diagonal and clear column k of L *//* ---------------------------------------------------------------------- */lnz = Lnz [k] - 1 ;ASSERT (Lnz [k] > 0) ;/* ---------------------------------------------------------------------- *//* update/downdate *//* ---------------------------------------------------------------------- *//* update or downdate L (k+1:n, k+1:n) with the vector* C = L (:,k) * sqrt (abs (D [k]))* Do a numeric update if D[k] > 0, numeric downdate otherwise.*/PRINT1 (("rowdel downdate lnz = "ID"\n", lnz)) ;/* store the new unit diagonal */p = Lp [k] ;pend = p + lnz + 1 ;dk = Lx [p] ;Lx [p++] = 1 ;PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ;ok = TRUE ;fl = 0 ;if (lnz > 0){/* compute DeltaB for updown (in DeltaB) */if (do_solve){xk = Xx [k] - yk [0] * dk ;for ( ; p < pend ; p++){Nx [Li [p]] += Lx [p] * xk ;}}do_update = IS_GT_ZERO (dk) ;if (!do_update){dk = -dk ;}sqrt_dk = sqrt (dk) ;p = Lp [k] + 1 ;for (kk = 0 ; kk < lnz ; kk++, p++){Ci [kk] = Li [p] ;Cx [kk] = Lx [p] * sqrt_dk ;Lx [p] = 0 ; /* clear column k */}fl = lnz + 1 ;/* create a n-by-1 sparse matrix to hold the single column */C = &Cmatrix ;C->nrow = n ;C->ncol = 1 ;C->nzmax = lnz ;C->sorted = TRUE ;C->packed = TRUE ;C->p = Cp ;C->i = Ci ;C->x = Cx ;C->nz = NULL ;C->itype = L->itype ;C->xtype = L->xtype ;C->dtype = L->dtype ;C->z = NULL ;C->stype = 0 ;Cp [0] = 0 ;Cp [1] = lnz ;/* numeric update if dk > 0, and with Lx=b change *//* workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) */ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark,L, X, DeltaB, Common) ;/* clear workspace */for (kk = 0 ; kk < lnz ; kk++){Cx [kk] = 0 ;}}Common->modfl += fl ;if (do_solve){/* kth equation becomes identity, so X(k) is now Y(k) */Xx [k] = yk [0] ;}DEBUG (CHOLMOD(dump_factor) (L, "LDL factorization, L:", Common)) ;ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;return (ok) ;}#endif