Rev 1820 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === UMF_singletons ======================================================= *//* ========================================================================== *//* -------------------------------------------------------------------------- *//* UMFPACK Version 4.5, Copyright (c) 2005 by Timothy A. Davis. CISE Dept, *//* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. *//* web: http://www.cise.ufl.edu/research/sparse/umfpack *//* -------------------------------------------------------------------------- *//* Find and order the row and column singletons of a matrix A. If there are* row and column singletons, the output is a row and column permutation such* that the matrix is in the following form:** x x x x x x x x x* 0 x x x x x x x x* 0 0 x x x x x x x* 0 0 0 x 0 0 0 0 0* 0 0 0 x x 0 0 0 0* 0 0 0 x x s s s s* 0 0 0 x x s s s s* 0 0 0 x x s s s s* 0 0 0 x x s s s s** The above example has 3 column singletons (the first three columns and* their corresponding pivot rows) and 2 row singletons. The singletons are* ordered first, because they have zero Markowitz cost. The LU factorization* for these first five rows and columns is free - there is no work to do* (except to scale the pivot columns for the 2 row singletons), and no* fill-in occurs. * The remaining * submatrix (4-by-4 in the above example)* has no rows or columns with degree one. It may have empty rows or columns.** This algorithm does not perform a full permutation to block triangular* form. If there are one or more singletons, then the matrix can be* permuted to block triangular form, but UMFPACK does not perform the full* BTF permutation (see also "dmperm" in MATLAB).*/#include "umf_internal.h"#ifndef NDEBUG/* ========================================================================== *//* === debug routines ======================================================= *//* ========================================================================== *//* Dump the singleton queue */PRIVATE void dump_singletons(Int head, /* head of the queue */Int tail, /* tail of the queue */Int Next [ ], /* Next [i] is the next object after i */char *name, /* "row" or "col" */Int Deg [ ], /* Deg [i] is the degree of object i */Int n /* objects are in the range 0 to n-1 */){Int i, next, cnt ;DEBUG6 (("%s Singleton list: head "ID" tail "ID"\n", name, head, tail)) ;i = head ;ASSERT (head >= EMPTY && head < n) ;ASSERT (tail >= EMPTY && tail < n) ;cnt = 0 ;while (i != EMPTY){DEBUG7 ((" "ID": "ID" deg: "ID"\n", cnt, i, Deg [i])) ;ASSERT (i >= 0 && i < n) ;next = Next [i] ;if (i == tail) ASSERT (next == EMPTY) ;i = next ;cnt++ ;ASSERT (cnt <= n) ;}}PRIVATE void dump_mat(char *xname,char *yname,Int nx,Int ny,const Int Xp [ ],const Int Xi [ ],Int Xdeg [ ],Int Ydeg [ ]){Int x, y, p, p1, p2, xdeg, do_xdeg, ydeg ;DEBUG6 (("\n ==== Dump %s mat:\n", xname)) ;for (x = 0 ; x < nx ; x++){p1 = Xp [x] ;p2 = Xp [x+1] ;xdeg = Xdeg [x] ;DEBUG6 (("Dump %s "ID" p1 "ID" p2 "ID" deg "ID"\n",xname, x, p1, p2, xdeg)) ;do_xdeg = (xdeg >= 0) ;for (p = p1 ; p < p2 ; p++){y = Xi [p] ;DEBUG7 ((" %s "ID" deg: ", yname, y)) ;ASSERT (y >= 0 && y < ny) ;ydeg = Ydeg [y] ;DEBUG7 ((ID"\n", ydeg)) ;if (do_xdeg && ydeg >= 0){xdeg-- ;}}ASSERT (IMPLIES (do_xdeg, xdeg == 0)) ;}}#endif/* ========================================================================== *//* === create_row_form ====================================================== *//* ========================================================================== *//* Create the row-form R of the column-form input matrix A. This could be done* by UMF_transpose, except that Rdeg has already been computed.*/PRIVATE void create_row_form(/* input, not modified: */Int n_row, /* A is n_row-by-n_col, nz = Ap [n_col] */Int n_col,const Int Ap [ ], /* Ap [0..n_col]: column pointers for A */const Int Ai [ ], /* Ai [0..nz-1]: row indices for A */Int Rdeg [ ], /* Rdeg [0..n_row-1]: row degrees *//* output, not defined on input: */Int Rp [ ], /* Rp [0..n_row]: row pointers for R */Int Ri [ ], /* Ri [0..nz-1]: column indices for R *//* workspace, not defined on input or output */Int W [ ] /* size n_row */){Int row, col, p, p2 ;/* create the row pointers */Rp [0] = 0 ;W [0] = 0 ;for (row = 0 ; row < n_row ; row++){Rp [row+1] = Rp [row] + Rdeg [row] ;W [row] = Rp [row] ;}/* create the indices for the row-form */for (col = 0 ; col < n_col ; col++){p2 = Ap [col+1] ;for (p = Ap [col] ; p < p2 ; p++){Ri [W [Ai [p]]++] = col ;}}}/* ========================================================================== *//* === order_singletons ===================================================== *//* ========================================================================== */PRIVATE int order_singletons /* return new number of singletons */(Int k, /* the number of singletons so far */Int head,Int tail,Int Next [ ],Int Xdeg [ ], Int Xperm [ ], const Int Xp [ ], const Int Xi [ ],Int Ydeg [ ], Int Yperm [ ], const Int Yp [ ], const Int Yi [ ]#ifndef NDEBUG, char *xname, char *yname, Int nx, Int ny#endif){Int xpivot, x, y, ypivot, p, p2, deg ;#ifndef NDEBUGInt i, k1 = k ;dump_singletons (head, tail, Next, xname, Xdeg, nx) ;dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;#endifwhile (head != EMPTY){/* remove the singleton at the head of the queue */xpivot = head ;DEBUG1 (("------ Order %s singleton: "ID"\n", xname, xpivot)) ;head = Next [xpivot] ;if (head == EMPTY) tail = EMPTY ;#ifndef NDEBUGif (k % 100 == 0) dump_singletons (head, tail, Next, xname, Xdeg, nx) ;#endifASSERT (Xdeg [xpivot] >= 0) ;if (Xdeg [xpivot] != 1){/* This row/column x is empty. The matrix is singular.* x will be ordered last in Xperm. */DEBUG1 (("empty %s, after singletons removed\n", xname)) ;continue ;}/* find the ypivot to match with this xpivot */#ifndef NDEBUG/* there can only be one ypivot, since the degree of x is 1 */deg = 0 ;p2 = Xp [xpivot+1] ;for (p = Xp [xpivot] ; p < p2 ; p++){y = Xi [p] ;DEBUG1 (("%s: "ID"\n", yname, y)) ;if (Ydeg [y] >= 0){/* this is a live index in this xpivot vector */deg++ ;}}ASSERT (deg == 1) ;#endifypivot = EMPTY ;p2 = Xp [xpivot+1] ;for (p = Xp [xpivot] ; p < p2 ; p++){y = Xi [p] ;DEBUG1 (("%s: "ID"\n", yname, y)) ;if (Ydeg [y] >= 0){/* this is a live index in this xpivot vector */ypivot = y ;break ;}}DEBUG1 (("Pivot %s: "ID"\n", yname, ypivot)) ;ASSERT (ypivot != EMPTY) ;DEBUG1 (("deg "ID"\n", Ydeg [ypivot])) ;ASSERT (Ydeg [ypivot] >= 0) ;/* decrement the degrees after removing this singleton */DEBUG1 (("p1 "ID"\n", Yp [ypivot])) ;DEBUG1 (("p2 "ID"\n", Yp [ypivot+1])) ;p2 = Yp [ypivot+1] ;for (p = Yp [ypivot] ; p < p2 ; p++){x = Yi [p] ;DEBUG1 ((" %s: "ID" deg: "ID"\n", xname, x, Xdeg [x])) ;if (Xdeg [x] < 0) continue ;ASSERT (Xdeg [x] > 0) ;if (x == xpivot) continue ;deg = --(Xdeg [x]) ;ASSERT (Xdeg [x] >= 0) ;if (deg == 1){/* this is a new singleton, put at the end of the queue */Next [x] = EMPTY ;if (head == EMPTY){head = x ;}else{ASSERT (tail != EMPTY) ;Next [tail] = x ;}tail = x ;DEBUG1 ((" New %s singleton: "ID"\n", xname, x)) ;#ifndef NDEBUGif (k % 100 == 0){dump_singletons (head, tail, Next, xname, Xdeg, nx) ;}#endif}}/* flag the xpivot and ypivot by FLIP'ing the degrees */Xdeg [xpivot] = FLIP (1) ;Ydeg [ypivot] = FLIP (Ydeg [ypivot]) ;/* keep track of the pivot row and column */Xperm [k] = xpivot ;Yperm [k] = ypivot ;k++ ;#ifndef NDEBUGif (k % 1000 == 0){dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;}#endif}#ifndef NDEBUGDEBUGm4 (("%s singletons: k = "ID"\n", xname, k)) ;for (i = k1 ; i < k ; i++){DEBUG1 ((" %s: "ID" %s: "ID"\n", xname, Xperm [i], yname, Yperm [i])) ;}ASSERT (k > 0) ;#endifreturn (k) ;}/* ========================================================================== *//* === find_any_singletons ================================================== *//* ========================================================================== */PRIVATE Int find_any_singletons /* returns # of singletons found */(/* input, not modified: */Int n_row,Int n_col,const Int Ap [ ], /* size n_col+1 */const Int Ai [ ], /* size nz = Ap [n_col] *//* input, modified on output: */Int Cdeg [ ], /* size n_col */Int Rdeg [ ], /* size n_row *//* output, not defined on input: */Int Cperm [ ], /* size n_col */Int Rperm [ ], /* size n_row */Int *p_n1r, /* # of row singletons */Int *p_n1c, /* # of col singletons *//* workspace, not defined on input or output */Int Rp [ ], /* size n_row+1 */Int Ri [ ], /* size nz */Int W [ ], /* size n_row */Int Next [ ] /* size MAX (n_row, n_col) */){Int n1, col, row, row_form, head, tail, n1r, n1c ;/* ---------------------------------------------------------------------- *//* eliminate column singletons *//* ---------------------------------------------------------------------- */n1 = 0 ;n1r = 0 ;n1c = 0 ;row_form = FALSE ;head = EMPTY ;tail = EMPTY ;for (col = n_col-1 ; col >= 0 ; col--){if (Cdeg [col] == 1){/* put the column singleton in the queue */if (head == EMPTY) tail = col ;Next [col] = head ;head = col ;DEBUG1 (("Column singleton: "ID"\n", col)) ;}}if (head != EMPTY){/* ------------------------------------------------------------------ *//* create the row-form of A *//* ------------------------------------------------------------------ */create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;row_form = TRUE ;/* ------------------------------------------------------------------ *//* find and order the column singletons *//* ------------------------------------------------------------------ */n1 = order_singletons (0, head, tail, Next,Cdeg, Cperm, Ap, Ai,Rdeg, Rperm, Rp, Ri#ifndef NDEBUG, "col", "row", n_col, n_row#endif) ;n1c = n1 ;}/* ---------------------------------------------------------------------- *//* eliminate row singletons *//* ---------------------------------------------------------------------- */head = EMPTY ;tail = EMPTY ;for (row = n_row-1 ; row >= 0 ; row--){if (Rdeg [row] == 1){/* put the row singleton in the queue */if (head == EMPTY) tail = row ;Next [row] = head ;head = row ;DEBUG1 (("Row singleton: "ID"\n", row)) ;}}if (head != EMPTY){/* ------------------------------------------------------------------ *//* create the row-form of A, if not already created *//* ------------------------------------------------------------------ */if (!row_form){create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;}/* ------------------------------------------------------------------ *//* find and order the row singletons *//* ------------------------------------------------------------------ */n1 = order_singletons (n1, head, tail, Next,Rdeg, Rperm, Rp, Ri,Cdeg, Cperm, Ap, Ai#ifndef NDEBUG, "row", "col", n_row, n_col#endif) ;n1r = n1 - n1c ;}DEBUG0 (("n1 "ID"\n", n1)) ;*p_n1r = n1r ;*p_n1c = n1c ;return (n1) ;}/* ========================================================================== *//* === find_user_singletons ================================================= *//* ========================================================================== */PRIVATE Int find_user_singletons /* returns # singletons found */(/* input, not modified: */Int n_row,Int n_col,const Int Ap [ ], /* size n_col+1 */const Int Ai [ ], /* size nz = Ap [n_col] */const Int Quser [ ], /* size n_col if present *//* input, modified on output: */Int Cdeg [ ], /* size n_col */Int Rdeg [ ], /* size n_row *//* output, not defined on input */Int Cperm [ ], /* size n_col */Int Rperm [ ], /* size n_row */Int *p_n1r, /* # of row singletons */Int *p_n1c, /* # of col singletons *//* workspace, not defined on input or output */Int Rp [ ], /* size n_row+1 */Int Ri [ ], /* size nz */Int W [ ] /* size n_row */){Int n1, col, row, p, p2, pivcol, pivrow, found, k, n1r, n1c ;n1 = 0 ;n1r = 0 ;n1c = 0 ;*p_n1r = 0 ;*p_n1c = 0 ;/* find singletons in the user column permutation, Quser */pivcol = Quser [0] ;found = (Cdeg [pivcol] == 1) ;DEBUG0 (("Is first col: "ID" a col singleton?: "ID"\n", pivcol, found)) ;if (!found){/* the first column is not a column singleton, check for a row* singleton in the first column. */for (p = Ap [pivcol] ; p < Ap [pivcol+1] ; p++){if (Rdeg [Ai [p]] == 1){DEBUG0 (("Row singleton in first col: "ID" row: "ID"\n",pivcol, Ai [p])) ;found = TRUE ;break ;}}}if (!found){/* no singletons in the leading part of A (:,Quser) */return (0) ;}/* there is at least one row or column singleton. Look for more. */create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;n1 = 0 ;for (k = 0 ; k < n_col ; k++){pivcol = Quser [k] ;pivrow = EMPTY ;/* ------------------------------------------------------------------ *//* check if col is a column singleton, or contains a row singleton *//* ------------------------------------------------------------------ */found = (Cdeg [pivcol] == 1) ;if (found){/* -------------------------------------------------------------- *//* pivcol is a column singleton *//* -------------------------------------------------------------- */DEBUG0 (("Found a col singleton: k "ID" pivcol "ID"\n", k, pivcol));/* find the pivrow to match with this pivcol */#ifndef NDEBUG/* there can only be one pivrow, since the degree of pivcol is 1 */{Int deg = 0 ;p2 = Ap [pivcol+1] ;for (p = Ap [pivcol] ; p < p2 ; p++){row = Ai [p] ;DEBUG1 (("row: "ID"\n", row)) ;if (Rdeg [row] >= 0){/* this is a live index in this column vector */deg++ ;}}ASSERT (deg == 1) ;}#endifp2 = Ap [pivcol+1] ;for (p = Ap [pivcol] ; p < p2 ; p++){row = Ai [p] ;DEBUG1 (("row: "ID"\n", row)) ;if (Rdeg [row] >= 0){/* this is a live index in this pivcol vector */pivrow = row ;break ;}}DEBUG1 (("Pivot row: "ID"\n", pivrow)) ;ASSERT (pivrow != EMPTY) ;DEBUG1 (("deg "ID"\n", Rdeg [pivrow])) ;ASSERT (Rdeg [pivrow] >= 0) ;/* decrement the degrees after removing this col singleton */DEBUG1 (("p1 "ID"\n", Rp [pivrow])) ;DEBUG1 (("p2 "ID"\n", Rp [pivrow+1])) ;p2 = Rp [pivrow+1] ;for (p = Rp [pivrow] ; p < p2 ; p++){col = Ri [p] ;DEBUG1 ((" col: "ID" deg: "ID"\n", col, Cdeg [col])) ;if (Cdeg [col] < 0) continue ;ASSERT (Cdeg [col] > 0) ;Cdeg [col]-- ;ASSERT (Cdeg [col] >= 0) ;}/* flag the pivcol and pivrow by FLIP'ing the degrees */Cdeg [pivcol] = FLIP (1) ;Rdeg [pivrow] = FLIP (Rdeg [pivrow]) ;n1c++ ;}else{/* -------------------------------------------------------------- *//* pivcol may contain a row singleton *//* -------------------------------------------------------------- */p2 = Ap [pivcol+1] ;for (p = Ap [pivcol] ; p < p2 ; p++){pivrow = Ai [p] ;if (Rdeg [pivrow] == 1){DEBUG0 (("Row singleton in pivcol: "ID" row: "ID"\n",pivcol, pivrow)) ;found = TRUE ;break ;}}if (!found){DEBUG0 (("End of user singletons\n")) ;break ;}#ifndef NDEBUG/* there can only be one pivrow, since the degree of pivcol is 1 */{Int deg = 0 ;p2 = Rp [pivrow+1] ;for (p = Rp [pivrow] ; p < p2 ; p++){col = Ri [p] ;DEBUG1 (("col: "ID" cdeg::: "ID"\n", col, Cdeg [col])) ;if (Cdeg [col] >= 0){/* this is a live index in this column vector */ASSERT (col == pivcol) ;deg++ ;}}ASSERT (deg == 1) ;}#endifDEBUG1 (("Pivot row: "ID"\n", pivrow)) ;DEBUG1 (("pivcol deg "ID"\n", Cdeg [pivcol])) ;ASSERT (Cdeg [pivcol] > 1) ;/* decrement the degrees after removing this row singleton */DEBUG1 (("p1 "ID"\n", Ap [pivcol])) ;DEBUG1 (("p2 "ID"\n", Ap [pivcol+1])) ;p2 = Ap [pivcol+1] ;for (p = Ap [pivcol] ; p < p2 ; p++){row = Ai [p] ;DEBUG1 ((" row: "ID" deg: "ID"\n", row, Rdeg [row])) ;if (Rdeg [row] < 0) continue ;ASSERT (Rdeg [row] > 0) ;Rdeg [row]-- ;ASSERT (Rdeg [row] >= 0) ;}/* flag the pivcol and pivrow by FLIP'ing the degrees */Cdeg [pivcol] = FLIP (Cdeg [pivcol]) ;Rdeg [pivrow] = FLIP (1) ;n1r++ ;}/* keep track of the pivot row and column */Cperm [k] = pivcol ;Rperm [k] = pivrow ;n1++ ;#ifndef NDEBUGdump_mat ("col", "row", n_col, n_row, Ap, Ai, Cdeg, Rdeg) ;dump_mat ("row", "col", n_row, n_col, Rp, Ri, Rdeg, Cdeg) ;#endif}DEBUGm4 (("User singletons found: "ID"\n", n1)) ;ASSERT (n1 > 0) ;*p_n1r = n1r ;*p_n1c = n1c ;return (n1) ;}/* ========================================================================== *//* === finish_permutation =================================================== *//* ========================================================================== *//* Complete the permutation for the pruned submatrix. The singletons are* already ordered, but remove their flags. Place rows/columns that are empty* in the pruned submatrix at the end of the output permutation. This can only* occur if the matrix is singular.*/PRIVATE Int finish_permutation(Int n1,Int nx,Int Xdeg [ ],const Int Xuser [ ],Int Xperm [ ],Int *p_max_deg){Int nempty, x, deg, s, max_deg, k ;nempty = 0 ;s = n1 ;max_deg = 0 ;DEBUG0 (("n1 "ID" nempty "ID"\n", n1, nempty)) ;for (k = 0 ; k < nx ; k++){x = (Xuser != (Int *) NULL) ? Xuser [k] : k ;DEBUG0 (("finish perm k "ID" x "ID" nx "ID"\n", k, x, nx)) ;deg = Xdeg [x] ;if (deg == 0){/* this row/col is empty in the pruned submatrix */ASSERT (s < nx - nempty) ;DEBUG0 (("empty k "ID"\n", k)) ;nempty++ ;Xperm [nx - nempty] = x ;}else if (deg > 0){/* this row/col is nonempty in the pruned submatrix */ASSERT (s < nx - nempty) ;Xperm [s++] = x ;max_deg = MAX (max_deg, deg) ;}else{/* This is a singleton row/column - it is already ordered.* Just clear the flag. */Xdeg [x] = FLIP (deg) ;}}ASSERT (s == nx - nempty) ;*p_max_deg = max_deg ;return (nempty) ;}/* ========================================================================== *//* === UMF_singletons ======================================================= *//* ========================================================================== */GLOBAL Int UMF_singletons(/* input, not modified: */Int n_row,Int n_col,const Int Ap [ ], /* size n_col+1 */const Int Ai [ ], /* size nz = Ap [n_col] */const Int Quser [ ], /* size n_col if present */Int strategy, /* strategy requested by user *//* output, not defined on input: */Int Cdeg [ ], /* size n_col */Int Cperm [ ], /* size n_col */Int Rdeg [ ], /* size n_row */Int Rperm [ ], /* size n_row */Int InvRperm [ ], /* size n_row, the inverse of Rperm */Int *p_n1, /* # of col and row singletons */Int *p_n1c, /* # of col singletons */Int *p_n1r, /* # of row singletons */Int *p_nempty_col, /* # of empty columns in pruned submatrix */Int *p_nempty_row, /* # of empty columns in pruned submatrix */Int *p_is_sym, /* TRUE if pruned submatrix is square and has been* symmetrically permuted by Cperm and Rperm */Int *p_max_rdeg, /* maximum Rdeg in pruned submatrix *//* workspace, not defined on input or output */Int Rp [ ], /* size n_row+1 */Int Ri [ ], /* size nz */Int W [ ], /* size n_row */Int Next [ ] /* size MAX (n_row, n_col) */){Int n1, s, col, row, p, p1, p2, cdeg, last_row, is_sym, k,nempty_row, nempty_col, max_cdeg, max_rdeg, n1c, n1r ;/* ---------------------------------------------------------------------- *//* initializations *//* ---------------------------------------------------------------------- */#ifndef NDEBUGUMF_dump_start ( ) ;DEBUGm4 (("Starting umf_singletons\n")) ;#endif/* ---------------------------------------------------------------------- *//* scan the columns, check for errors and count row degrees *//* ---------------------------------------------------------------------- */if (Ap [0] != 0 || Ap [n_col] < 0){return (UMFPACK_ERROR_invalid_matrix) ;}for (row = 0 ; row < n_row ; row++){Rdeg [row] = 0 ;}for (col = 0 ; col < n_col ; col++){p1 = Ap [col] ;p2 = Ap [col+1] ;cdeg = p2 - p1 ;if (cdeg < 0){return (UMFPACK_ERROR_invalid_matrix) ;}last_row = EMPTY ;for (p = p1 ; p < p2 ; p++){row = Ai [p] ;if (row <= last_row || row >= n_row){return (UMFPACK_ERROR_invalid_matrix) ;}Rdeg [row]++ ;last_row = row ;}Cdeg [col] = cdeg ;}/* ---------------------------------------------------------------------- *//* find singletons *//* ---------------------------------------------------------------------- */if (Quser != (Int *) NULL){/* user has provided an input column ordering */if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC){/* look for singletons, but respect the user's input permutation */n1 = find_user_singletons (n_row, n_col, Ap, Ai, Quser,Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W) ;}else{/* do not look for singletons if Quser given and strategy is* not unsymmetric */n1 = 0 ;n1r = 0 ;n1c = 0 ;}}else{/* look for singletons anywhere */n1 = find_any_singletons (n_row, n_col, Ap, Ai,Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W, Next) ;}/* ---------------------------------------------------------------------- *//* eliminate empty columns and complete the column permutation *//* ---------------------------------------------------------------------- */nempty_col = finish_permutation (n1, n_col, Cdeg, Quser, Cperm, &max_cdeg) ;/* ---------------------------------------------------------------------- *//* eliminate empty rows and complete the row permutation *//* ---------------------------------------------------------------------- */if (Quser != (Int *) NULL && strategy == UMFPACK_STRATEGY_SYMMETRIC){/* rows should be symmetrically permuted according to Quser */ASSERT (n_row == n_col) ;nempty_row = finish_permutation (n1, n_row, Rdeg, Quser, Rperm,&max_rdeg) ;}else{/* rows should not be symmetrically permuted according to Quser */nempty_row = finish_permutation (n1, n_row, Rdeg, (Int *) NULL, Rperm,&max_rdeg) ;}/* ---------------------------------------------------------------------- *//* compute the inverse of Rperm *//* ---------------------------------------------------------------------- */for (k = 0 ; k < n_row ; k++){ASSERT (Rperm [k] >= 0 && Rperm [k] < n_row) ;InvRperm [Rperm [k]] = k ;}/* ---------------------------------------------------------------------- *//* see if pruned submatrix is square and has been symmetrically permuted *//* ---------------------------------------------------------------------- */if (n_row == n_col && nempty_row == nempty_col){/* is_sym is true if the submatrix is square, and* Rperm [n1..n_row-nempty_row-1] = Cperm [n1..n_col-nempty_col-1] */is_sym = TRUE ;for (s = n1 ; s < n_col - nempty_col ; s++){if (Cperm [s] != Rperm [s]){is_sym = FALSE ;break ;}}}else{is_sym = FALSE ;}DEBUGm4 (("Submatrix square and symmetrically permuted? "ID"\n", is_sym)) ;DEBUGm4 (("singletons "ID" row "ID" col "ID"\n", n1, n1r, n1c)) ;DEBUGm4 (("Empty cols "ID" rows "ID"\n", nempty_col, nempty_row)) ;*p_n1 = n1 ;*p_n1r = n1r ;*p_n1c = n1c ;*p_is_sym = is_sym ;*p_nempty_col = nempty_col ;*p_nempty_row = nempty_row ;*p_max_rdeg = max_rdeg ;return (UMFPACK_OK) ;}