// breadth-first search for coarse decomposition (C0,C1,R1 or R0,R3,C3) private bool BreadthFirstSearch(SymbolicColumnStorage A, int n, int[] wi, int[] wj, int[] queue, int[] jimatch, int imatch_offset, int jmatch_offset, int mark) { // cs_bfs int[] Ap, Ai; int head = 0, tail = 0, j, i, p, j2; for (j = 0; j < n; j++) // place all unmatched nodes in queue { if (jimatch[imatch_offset + j] >= 0) { continue; // skip j if matched } wj[j] = 0; // j in set C0 (R0 if transpose) queue[tail++] = j; // place unmatched col j in queue } if (tail == 0) { return(true); // quick return if no unmatched nodes } // Transpose if requested SymbolicColumnStorage C = (mark == 1) ? A.Clone() : A.Transpose(); if (C == null) { return(false); // bfs of C=A' to find R3,C3 from R0 } Ap = C.ColumnPointers; Ai = C.RowIndices; while (head < tail) // while queue is not empty { j = queue[head++]; // get the head of the queue for (p = Ap[j]; p < Ap[j + 1]; p++) { i = Ai[p]; if (wi[i] >= 0) { continue; // skip if i is marked } wi[i] = mark; // i in set R1 (C3 if transpose) j2 = jimatch[jmatch_offset + i]; // traverse alternating path to j2 if (wj[j2] >= 0) { continue; // skip j2 if it is marked } wj[j2] = mark; // j2 in set C1 (R3 if transpose) queue[tail++] = j2; // add j2 to queue } } //if (mark != 1) SparseMatrix.spfree(C); // free A' if it was created return(true); }
/// <summary> /// Find a maximum transveral (zero-free diagonal). Seed optionally selects a /// randomized algorithm. /// </summary> /// <param name="A">column-compressed matrix</param> /// <param name="seed">0: natural, -1: reverse, randomized otherwise</param> /// <returns>row and column matching, size m+n</returns> public static int[] Generate(SymbolicColumnStorage A, int seed) { int i, j, k, p, n2 = 0, m2 = 0; int[] jimatch, w, cheap, js, iss, ps, Cp, q; int n = A.ColumnCount; int m = A.RowCount; int[] Ap = A.ColumnPointers; int[] Ai = A.RowIndices; //[jmatch [0..m-1]; imatch [0..n-1]] w = jimatch = new int[m + n]; // allocate result for (k = 0, j = 0; j < n; j++) // count nonempty rows and columns { n2 += (Ap[j] < Ap[j + 1]) ? 1 : 0; for (p = Ap[j]; p < Ap[j + 1]; p++) { w[Ai[p]] = 1; k += (j == Ai[p]) ? 1 : 0; // count entries already on diagonal } } if (k == Math.Min(m, n)) // quick return if diagonal zero-free { for (i = 0; i < k; i++) { jimatch[i] = i; } for (; i < m; i++) { jimatch[i] = -1; } for (j = 0; j < k; j++) { jimatch[m + j] = j; } for (; j < n; j++) { jimatch[m + j] = -1; } return(jimatch); } for (i = 0; i < m; i++) { m2 += w[i]; } // Transpose if needed SymbolicColumnStorage C = (m2 < n2) ? A.Transpose() : A.Clone(); if (C == null) { return(jimatch); } n = C.ColumnCount; m = C.RowCount; Cp = C.ColumnPointers; int jmatch_offset = (m2 < n2) ? n : 0; int imatch_offset = (m2 < n2) ? 0 : m; w = new int[n]; // get workspace cheap = new int[n]; js = new int[n]; iss = new int[n]; ps = new int[n]; for (j = 0; j < n; j++) { cheap[j] = Cp[j]; // for cheap assignment } for (j = 0; j < n; j++) { w[j] = -1; // all columns unflagged } for (i = 0; i < m; i++) { jimatch[jmatch_offset + i] = -1; // nothing matched yet } q = Permutation.Create(n, seed); // q = random permutation for (k = 0; k < n; k++) // augment, starting at column q[k] { Augment(q[k], C.ColumnPointers, C.RowIndices, jimatch, jmatch_offset, cheap, w, js, iss, ps); } for (j = 0; j < n; j++) { jimatch[imatch_offset + j] = -1; // find row match } for (i = 0; i < m; i++) { if (jimatch[jmatch_offset + i] >= 0) { jimatch[imatch_offset + jimatch[jmatch_offset + i]] = i; } } return(jimatch); }