//------------------------------------------------------------------------------ // BTF/Include/strongcomp.c: MATLAB interface for btf_strongcomp //------------------------------------------------------------------------------ // BTF, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. // Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ /* STRONGCOMP: Find a symmetric permutation to upper block triangular form of * a sparse square matrix. * * Usage: * * [p,r] = strongcomp (A) ; * * [p,q,r] = strongcomp (A,qin) ; * * In the first usage, the permuted matrix is C = A (p,p). In the second usage, * the matrix A (:,qin) is symmetrically permuted to upper block triangular * form, where qin is an input column permutation, and the final permuted * matrix is C = A (p,q). This second usage is equivalent to * * [p,r] = strongcomp (A (:,qin)) ; * q = qin (p) ; * * That is, if qin is not present it is assumed to be qin = 1:n. * * C is the permuted matrix, with a number of blocks equal to length(r)-1. * The kth block is from row/col r(k) to row/col r(k+1)-1 of C. * r(1) is one and the last entry in r is equal to n+1. * The diagonal of A (or A (:,qin)) is ignored. * * strongcomp is normally proceeded by a maximum transversal: * * [p,q,r] = strongcomp (A, maxtrans (A)) * * if the matrix has full structural rank. This is identical to * * [p,q,r] = btf (A) * * (except that btf handles the case when A is structurally rank-deficient). * It essentially the same as * * [p,q,r] = dmperm (A) * * except that p, q, and r will differ between btf and dmperm. Both return an * upper block triangular form with a zero-free diagonal. The number and sizes * of the blocks will be identical, but the order of the blocks, and the * ordering within the blocks, can be different. For structurally rank * deficient matrices, dmpmerm returns the maximum matching as a zero-free * diagonal that is above the main diagonal; btf always returns the matching as * the main diagonal (which will thus contain zeros). * * See also maxtrans, btf, dmperm */ /* ========================================================================== */ #include "mex.h" #include "btf.h" void mexFunction ( int nargout, mxArray *pargout[], int nargin, const mxArray *pargin[] ) { int64_t b, n, i, k, j, *Ap, *Ai, *P, *R, nblocks, *Work, *Q, jj ; double *Px, *Rx, *Qx ; /* ---------------------------------------------------------------------- */ /* get inputs and allocate workspace */ /* ---------------------------------------------------------------------- */ if (!((nargin == 1 && nargout <= 2) || (nargin == 2 && nargout <= 3))) { mexErrMsgTxt ("Usage: [p,r] = strongcomp (A)" " or [p,q,r] = strongcomp (A,qin)") ; } n = mxGetM (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetN (pargin [0])) { mexErrMsgTxt ("strongcomp: A must be sparse, square, and non-empty") ; } /* get sparse matrix A */ Ap = (int64_t *) mxGetJc (pargin [0]) ; Ai = (int64_t *) mxGetIr (pargin [0]) ; /* get output arrays */ P = mxMalloc (n * sizeof (int64_t)) ; R = mxMalloc ((n+1) * sizeof (int64_t)) ; /* get workspace of size 4n (recursive code only needs 2n) */ Work = mxMalloc (4*n * sizeof (int64_t)) ; /* get the input column permutation Q */ if (nargin == 2) { if (mxGetNumberOfElements (pargin [1]) != n) { mexErrMsgTxt ("strongcomp: qin must be a permutation vector of size n") ; } Qx = mxGetPr (pargin [1]) ; Q = mxMalloc (n * sizeof (int64_t)) ; /* connvert Qin to 0-based and check validity */ for (i = 0 ; i < n ; i++) { Work [i] = 0 ; } for (k = 0 ; k < n ; k++) { j = Qx [k] - 1 ; /* convert to 0-based */ jj = BTF_UNFLIP (j) ; if (jj < 0 || jj >= n || Work [jj] == 1) { mexErrMsgTxt ("strongcomp: qin must be a permutation vector of size n") ; } Work [jj] = 1 ; Q [k] = j ; } } else { /* no input column permutation */ Q = (int64_t *) NULL ; } /* ---------------------------------------------------------------------- */ /* find the strongly-connected components of A */ /* ---------------------------------------------------------------------- */ nblocks = btf_l_strongcomp (n, Ap, Ai, Q, P, R, Work) ; /* ---------------------------------------------------------------------- */ /* create outputs and free workspace */ /* ---------------------------------------------------------------------- */ /* create P */ pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; Px = mxGetPr (pargout [0]) ; for (k = 0 ; k < n ; k++) { Px [k] = P [k] + 1 ; /* convert to 1-based */ } /* create Q */ if (nargin == 2 && nargout > 1) { pargout [1] = mxCreateDoubleMatrix (1, n, mxREAL) ; Qx = mxGetPr (pargout [1]) ; for (k = 0 ; k < n ; k++) { Qx [k] = Q [k] + 1 ; /* convert to 1-based */ } } /* create R */ if (nargout == nargin + 1) { pargout [nargin] = mxCreateDoubleMatrix (1, nblocks+1, mxREAL) ; Rx = mxGetPr (pargout [nargin]) ; for (b = 0 ; b <= nblocks ; b++) { Rx [b] = R [b] + 1 ; /* convert to 1-based */ } } mxFree (P) ; mxFree (R) ; mxFree (Work) ; if (nargin == 2) { mxFree (Q) ; } }