public void TestEmptyTranspose(int rows, int columns)
        {
            var A = new SymbolicColumnStorage(rows, columns, 0, true);
            var B = A.Transpose();

            Assert.IsNotNull(B);
        }
Esempio n. 2
0
        // 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);
        }
Esempio n. 3
0
        /// <summary>
        /// Column counts for Cholesky (LL'=A or LL'=A'A) and QR, given parent and post ordering.
        /// </summary>
        public static int[] ColumnCounts(SymbolicColumnStorage A, int[] parent, int[] post, bool ata)
        {
            int i, j, k, J, p, q, jleaf = 0;

            int[] ATp, ATi, colcount, delta, head = null, next = null;

            if (parent == null || post == null)
            {
                return(null);                                  // check inputs
            }
            int m = A.RowCount;
            int n = A.ColumnCount;

            delta = colcount = new int[n]; // allocate result

            var AT = A.Transpose();        // AT = A'

            // w is ancestor
            int[] w = new int[n]; // get workspace

            int[] maxfirst = new int[n];
            int[] prevleaf = new int[n];
            int[] first    = new int[n];

            for (k = 0; k < n; k++)
            {
                w[k] = -1; // clear workspace w [0..s-1]
            }
            Array.Copy(w, maxfirst, n);
            Array.Copy(w, prevleaf, n);
            Array.Copy(w, first, n);

            for (k = 0; k < n; k++) // find first [j]
            {
                j        = post[k];
                delta[j] = (first[j] == -1) ? 1 : 0; // delta[j]=1 if j is a leaf
                for (; j != -1 && first[j] == -1; j = parent[j])
                {
                    first[j] = k;
                }
            }
            ATp = AT.ColumnPointers;
            ATi = AT.RowIndices;

            if (ata) // Init ata
            {
                head = new int[n + 1];
                next = new int[m];

                Array.Copy(w, head, n);
                head[n] = -1;

                for (k = 0; k < n; k++)
                {
                    w[post[k]] = k; // invert post
                }
                for (i = 0; i < m; i++)
                {
                    for (k = n, p = ATp[i]; p < ATp[i + 1]; p++)
                    {
                        k = Math.Min(k, w[ATi[p]]);
                    }
                    next[i] = head[k]; // place row i in linked list k
                    head[k] = i;
                }
            }

            for (i = 0; i < n; i++)
            {
                w[i] = i;                     // each node in its own set
            }
            for (k = 0; k < n; k++)
            {
                j = post[k]; // j is the kth node in postordered etree
                if (parent[j] != -1)
                {
                    delta[parent[j]]--;                  // j is not a root
                }
                //int HEAD(k,j) (ata ? head [k] : j)
                //int NEXT(J)   (ata ? next [J] : -1)
                for (J = (ata ? head[k] : j); J != -1; J = (ata ? next[J] : -1)) // J=j for LL'=A case
                {
                    for (p = ATp[J]; p < ATp[J + 1]; p++)
                    {
                        i = ATi[p];
                        q = IsLeaf(i, j, first, maxfirst, prevleaf, w, ref jleaf);
                        if (jleaf >= 1)
                        {
                            delta[j]++;             // A(i,j) is in skeleton
                        }
                        if (jleaf == 2)
                        {
                            delta[q]--;             // account for overlap in q
                        }
                    }
                }
                if (parent[j] != -1)
                {
                    w[j] = parent[j];
                }
            }
            for (j = 0; j < n; j++) // sum up delta's of each child
            {
                if (parent[j] != -1)
                {
                    colcount[parent[j]] += colcount[j];
                }
            }
            return(colcount); // success: free workspace
        }
Esempio n. 4
0
        /// <summary>
        /// Finds the strongly connected components of a square matrix.
        /// </summary>
        /// <returns>strongly connected components, null on error</returns>
        private static DulmageMendelsohn FindScc(SymbolicColumnStorage A, int n)
        {
            // matrix A temporarily modified, then restored

            int i, k, b, nb = 0, top;

            int[] xi, p, r, Ap, ATp;

            var AT = A.Transpose(); // AT = A'

            Ap  = A.ColumnPointers;
            ATp = AT.ColumnPointers;

            xi = new int[2 * n + 1];             // get workspace

            var D = new DulmageMendelsohn(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 = GraphHelper.DepthFirstSearch(i, A.ColumnPointers, A.RowIndices, 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     = GraphHelper.DepthFirstSearch(i, AT.ColumnPointers, AT.RowIndices, 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);
        }
Esempio n. 5
0
        // Construct matrix C
        private static SymbolicColumnStorage ConstructMatrix(SymbolicColumnStorage A, ColumnOrdering order)
        {
            SymbolicColumnStorage result = null;

            // Compute A'
            var AT = A.Transpose();

            int m = A.RowCount;
            int n = A.ColumnCount;

            if (order == ColumnOrdering.MinimumDegreeAtPlusA)
            {
                if (n != m)
                {
                    throw new ArgumentException(Resources.MatrixSquare, "A");
                }

                // Return A+A'
                result = A.Add(AT);
            }
            else if (order == ColumnOrdering.MinimumDegreeStS)
            {
                // Drop dense columns from AT
                int dense, p, p2 = 0;

                // Find dense threshold
                dense = Math.Max(16, 10 * (int)Math.Sqrt(n));
                dense = Math.Min(n - 2, dense);

                var colptr = AT.ColumnPointers;
                var rowind = AT.RowIndices;

                for (int j = 0; j < m; j++)
                {
                    // Column j of AT starts here.
                    p = colptr[j];

                    // New column j starts here.
                    colptr[j] = p2;

                    if (colptr[j + 1] - p > dense)
                    {
                        // Skip dense column j
                        continue;
                    }

                    for (; p < colptr[j + 1]; p++)
                    {
                        rowind[p2++] = rowind[p];
                    }
                }
                colptr[m] = p2;

                // Return A'*A with no dense rows
                result = AT.Multiply(AT.Transpose());
            }
            else
            {
                // Return A'*A
                result = AT.Multiply(A);
            }

            // Drop diagonal entries.
            result.Keep(KeepOffDiag);

            return(result);
        }
Esempio n. 6
0
        /// <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);
        }