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) ;
}
Beispiel #2
0
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) ;
}