obj_t make_weak_pointer(obj_t object) { obj_t res = alloc(obj_WeakPointerClass, sizeof(struct weak_pointer)); WEAK(res)->object = object; WEAK(res)->broken = FALSE; WEAK(res)->next = NULL; return res; }
GLOBAL void UMF_2by2 ( /* input, not modified: */ Int n, /* A is n-by-n */ const Int Ap [ ], /* size n+1 */ const Int Ai [ ], /* size nz = Ap [n] */ const double Ax [ ], /* size nz if present */ #ifdef COMPLEX const double Az [ ], /* size nz if present */ #endif double tol, /* tolerance for determining whether or not an * entry is numerically acceptable. If tol <= 0 * then all numerical values ignored. */ Int scale, /* scaling to perform (none, sum, or max) */ Int Cperm1 [ ], /* singleton permutations */ #ifndef NDEBUG Int Rperm1 [ ], /* not needed, since Rperm1 = Cperm1 for submatrix S */ #endif Int InvRperm1 [ ], /* inverse of Rperm1 */ Int n1, /* number of singletons */ Int nempty, /* number of empty rows/cols */ /* input, contents undefined on output: */ Int Degree [ ], /* Degree [j] is the number of off-diagonal * entries in row/column j of S+S', where * where S = A (Cperm1 [n1..], Rperm1 [n1..]). * Note that S is not used, nor formed. */ /* output: */ Int P [ ], /* P [k] = i means original row i is kth row in S(P,:) * where S = A (Cperm1 [n1..], Rperm1 [n1..]) */ Int *p_nweak, Int *p_unmatched, /* workspace (not defined on input or output): */ Int Ri [ ], /* of size >= max (nz, n) */ Int Rp [ ], /* of size n+1 */ double Rs [ ], /* of size n if present. Rs = sum (abs (A),2) or * max (abs (A),2), the sum or max of each row. Unused * if scale is equal to UMFPACK_SCALE_NONE. */ Int Head [ ], /* of size n. Head pointers for bucket sort */ Int Next [ ], /* of size n. Next pointers for bucket sort */ Int Ci [ ], /* size nz */ Int Cp [ ] /* size n+1 */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry aij ; double cmax, value, rs, ctol, dvalue ; Int k, p, row, col, do_values, do_sum, do_max, do_scale, nweak, weak, p1, p2, dfound, unmatched, n2, oldrow, newrow, oldcol, newcol, pp ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif #ifndef NRECIPROCAL Int do_recip = FALSE ; #endif #ifndef NDEBUG /* UMF_debug += 99 ; */ DEBUGm3 (("\n ==================================UMF_2by2: tol %g\n", tol)) ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; for (k = n1 ; k < n - nempty ; k++) { ASSERT (Cperm1 [k] == Rperm1 [k]) ; } #endif /* ---------------------------------------------------------------------- */ /* determine scaling options */ /* ---------------------------------------------------------------------- */ /* use the values, but only if they are present */ /* ignore the values if tol <= 0 */ do_values = (tol > 0) && (Ax != (double *) NULL) ; if (do_values && (Rs != (double *) NULL)) { do_sum = (scale == UMFPACK_SCALE_SUM) ; do_max = (scale == UMFPACK_SCALE_MAX) ; } else { /* no scaling */ do_sum = FALSE ; do_max = FALSE ; } do_scale = do_max || do_sum ; DEBUGm3 (("do_values "ID" do_sum "ID" do_max "ID" do_scale "ID"\n", do_values, do_sum, do_max, do_scale)) ; /* ---------------------------------------------------------------------- */ /* compute the row scaling, if requested */ /* ---------------------------------------------------------------------- */ /* see also umf_kernel_init */ if (do_scale) { #ifndef NRECIPROCAL double rsmin ; #endif for (row = 0 ; row < n ; row++) { Rs [row] = 0.0 ; } for (col = 0 ; col < n ; col++) { p2 = Ap [col+1] ; for (p = Ap [col] ; p < p2 ; p++) { row = Ai [p] ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; rs = Rs [row] ; if (!SCALAR_IS_NAN (rs)) { if (SCALAR_IS_NAN (value)) { /* if any entry in a row is NaN, then the scale factor * for the row is NaN. It will be set to 1 later. */ Rs [row] = value ; } else if (do_max) { Rs [row] = MAX (rs, value) ; } else { Rs [row] += value ; } } } } #ifndef NRECIPROCAL rsmin = Rs [0] ; if (SCALAR_IS_ZERO (rsmin) || SCALAR_IS_NAN (rsmin)) { rsmin = 1.0 ; } #endif for (row = 0 ; row < n ; row++) { /* do not scale an empty row, or a row with a NaN */ rs = Rs [row] ; if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs)) { Rs [row] = 1.0 ; } #ifndef NRECIPROCAL rsmin = MIN (rsmin, Rs [row]) ; #endif } #ifndef NRECIPROCAL /* multiply by the reciprocal if Rs is not too small */ do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ; if (do_recip) { /* invert the scale factors */ for (row = 0 ; row < n ; row++) { Rs [row] = 1.0 / Rs [row] ; } } #endif } /* ---------------------------------------------------------------------- */ /* compute the max in each column and find diagonal */ /* ---------------------------------------------------------------------- */ nweak = 0 ; #ifndef NDEBUG for (k = 0 ; k < n ; k++) { ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n) ; ASSERT (InvRperm1 [Rperm1 [k]] == k) ; } #endif n2 = n - n1 - nempty ; /* use Ri to count the number of strong entries in each row */ for (row = 0 ; row < n2 ; row++) { Ri [row] = 0 ; } pp = 0 ; ctol = 0 ; dvalue = 1 ; /* construct C = pruned submatrix, strong values only, column form */ for (k = n1 ; k < n - nempty ; k++) { oldcol = Cperm1 [k] ; newcol = k - n1 ; Next [newcol] = EMPTY ; DEBUGm1 (("Column "ID" newcol "ID" oldcol "ID"\n", k, newcol, oldcol)) ; Cp [newcol] = pp ; dfound = FALSE ; p1 = Ap [oldcol] ; p2 = Ap [oldcol+1] ; if (do_values) { cmax = 0 ; dvalue = 0 ; if (!do_scale) { /* no scaling */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } #ifndef NRECIPROCAL else if (do_recip) { /* multiply by the reciprocal */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value *= Rs [oldrow] ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } #endif else { /* divide instead */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value /= Rs [oldrow] ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } ctol = tol * cmax ; DEBUGm1 ((" cmax col "ID" %g ctol %g\n", oldcol, cmax, ctol)) ; } else { for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; Ci [pp++] = newrow ; if (oldrow == oldcol) { /* we found the diagonal entry in this column */ ASSERT (newrow == newcol) ; dfound = TRUE ; } /* count the entries in each column */ Ri [newrow]++ ; } } /* ------------------------------------------------------------------ */ /* flag the weak diagonals */ /* ------------------------------------------------------------------ */ if (!dfound) { /* no diagonal entry present */ weak = TRUE ; } else { /* diagonal entry is present, check its value */ weak = (do_values) ? WEAK (dvalue, ctol) : FALSE ; } if (weak) { /* flag this column as weak */ DEBUG0 (("Weak!\n")) ; Next [newcol] = IS_WEAK ; nweak++ ; } /* ------------------------------------------------------------------ */ /* count entries in each row that are not numerically weak */ /* ------------------------------------------------------------------ */ if (do_values) { if (!do_scale) { /* no scaling */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } #ifndef NRECIPROCAL else if (do_recip) { /* multiply by the reciprocal */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value *= Rs [oldrow] ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } #endif else { /* divide instead */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value /= Rs [oldrow] ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } } } Cp [n2] = pp ; ASSERT (AMD_valid (n2, n2, Cp, Ci) == AMD_OK) ; if (nweak == 0) { /* nothing to do, quick return */ DEBUGm2 (("\n =============================UMF_2by2: quick return\n")) ; for (k = 0 ; k < n ; k++) { P [k] = k ; } *p_nweak = 0 ; *p_unmatched = 0 ; return ; } #ifndef NDEBUG for (k = 0 ; k < n2 ; k++) { P [k] = EMPTY ; } for (k = 0 ; k < n2 ; k++) { ASSERT (Degree [k] >= 0 && Degree [k] < n2) ; } #endif /* ---------------------------------------------------------------------- */ /* find the 2-by-2 permutation */ /* ---------------------------------------------------------------------- */ /* The matrix S is now mapped to the index range 0 to n2-1. We have * S = A (Rperm [n1 .. n-nempty-1], Cperm [n1 .. n-nempty-1]), and then * C = pattern of strong entries in S. A weak diagonal k in S is marked * with Next [k] = IS_WEAK. */ unmatched = two_by_two (n2, Cp, Ci, Degree, Next, Ri, P, Rp, Head) ; /* ---------------------------------------------------------------------- */ *p_nweak = nweak ; *p_unmatched = unmatched ; #ifndef NDEBUG DEBUGm4 (("UMF_2by2: weak "ID" unmatched "ID"\n", nweak, unmatched)) ; for (row = 0 ; row < n ; row++) { DEBUGm2 (("P ["ID"] = "ID"\n", row, P [row])) ; } DEBUGm2 (("\n =============================UMF_2by2: done\n\n")) ; #endif }