double umf_hypot (double x, double y) { double s, r ; x = SCALAR_ABS (x) ; y = SCALAR_ABS (y) ; if (x >= y) { if (x + y == x) { s = x ; } else { r = y / x ; s = x * sqrt (1.0 + r*r) ; } } else { if (y + x == y) { s = y ; } else { r = x / y ; s = y * sqrt (1.0 + r*r) ; } } return (s) ; }
int umf_divcomplex ( double ar, double ai, /* real and imaginary parts of a */ double br, double bi, /* real and imaginary parts of b */ double *cr, double *ci /* real and imaginary parts of c */ ) { double tr, ti, r, den ; if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) { r = bi / br ; den = br + r * bi ; tr = (ar + ai * r) / den ; ti = (ai - ar * r) / den ; } else { r = br / bi ; den = r * br + bi ; tr = (ar * r + ai) / den ; ti = (ai * r - ar) / den ; } *cr = tr ; *ci = ti ; return (SCALAR_IS_ZERO (den)) ; }
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) ; }