/// <summary> /// Compute coarse and then fine Dulmage-Mendelsohn decomposition. seed /// optionally selects a randomized algorithm. /// </summary> /// <param name="A">column-compressed matrix</param> /// <param name="seed">0: natural, -1: reverse, random order oterwise</param> /// <returns>Dulmage-Mendelsohn analysis, null on error</returns> public static Decomposition Analyse(Matrix A, int seed) { int i, j, k, cnz, nc, nb1, nb2; int[] Cp, ps, rs; bool ok; // Maximum matching int m = A.m; int n = A.n; Decomposition D = new Decomposition(m, n); // allocate result int[] p = D.p; int[] q = D.q; int[] r = D.r; int[] s = D.s; int[] cc = D.cc; int[] rr = D.rr; int[] jimatch = MaximumTransveral(A, seed); // max transversal if (jimatch == null) { return(null); } // Coarse decomposition for (j = 0; j < n; j++) { s[j] = -1; // unmark all cols for bfs } for (i = 0; i < m; i++) { r[i] = -1; // unmark all rows for bfs } BreadthFirstSearch(A, n, r, s, q, jimatch, m, 0, 1); // find C1, R1 from C0*/ ok = BreadthFirstSearch(A, m, s, r, p, jimatch, 0, m, 3); // find R3, C3 from R0*/ if (!ok) { return(null); } Unmatched(n, s, q, cc, 0); // unmatched set C0 Matched(n, s, jimatch, m, p, q, cc, rr, 1, 1); // set R1 and C1 Matched(n, s, jimatch, m, p, q, cc, rr, 2, -1); // set R2 and C2 Matched(n, s, jimatch, m, p, q, cc, rr, 3, 3); // set R3 and C3 Unmatched(m, r, p, rr, 3); // unmatched set R0 // Fine decomposition int[] pinv = Common.InversePermutation(p, m); // pinv=p' Matrix C = A.Permute(pinv, q, false); // C=A(p,q) (it will hold A(R2,C2)) Cp = C.p; nc = cc[3] - cc[2]; // delete cols C0, C1, and C3 from C if (cc[2] > 0) { for (j = cc[2]; j <= cc[3]; j++) { Cp[j - cc[2]] = Cp[j]; } } C.n = nc; if (rr[2] - rr[1] < m) // delete rows R0, R1, and R3 from C { C.KeepSymbolic(RowPrune, rr); cnz = Cp[nc]; int[] Ci = C.i; if (rr[1] > 0) { for (k = 0; k < cnz; k++) { Ci[k] -= rr[1]; } } } C.m = nc; Decomposition scc = FindScc(C); // find strongly connected components of C*/ // Combine coarse and fine decompositions ps = scc.p; // C(ps,ps) is the permuted matrix rs = scc.r; // kth block is rs[k]..rs[k+1]-1 nb1 = scc.nb; // # of blocks of A(R2,C2) for (k = 0; k < nc; k++) { s[k] = q[ps[k] + cc[2]]; } for (k = 0; k < nc; k++) { q[k + cc[2]] = s[k]; } for (k = 0; k < nc; k++) { r[k] = p[ps[k] + rr[1]]; } for (k = 0; k < nc; k++) { p[k + rr[1]] = r[k]; } nb2 = 0; // create the fine block partitions r[0] = s[0] = 0; if (cc[2] > 0) { nb2++; // leading coarse block A (R1, [C0 C1]) } for (k = 0; k < nb1; k++) // coarse block A (R2,C2) { r[nb2] = rs[k] + rr[1]; // A (R2,C2) splits into nb1 fine blocks s[nb2] = rs[k] + cc[2]; nb2++; } if (rr[2] < m) { r[nb2] = rr[2]; // trailing coarse block A ([R3 R0], C3) s[nb2] = cc[3]; nb2++; } r[nb2] = m; s[nb2] = n; D.nb = nb2; return(D); }
/// <summary> /// Finds the strongly connected components of a square matrix. /// </summary> /// <param name="A">column-compressed matrix (A.p modified then restored)</param> /// <returns>strongly connected components, null on error</returns> static Decomposition FindScc(Matrix A) { // matrix A temporarily modified, then restored int n, i, k, b, nb = 0, top; int[] xi, p, r, Ap, ATp; Matrix AT; n = A.n; Ap = A.p; AT = A.Transpose(false); // AT = A' ATp = AT.p; xi = new int[2 * n + 1]; // get workspace Decomposition D = new Decomposition(n, 0); // allocate result p = D.p; r = D.r; top = n; for (i = 0; i < n; i++) // first dfs(A) to find finish times (xi) { if (!(Ap[i] < 0)) { top = Common.DepthFirstSearch(i, A, top, xi, xi, n, null); } } for (i = 0; i < n; i++) { //CS_MARK(Ap, i); Ap[i] = -(Ap[i]) - 2; // restore A; unmark all nodes } top = n; nb = n; for (k = 0; k < n; k++) // dfs(A') to find strongly connnected comp { i = xi[k]; // get i in reverse order of finish times if (ATp[i] < 0) { continue; // skip node i if already ordered } r[nb--] = top; // node i is the start of a component in p top = Common.DepthFirstSearch(i, AT, top, p, xi, n, null); } r[nb] = 0; // first block starts at zero; shift r up for (k = nb; k <= n; k++) { r[k - nb] = r[k]; } D.nb = nb = n - nb; // nb = # of strongly connected components for (b = 0; b < nb; b++) // sort each block in natural order { for (k = r[b]; k < r[b + 1]; k++) { xi[p[k]] = b; } } for (b = 0; b <= nb; b++) { xi[n + b] = r[b]; } for (i = 0; i < n; i++) { p[xi[n + xi[i]]++] = i; } return(D); }