PRIVATE Int two_by_two /* returns # unmatched weak diagonals */ ( /* input, not modified */ Int n2, /* C is n2-by-n2 */ Int Cp [ ], /* size n2+1, column pointers for C */ Int Ci [ ], /* size snz = Cp [n2], row indices for C */ Int Degree [ ], /* Degree [i] = degree of row i of C+C' */ /* input, not defined on output */ Int Next [ ], /* Next [k] == IS_WEAK if k is a weak diagonal */ Int Ri [ ], /* Ri [i] is the length of row i in C */ /* output, not defined on input */ Int P [ ], /* workspace, not defined on input or output */ Int Rp [ ], Int Head [ ] ) { Int deg, newcol, row, col, p, p2, unmatched, k, j, j2, j_best, best, jdiff, jdiff_best, jdeg, jdeg_best, cp, cp1, cp2, rp, rp1, rp2, maxdeg, mindeg ; /* ---------------------------------------------------------------------- */ /* place weak diagonals in the degree lists */ /* ---------------------------------------------------------------------- */ for (deg = 0 ; deg < n2 ; deg++) { Head [deg] = EMPTY ; } maxdeg = 0 ; mindeg = Int_MAX ; for (newcol = n2-1 ; newcol >= 0 ; newcol--) { if (Next [newcol] == IS_WEAK) { /* add this column to the list of weak nodes */ DEBUGm1 ((" newcol "ID" has a weak diagonal deg "ID"\n", newcol, deg)) ; deg = Degree [newcol] ; ASSERT (deg >= 0 && deg < n2) ; Next [newcol] = Head [deg] ; Head [deg] = newcol ; maxdeg = MAX (maxdeg, deg) ; mindeg = MIN (mindeg, deg) ; } } /* ---------------------------------------------------------------------- */ /* construct R = C' (C = strong entries in pruned submatrix) */ /* ---------------------------------------------------------------------- */ /* Ri [0..n2-1] is the length of each row of R */ /* use P as temporary pointer into the row form of R [ */ Rp [0] = 0 ; for (row = 0 ; row < n2 ; row++) { Rp [row+1] = Rp [row] + Ri [row] ; P [row] = Rp [row] ; } /* Ri no longer needed for row counts */ /* all entries in C are strong */ for (col = 0 ; col < n2 ; col++) { p2 = Cp [col+1] ; for (p = Cp [col] ; p < p2 ; p++) { /* place the column index in row = Ci [p] */ Ri [P [Ci [p]]++] = col ; } } /* contents of P no longer needed ] */ #ifndef NDEBUG DEBUG0 (("==================R: row form of strong entries in A:\n")) ; UMF_dump_col_matrix ((double *) NULL, #ifdef COMPLEX (double *) NULL, #endif Ri, Rp, n2, n2, Rp [n2]) ; #endif ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ; /* ---------------------------------------------------------------------- */ /* for each weak diagonal, find a pair of strong off-diagonal entries */ /* ---------------------------------------------------------------------- */ for (row = 0 ; row < n2 ; row++) { P [row] = EMPTY ; } unmatched = 0 ; best = EMPTY ; jdiff = EMPTY ; jdeg = EMPTY ; for (deg = mindeg ; deg <= maxdeg ; deg++) { /* find the next weak diagonal of lowest degree */ DEBUGm2 (("---------------------------------- Deg: "ID"\n", deg)) ; for (k = Head [deg] ; k != EMPTY ; k = Next [k]) { DEBUGm2 (("k: "ID"\n", k)) ; if (P [k] == EMPTY) { /* C (k,k) is a weak diagonal entry. Find an index j != k such * that C (j,k) and C (k,j) are both strong, and also such * that Degree [j] is minimized. In case of a tie, pick * the smallest index j. C and R contain the pattern of * strong entries only. * * Note that row k of R and column k of C are both sorted. */ DEBUGm4 (("===== Weak diagonal k = "ID"\n", k)) ; DEBUG1 (("Column k of C:\n")) ; for (p = Cp [k] ; p < Cp [k+1] ; p++) { DEBUG1 ((" "ID": deg "ID"\n", Ci [p], Degree [Ci [p]])); } DEBUG1 (("Row k of R (strong entries only):\n")) ; for (p = Rp [k] ; p < Rp [k+1] ; p++) { DEBUG1 ((" "ID": deg "ID"\n", Ri [p], Degree [Ri [p]])); } /* no (C (k,j), C (j,k)) pair exists yet */ j_best = EMPTY ; jdiff_best = Int_MAX ; jdeg_best = Int_MAX ; /* pointers into column k (including values) */ cp1 = Cp [k] ; cp2 = Cp [k+1] ; cp = cp1 ; /* pointers into row k (strong entries only, no values) */ rp1 = Rp [k] ; rp2 = Rp [k+1] ; rp = rp1 ; /* while entries searched in column k and row k */ while (TRUE) { if (cp >= cp2) { /* no more entries in this column */ break ; } /* get C (j,k), which is strong */ j = Ci [cp] ; if (rp >= rp2) { /* no more entries in this column */ break ; } /* get R (k,j2), which is strong */ j2 = Ri [rp] ; if (j < j2) { /* C (j,k) is strong, but R (k,j) is not strong */ cp++ ; continue ; } if (j2 < j) { /* C (k,j2) is strong, but R (j2,k) is not strong */ rp++ ; continue ; } /* j == j2: C (j,k) is strong and R (k,j) is strong */ best = FALSE ; if (P [j] == EMPTY) { /* j has not yet been matched */ jdeg = Degree [j] ; jdiff = SCALAR_ABS (k-j) ; DEBUG1 (("Try candidate j "ID" deg "ID" diff "ID "\n", j, jdeg, jdiff)) ; if (j_best == EMPTY) { /* this is the first candidate seen */ DEBUG1 ((" first\n")) ; best = TRUE ; } else { if (jdeg < jdeg_best) { /* the degree of j is best seen so far. */ DEBUG1 ((" least degree\n")) ; best = TRUE ; } else if (jdeg == jdeg_best) { /* degree of j and j_best are the same */ /* tie break by nearest node number */ if (jdiff < jdiff_best) { DEBUG1 ((" tie degree, closer\n")) ; best = TRUE ; } else if (jdiff == jdiff_best) { /* |j-k| = |j_best-k|. For any given k * and j_best there is only one other j * than can be just as close as j_best. * Tie break by picking the smaller of * j and j_best */ DEBUG1 ((" tie degree, as close\n")); best = j < j_best ; } } else { /* j has higher degree than best so far */ best = FALSE ; } } } if (best) { /* j is best match for k */ /* found a strong pair, A (j,k) and A (k,j) */ DEBUG1 ((" --- Found pair k: "ID" j: " ID " jdeg: "ID" jdiff: "ID"\n", k, j, jdeg, jdiff)) ; ASSERT (jdiff != EMPTY) ; ASSERT (jdeg != EMPTY) ; j_best = j ; jdeg_best = jdeg ; jdiff_best = jdiff ; } /* get the next entries in column k and row k */ cp++ ; rp++ ; } /* save the pair (j,k), if we found one */ if (j_best != EMPTY) { j = j_best ; DEBUGm4 ((" --- best pair j: "ID" for k: "ID"\n", j, k)) ; P [k] = j ; P [j] = k ; } else { /* no match was found for k */ unmatched++ ; } } } } /* ---------------------------------------------------------------------- */ /* finalize the row permutation, P */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n2 ; k++) { if (P [k] == EMPTY) { P [k] = k ; } } ASSERT (UMF_is_permutation (P, Rp, n2, n2)) ; return (unmatched) ; }
GLOBAL Int UMF_triplet_map_x #else GLOBAL Int UMF_triplet_map_nox #endif #else #ifdef DO_VALUES GLOBAL Int UMF_triplet_nomap_x #else GLOBAL Int UMF_triplet_nomap_nox #endif #endif ( Int n_row, Int n_col, Int nz, const Int Ti [ ], /* size nz */ const Int Tj [ ], /* size nz */ Int Ap [ ], /* size n_col + 1 */ Int Ai [ ], /* size nz */ Int Rp [ ], /* size n_row + 1 */ Int Rj [ ], /* size nz */ Int W [ ], /* size max (n_row, n_col) */ Int RowCount [ ] /* size n_row */ #ifdef DO_VALUES , const double Tx [ ] /* size nz */ , double Ax [ ] /* size nz */ , double Rx [ ] /* size nz */ #ifdef COMPLEX , const double Tz [ ] /* size nz */ , double Az [ ] /* size nz */ , double Rz [ ] /* size nz */ #endif #endif #ifdef DO_MAP , Int Map [ ] /* size nz */ , Int Map2 [ ] /* size nz */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, k, p, cp, p1, p2, pdest, pj ; #ifdef DO_MAP Int duplicates ; #endif #ifdef DO_VALUES #ifdef COMPLEX Int split = SPLIT (Tz) && SPLIT (Az) && SPLIT (Rz) ; #endif #endif /* ---------------------------------------------------------------------- */ /* count the entries in each row (also counting duplicates) */ /* ---------------------------------------------------------------------- */ /* use W as workspace for row counts (including duplicates) */ for (i = 0 ; i < n_row ; i++) { W [i] = 0 ; } for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= n_row || j < 0 || j >= n_col) { return (UMFPACK_ERROR_invalid_matrix) ; } W [i]++ ; #ifndef NDEBUG DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ; #ifdef DO_VALUES { Entry tt ; ASSIGN (tt, Tx, Tz, k, split) ; EDEBUG2 (tt) ; DEBUG1 (("\n")) ; } #endif #endif } /* ---------------------------------------------------------------------- */ /* compute the row pointers */ /* ---------------------------------------------------------------------- */ Rp [0] = 0 ; for (i = 0 ; i < n_row ; i++) { Rp [i+1] = Rp [i] + W [i] ; W [i] = Rp [i] ; } /* W is now equal to the row pointers */ /* ---------------------------------------------------------------------- */ /* construct the row form */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < nz ; k++) { p = W [Ti [k]]++ ; #ifdef DO_MAP Map [k] = p ; #endif Rj [p] = Tj [k] ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [p] = Tx [k] ; Rz [p] = Tz [k] ; } else { Rx [2*p ] = Tx [2*k ] ; Rx [2*p+1] = Tx [2*k+1] ; } #else Rx [p] = Tx [k] ; #endif #endif } /* Rp stays the same, but W [i] is advanced to the start of row i+1 */ #ifndef NDEBUG for (i = 0 ; i < n_row ; i++) { ASSERT (W [i] == Rp [i+1]) ; } #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* ---------------------------------------------------------------------- */ /* sum up duplicates */ /* ---------------------------------------------------------------------- */ /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */ for (j = 0 ; j < n_col ; j++) { W [j] = EMPTY ; } #ifdef DO_MAP duplicates = FALSE ; #endif for (i = 0 ; i < n_row ; i++) { p1 = Rp [i] ; p2 = Rp [i+1] ; pdest = p1 ; /* At this point, W [j] < p1 holds true for all columns j, */ /* because Ri/Rx/Rz is stored in row oriented order. */ #ifndef NDEBUG if (UMF_debug >= -2) { for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] < p1) ; } } #endif for (p = p1 ; p < p2 ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; pj = W [j] ; if (pj >= p1) { /* this column index, j, is already in row i, at position pj */ ASSERT (pj < p) ; ASSERT (Rj [pj] == j) ; #ifdef DO_MAP Map2 [p] = pj ; duplicates = TRUE ; #endif #ifdef DO_VALUES /* sum the entry */ #ifdef COMPLEX if (split) { Rx [pj] += Rx [p] ; Rz [pj] += Rz [p] ; } else { Rx[2*pj ] += Rx[2*p ] ; Rx[2*pj+1] += Rx[2*p+1] ; } #else Rx [pj] += Rx [p] ; #endif #endif } else { /* keep the entry */ /* also keep track in W[j] of position of a_ij for case above */ W [j] = pdest ; #ifdef DO_MAP Map2 [p] = pdest ; #endif /* no need to move the entry if pdest is equal to p */ if (pdest != p) { Rj [pdest] = j ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [pdest] = Rx [p] ; Rz [pdest] = Rz [p] ; } else { Rx [2*pdest ] = Rx [2*p ] ; Rx [2*pdest+1] = Rx [2*p+1] ; } #else Rx [pdest] = Rx [p] ; #endif #endif } pdest++ ; } } RowCount [i] = pdest - p1 ; } /* done using W for position of a_ij ] */ /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP if (duplicates) { for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } } #ifndef NDEBUG else { /* no duplicates, so no need to recompute Map */ for (k = 0 ; k < nz ; k++) { ASSERT (Map2 [k] == k) ; } } for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */ /* ---------------------------------------------------------------------- */ /* count the entries in each column */ /* ---------------------------------------------------------------------- */ /* [ use W as work space for column counts of A */ for (j = 0 ; j < n_col ; j++) { W [j] = 0 ; } for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; W [j]++ ; } } /* ---------------------------------------------------------------------- */ /* create the column pointers */ /* ---------------------------------------------------------------------- */ Ap [0] = 0 ; for (j = 0 ; j < n_col ; j++) { Ap [j+1] = Ap [j] + W [j] ; } /* done using W as workspace for column counts of A ] */ for (j = 0 ; j < n_col ; j++) { W [j] = Ap [j] ; } /* ---------------------------------------------------------------------- */ /* construct the column form */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { cp = W [Rj [p]]++ ; #ifdef DO_MAP Map2 [p] = cp ; #endif Ai [cp] = i ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Ax [cp] = Rx [p] ; Az [cp] = Rz [p] ; } else { Ax [2*cp ] = Rx [2*p ] ; Ax [2*cp+1] = Rx [2*p+1] ; } #else Ax [cp] = Rx [p] ; #endif #endif } } /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } #endif /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */ #ifndef NDEBUG for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] == Ap [j+1]) ; } UMF_dump_col_matrix ( #ifdef DO_VALUES Ax, #ifdef COMPLEX Az, #endif #else (double *) NULL, #ifdef COMPLEX (double *) NULL, #endif #endif Ai, Ap, n_row, n_col, nz) ; #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (i == Ai [p]) ; DEBUG1 ((" i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n", i, j, Ap [j], p, Ap [j+1])) ; ASSERT (Ap [j] <= p && p < Ap [j+1]) ; } #endif #endif return (UMFPACK_OK) ; }
PRIVATE void get_U ( Int Up [ ], /* of size n_col+1 */ Int Ui [ ], /* of size unz, where unz = Up [n_col] */ double Ux [ ], /* of size unz */ #ifdef COMPLEX double Uz [ ], /* of size unz */ #endif NumericType *Numeric, Int Pattern [ ], /* workspace of size n_col */ Int Wi [ ] /* workspace of size n_col */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry value ; Entry *xp, *D, *Uval ; Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen, *Usi, unz2, p, k, up, newUchain, pos, npiv, n1 ; #ifdef COMPLEX Int split = SPLIT (Uz) ; #endif #ifndef NDEBUG Int nnzpiv = 0 ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ DEBUG4 (("get_U start:\n")) ; n_col = Numeric->n_col ; n1 = Numeric->n1 ; npiv = Numeric->npiv ; Upos = Numeric->Upos ; Uilen = Numeric->Uilen ; Uip = Numeric->Uip ; D = Numeric->D ; /* ---------------------------------------------------------------------- */ /* count the nonzeros in each column of U */ /* ---------------------------------------------------------------------- */ for (col = 0 ; col < npiv ; col++) { /* include the diagonal entry in the column counts */ DEBUG4 (("D ["ID"] = ", col)) ; EDEBUG4 (D [col]) ; Wi [col] = IS_NONZERO (D [col]) ; DEBUG4 ((" is nonzero: "ID"\n", Wi [col])) ; #ifndef NDEBUG nnzpiv += IS_NONZERO (D [col]) ; #endif } DEBUG4 (("nnzpiv "ID" "ID"\n", nnzpiv, Numeric->nnzpiv)) ; ASSERT (nnzpiv == Numeric->nnzpiv) ; for (col = npiv ; col < n_col ; col++) { /* diagonal entries are zero for structurally singular part */ Wi [col] = 0 ; } deg = Numeric->ulen ; if (deg > 0) { /* make last pivot row of U (singular matrices only) */ DEBUG0 (("Last pivot row of U: ulen "ID"\n", deg)) ; for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; DEBUG0 ((" column "ID"\n", Pattern [j])) ; } } /* non-singletons */ for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* use row k of U */ /* ------------------------------------------------------------------ */ up = Uip [k] ; ulen = Uilen [k] ; newUchain = (up < 0) ; if (newUchain) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value\n", k, Pattern [j])) ; col = Pattern [j] ; ASSERT (col >= 0 && col < n_col) ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [col]++ ; } } /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (k == n1) break ; if (newUchain) { /* next row is a new Uchain */ deg = ulen ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } else { deg -= ulen ; DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg)); ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* singletons */ for (k = n1 - 1 ; k >= 0 ; k--) { deg = Uilen [k] ; DEBUG4 (("Singleton k "ID"\n", k)) ; if (deg > 0) { up = Uip [k] ; Usi = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = Usi [j] ; value = Uval [j] ; DEBUG4 ((" k "ID" col "ID" value", k, col)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [col]++ ; } } } } /* ---------------------------------------------------------------------- */ /* construct the final column form of U */ /* ---------------------------------------------------------------------- */ /* create the column pointers */ unz2 = 0 ; for (col = 0 ; col < n_col ; col++) { Up [col] = unz2 ; unz2 += Wi [col] ; } Up [n_col] = unz2 ; DEBUG1 (("Numeric->unz "ID" npiv "ID" nnzpiv "ID" unz2 "ID"\n", Numeric->unz, npiv, Numeric->nnzpiv, unz2)) ; ASSERT (Numeric->unz + Numeric->nnzpiv == unz2) ; for (col = 0 ; col < n_col ; col++) { Wi [col] = Up [col+1] ; } /* add all of the diagonal entries */ for (col = 0 ; col < npiv ; col++) { if (IS_NONZERO (D [col])) { p = --(Wi [col]) ; Ui [p] = col ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (D [col]) ; Uz [p] = IMAG_COMPONENT (D [col]) ; } else { Ux [2*p ] = REAL_COMPONENT (D [col]) ; Ux [2*p+1] = IMAG_COMPONENT (D [col]) ; } #else Ux [p] = D [col] ; #endif } } /* add all the entries from the rows of U */ deg = Numeric->ulen ; if (deg > 0) { /* make last pivot row of U (singular matrices only) */ for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; } } /* non-singletons */ for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* use row k of U */ /* ------------------------------------------------------------------ */ up = Uip [k] ; ulen = Uilen [k] ; newUchain = (up < 0) ; if (newUchain) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } xp += deg ; for (j = deg-1 ; j >= 0 ; j--) { DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ; col = Pattern [j] ; ASSERT (col >= 0 && col < n_col) ; value = *(--xp) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = --(Wi [col]) ; Ui [p] = k ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (value) ; Uz [p] = IMAG_COMPONENT (value) ; } else { Ux [2*p ] = REAL_COMPONENT (value) ; Ux [2*p+1] = IMAG_COMPONENT (value) ; } #else Ux [p] = value ; #endif } } /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (newUchain) { /* next row is a new Uchain */ deg = ulen ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } else { deg -= ulen ; DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg)); ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* singletons */ for (k = n1 - 1 ; k >= 0 ; k--) { deg = Uilen [k] ; DEBUG4 (("Singleton k "ID"\n", k)) ; if (deg > 0) { up = Uip [k] ; Usi = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = Usi [j] ; value = Uval [j] ; DEBUG4 ((" k "ID" col "ID" value", k, col)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = --(Wi [col]) ; Ui [p] = k ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (value) ; Uz [p] = IMAG_COMPONENT (value) ; } else { Ux [2*p ] = REAL_COMPONENT (value) ; Ux [2*p+1] = IMAG_COMPONENT (value) ; } #else Ux [p] = value ; #endif } } } } #ifndef NDEBUG DEBUG6 (("U matrix:")) ; UMF_dump_col_matrix (Ux, #ifdef COMPLEX Uz, #endif Ui, Up, Numeric->n_row, n_col, Numeric->unz + Numeric->nnzpiv) ; #endif }
GLOBAL Int UMF_transpose ( Int n_row, /* A is n_row-by-n_col */ Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ const double Ax [ ], /* size nz if present */ const Int P [ ], /* P [k] = i means original row i is kth row in A(P,Q)*/ /* P is identity if not present */ /* size n_row, if present */ const Int Q [ ], /* Q [k] = j means original col j is kth col in A(P,Q)*/ /* Q is identity if not present */ /* size nq, if present */ Int nq, /* size of Q, ignored if Q is (Int *) NULL */ /* output matrix: Rp, Ri, Rx, and Rz: */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ double Rx [ ], /* size nz, if present */ Int W [ ], /* size max (n_row,n_col) workspace */ Int check /* if true, then check inputs */ #ifdef COMPLEX , const double Az [ ] /* size nz */ , double Rz [ ] /* size nz */ , Int do_conjugate /* if true, then do conjugate transpose */ /* otherwise, do array transpose */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, k, p, bp, newj, do_values ; #ifdef COMPLEX Int split ; #endif /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG Int nz ; ASSERT (n_col >= 0) ; nz = (Ap != (Int *) NULL) ? Ap [n_col] : 0 ; DEBUG2 (("UMF_transpose: "ID"-by-"ID" nz "ID"\n", n_row, n_col, nz)) ; #endif if (check) { /* UMFPACK_symbolic skips this check */ /* UMFPACK_transpose always does this check */ if (!Ai || !Ap || !Ri || !Rp || !W) { return (UMFPACK_ERROR_argument_missing) ; } if (n_row <= 0 || n_col <= 0) /* n_row,n_col must be > 0 */ { return (UMFPACK_ERROR_n_nonpositive) ; } if (!UMF_is_permutation (P, W, n_row, n_row) || !UMF_is_permutation (Q, W, nq, nq)) { return (UMFPACK_ERROR_invalid_permutation) ; } if (!AMD_valid (n_row, n_col, Ap, Ai)) { return (UMFPACK_ERROR_invalid_matrix) ; } } #ifndef NDEBUG DEBUG2 (("UMF_transpose, input matrix:\n")) ; UMF_dump_col_matrix (Ax, #ifdef COMPLEX Az, #endif Ai, Ap, n_row, n_col, nz) ; #endif /* ---------------------------------------------------------------------- */ /* count the entries in each row of A */ /* ---------------------------------------------------------------------- */ /* use W as workspace for RowCount */ for (i = 0 ; i < n_row ; i++) { W [i] = 0 ; Rp [i] = 0 ; } if (Q != (Int *) NULL) { for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; ASSERT (i >= 0 && i < n_row) ; W [i]++ ; } } } else { for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; ASSERT (i >= 0 && i < n_row) ; W [i]++ ; } } } /* ---------------------------------------------------------------------- */ /* compute the row pointers for R = A (P,Q) */ /* ---------------------------------------------------------------------- */ if (P != (Int *) NULL) { Rp [0] = 0 ; for (k = 0 ; k < n_row ; k++) { i = P [k] ; ASSERT (i >= 0 && i < n_row) ; Rp [k+1] = Rp [k] + W [i] ; } for (k = 0 ; k < n_row ; k++) { i = P [k] ; ASSERT (i >= 0 && i < n_row) ; W [i] = Rp [k] ; } } else { Rp [0] = 0 ; for (i = 0 ; i < n_row ; i++) { Rp [i+1] = Rp [i] + W [i] ; } for (i = 0 ; i < n_row ; i++) { W [i] = Rp [i] ; } } ASSERT (Rp [n_row] <= Ap [n_col]) ; /* at this point, W holds the permuted row pointers */ /* ---------------------------------------------------------------------- */ /* construct the row form of B */ /* ---------------------------------------------------------------------- */ do_values = Ax && Rx ; #ifdef COMPLEX split = SPLIT (Az) && SPLIT (Rz) ; if (do_conjugate && do_values) { if (Q != (Int *) NULL) { if (split) { /* R = A (P,Q)' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [bp] = Ax [p] ; Rz [bp] = -Az [p] ; } } } else { /* R = A (P,Q)' (merged complex values) */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = -Ax [2*p+1] ; } } } } else { if (split) { /* R = A (P,:)' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [bp] = Ax [p] ; Rz [bp] = -Az [p] ; } } } else { /* R = A (P,:)' (merged complex values) */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = -Ax [2*p+1] ; } } } } } else #endif { if (Q != (Int *) NULL) { if (do_values) { #ifdef COMPLEX if (split) #endif { /* R = A (P,Q).' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [bp] = Ax [p] ; #ifdef COMPLEX Rz [bp] = Az [p] ; #endif } } } #ifdef COMPLEX else { /* R = A (P,Q).' (merged complex values) */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = Ax [2*p+1] ; } } } #endif } else { /* R = pattern of A (P,Q).' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { Ri [W [Ai [p]]++] = newj ; } } } } else { if (do_values) { #ifdef COMPLEX if (split) #endif { /* R = A (P,:).' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [bp] = Ax [p] ; #ifdef COMPLEX Rz [bp] = Az [p] ; #endif } } } #ifdef COMPLEX else { /* R = A (P,:).' (merged complex values) */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = Ax [2*p+1] ; } } } #endif } else { /* R = pattern of A (P,:).' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { Ri [W [Ai [p]]++] = j ; } } } } } #ifndef NDEBUG for (k = 0 ; k < n_row ; k++) { if (P != (Int *) NULL) { i = P [k] ; } else { i = k ; } DEBUG3 ((ID": W[i] "ID" Rp[k+1] "ID"\n", i, W [i], Rp [k+1])) ; ASSERT (W [i] == Rp [k+1]) ; } DEBUG2 (("UMF_transpose, output matrix:\n")) ; UMF_dump_col_matrix (Rx, #ifdef COMPLEX Rz, #endif Ri, Rp, n_col, n_row, Rp [n_row]) ; ASSERT (AMD_valid (n_col, n_row, Rp, Ri)) ; #endif return (UMFPACK_OK) ; }
PRIVATE void get_L ( Int Lp [ ], /* of size n_row+1 */ Int Lj [ ], /* of size lnz, where lnz = Lp [n_row] */ double Lx [ ], /* of size lnz */ #ifdef COMPLEX double Lz [ ], /* of size lnz */ #endif NumericType *Numeric, Int Pattern [ ], /* workspace of size n_row */ Int Wi [ ] /* workspace of size n_row */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry value ; Entry *xp, *Lval ; Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen, lnz2, lp, newLchain, k, pos, npiv, *Li, n1 ; #ifdef COMPLEX Int split = SPLIT (Lz) ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ DEBUG4 (("get_L start:\n")) ; n_row = Numeric->n_row ; n_col = Numeric->n_col ; n_inner = MIN (n_row, n_col) ; npiv = Numeric->npiv ; n1 = Numeric->n1 ; Lpos = Numeric->Lpos ; Lilen = Numeric->Lilen ; Lip = Numeric->Lip ; deg = 0 ; /* ---------------------------------------------------------------------- */ /* count the nonzeros in each row of L */ /* ---------------------------------------------------------------------- */ #pragma ivdep for (row = 0 ; row < n_inner ; row++) { /* include the diagonal entry in the row counts */ Wi [row] = 1 ; } #pragma ivdep for (row = n_inner ; row < n_row ; row++) { Wi [row] = 0 ; } /* singletons */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; deg = Lilen [k] ; if (deg > 0) { lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { row = Li [j] ; value = Lval [j] ; DEBUG4 ((" row "ID" k "ID" value", row, k)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [row]++ ; } } } } /* non-singletons */ for (k = n1 ; k < npiv ; k++) { /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; } /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (!newLchain) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k && row < n_row) ; Pattern [deg++] = row ; } xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; row = Pattern [j] ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [row]++ ; } } } /* ---------------------------------------------------------------------- */ /* construct the final row form of L */ /* ---------------------------------------------------------------------- */ /* create the row pointers */ lnz2 = 0 ; for (row = 0 ; row < n_row ; row++) { Lp [row] = lnz2 ; lnz2 += Wi [row] ; Wi [row] = Lp [row] ; } Lp [n_row] = lnz2 ; ASSERT (Numeric->lnz + n_inner == lnz2) ; /* add entries from the rows of L (singletons) */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; deg = Lilen [k] ; if (deg > 0) { lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { row = Li [j] ; value = Lval [j] ; DEBUG4 ((" row "ID" k "ID" value", row, k)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = Wi [row]++ ; Lj [p] = k ; #ifdef COMPLEX if (split) { Lx [p] = REAL_COMPONENT (value) ; Lz [p] = IMAG_COMPONENT (value) ; } else { Lx [2*p ] = REAL_COMPONENT (value) ; Lx [2*p+1] = IMAG_COMPONENT (value) ; } #else Lx [p] = value ; #endif } } } } /* add entries from the rows of L (non-singletons) */ for (k = n1 ; k < npiv ; k++) { /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; } /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (!newLchain) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k) ; Pattern [deg++] = row ; } xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; row = Pattern [j] ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = Wi [row]++ ; Lj [p] = k ; #ifdef COMPLEX if (split) { Lx [p] = REAL_COMPONENT (value) ; Lz [p] = IMAG_COMPONENT (value) ; } else { Lx [2*p ] = REAL_COMPONENT (value) ; Lx [2*p+1] = IMAG_COMPONENT (value) ; } #else Lx [p] = value ; #endif } } } /* add all of the diagonal entries (L is unit diagonal) */ for (row = 0 ; row < n_inner ; row++) { p = Wi [row]++ ; Lj [p] = row ; #ifdef COMPLEX if (split) { Lx [p] = 1. ; Lz [p] = 0. ; } else { Lx [2*p ] = 1. ; Lx [2*p+1] = 0. ; } #else Lx [p] = 1. ; #endif ASSERT (Wi [row] == Lp [row+1]) ; } #ifndef NDEBUG DEBUG6 (("L matrix (stored by rows):")) ; UMF_dump_col_matrix (Lx, #ifdef COMPLEX Lz, #endif Lj, Lp, n_inner, n_row, Numeric->lnz+n_inner) ; #endif DEBUG4 (("get_L done:\n")) ; }