Ejemplo n.º 1
0
        public static CompressedColumnStorage FromMathNET(SparseMatrix matrix,
                                                          ColumnOrdering ordering = ColumnOrdering.MinimumDegreeAtPlusA)
        {
            int n = matrix.RowCount;

            // Check for proper dimensions.
            if (n != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.MatrixMustBeSparse);
            }

            // Get CSR storage.
            var storage = (SparseCompressedRowMatrixStorage <double>)matrix.Storage;

            // Create CSparse matrix.
            var A = new CompressedColumnStorage(n, n);

            // Assign storage arrays.
            A.ColumnPointers = storage.RowPointers;
            A.RowIndices     = storage.ColumnIndices;
            A.Values         = storage.Values;

            return(A);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a sparse QR factorization.
        /// </summary>
        /// <param name="A">Column-compressed matrix, symmetric positive definite.</param>
        /// <param name="order">Ordering method to use (natural or A+A').</param>
        /// <param name="progress">Report progress (range from 0.0 to 1.0).</param>
        public static SparseQR Create(CompressedColumnStorage <double> A, ColumnOrdering order,
                                      IProgress <double> progress)
        {
            Check.NotNull(A, "A");

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

            var C = new SparseQR(m, n);

            if (m >= n)
            {
                var p = AMD.Generate(A, order);

                // Ordering and symbolic analysis
                C.SymbolicAnalysis(A, p, order == ColumnOrdering.Natural);

                // Numeric QR factorization
                C.Factorize(A, progress);
            }
            else
            {
                // Ax=b is underdetermined
                var AT = A.Transpose();

                var p = AMD.Generate(AT, order);

                // Ordering and symbolic analysis
                C.SymbolicAnalysis(AT, p, order == ColumnOrdering.Natural);

                // Numeric QR factorization of A'
                C.Factorize(AT, progress);
            }

            return(C);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Compute the numeric LDL' factorization of PAP'.
        /// </summary>
        void Factorize(CompressedColumnStorage <double> A)
        {
            int n = A.ColumnCount;

            var ap = A.ColumnPointers;
            var ai = A.RowIndices;
            var ax = A.Values;

            int[] parent = S.parent;
            int[] P      = S.q;
            int[] Pinv   = S.pinv;

            this.D = new double[n];
            this.L = CompressedColumnStorage <double> .Create(n, n, S.cp[n]);

            Array.Copy(S.cp, L.ColumnPointers, n + 1);

            var lp = L.ColumnPointers;
            var li = L.RowIndices;
            var lx = L.Values;

            // Workspace
            var y       = new double[n];
            var pattern = new int[n];
            var flag    = new int[n];
            var lnz     = new int[n];

            double yi, l_ki;
            int    i, k, p, kk, p2, len, top;

            for (k = 0; k < n; k++)
            {
                // compute nonzero Pattern of kth row of L, in topological order
                y[k]    = 0.0;                        // Y(0:k) is now all zero
                top     = n;                          // stack for pattern is empty
                flag[k] = k;                          // mark node k as visited
                lnz[k]  = 0;                          // count of nonzeros in column k of L
                kk      = (P != null) ? (P[k]) : (k); // kth original, or permuted, column
                p2      = ap[kk + 1];
                for (p = ap[kk]; p < p2; p++)
                {
                    i = (Pinv != null) ? (Pinv[ai[p]]) : (ai[p]); // get A(i,k)
                    if (i <= k)
                    {
                        y[i] += ax[p]; // scatter A(i,k) into Y (sum duplicates)
                        for (len = 0; flag[i] != k; i = parent[i])
                        {
                            pattern[len++] = i; // L(k,i) is nonzero
                            flag[i]        = k; // mark i as visited
                        }
                        while (len > 0)
                        {
                            pattern[--top] = pattern[--len];
                        }
                    }
                }

                // compute numerical values kth row of L (a sparse triangular solve)
                D[k] = y[k]; // get D(k,k) and clear Y(k)
                y[k] = 0.0;
                for (; top < n; top++)
                {
                    i    = pattern[top]; // Pattern [top:n-1] is pattern of L(:,k)
                    yi   = y[i];         // get and clear Y(i)
                    y[i] = 0.0;
                    p2   = lp[i] + lnz[i];
                    for (p = lp[i]; p < p2; p++)
                    {
                        y[li[p]] -= lx[p] * yi;
                    }
                    l_ki  = yi / D[i]; // the nonzero entry L(k,i)
                    D[k] -= l_ki * yi;
                    li[p] = k;         // store L(k,i) in column form of L
                    lx[p] = l_ki;
                    lnz[i]++;          // increment count of nonzeros in col i
                }

                if (D[k] == 0.0)
                {
                    // failure, D(k,k) is zero
                    throw new Exception("Diagonal element is zero.");
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Sparse QR factorization [V,beta,pinv,R] = qr(A)
        /// </summary>
        protected void Factorize(CompressedColumnStorage <T> A, IProgress progress)
        {
            T zero = Helper.ZeroOf <T>();

            int i, p, p1, top, len, col;

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

            var ap = A.ColumnPointers;
            var ai = A.RowIndices;
            var ax = A.Values;

            int[] q      = S.q;
            int[] parent = S.parent;
            int[] pinv   = S.pinv;
            int   m2     = S.m2;

            int vnz = S.lnz;
            int rnz = S.unz;

            int[] leftmost = S.leftmost;

            int[] w = new int[m2 + n]; // get int workspace
            T[]   x = new T[m2];       // get double workspace

            int s = m2;                // offset into w

            // Allocate result V, R and beta
            var V = this.Q = CompressedColumnStorage <T> .Create(m2, n, vnz);

            var R = this.R = CompressedColumnStorage <T> .Create(m2, n, rnz);

            var b = this.beta = new double[n];

            var rp = R.ColumnPointers;
            var ri = R.RowIndices;
            var rx = R.Values;

            var vp = V.ColumnPointers;
            var vi = V.RowIndices;
            var vx = V.Values;

            for (i = 0; i < m2; i++)
            {
                w[i] = -1; // clear w, to mark nodes
            }

            double current = 0.0;
            double step    = n / 100.0;

            rnz = 0; vnz = 0;
            for (int k = 0; k < n; k++) // compute V and R
            {
                // Progress reporting.
                if (k >= current)
                {
                    current += step;

                    if (progress != null)
                    {
                        progress.Report(k / (double)n);
                    }
                }

                rp[k]     = rnz;      // R(:,k) starts here
                vp[k]     = p1 = vnz; // V(:,k) starts here
                w[k]      = k;        // add V(k,k) to pattern of V
                vi[vnz++] = k;
                top       = n;
                col       = q != null ? q[k] : k;
                for (p = ap[col]; p < ap[col + 1]; p++)     // find R(:,k) pattern
                {
                    i = leftmost[ai[p]];                    // i = min(find(A(i,q)))
                    for (len = 0; w[i] != k; i = parent[i]) // traverse up to k
                    {
                        //len++;
                        w[s + len++] = i;
                        w[i]         = k;
                    }
                    while (len > 0)
                    {
                        --top;
                        --len;
                        w[s + top] = w[s + len]; // push path on stack
                    }
                    i    = pinv[ai[p]];          // i = permuted row of A(:,col)
                    x[i] = ax[p];                // x (i) = A(:,col)
                    if (i > k && w[i] < k)       // pattern of V(:,k) = x (k+1:m)
                    {
                        vi[vnz++] = i;           // add i to pattern of V(:,k)
                        w[i]      = k;
                    }
                }
                for (p = top; p < n; p++)            // for each i in pattern of R(:,k)
                {
                    i = w[s + p];                    // R(i,k) is nonzero
                    ApplyHouseholder(V, i, b[i], x); // apply (V(i),Beta(i)) to x
                    ri[rnz]   = i;                   // R(i,k) = x(i)
                    rx[rnz++] = x[i];
                    x[i]      = zero;
                    if (parent[i] == k)
                    {
                        vnz = V.Scatter(i, zero, w, null, k, V, vnz);
                    }
                }
                for (p = p1; p < vnz; p++) // gather V(:,k) = x
                {
                    vx[p]    = x[vi[p]];
                    x[vi[p]] = zero;
                }
                ri[rnz]   = k;                                             // R(k,k) = norm (x)
                rx[rnz++] = CreateHouseholder(vx, p1, ref b[k], vnz - p1); // [v,beta]=house(x)
            }

            rp[n] = rnz; // finalize R
            vp[n] = vnz; // finalize V
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Creates a sparse Cholesky factorization.
 /// </summary>
 /// <param name="A">Column-compressed matrix, symmetric positive definite.</param>
 /// <param name="p">Permutation.</param>
 public static SparseCholesky Create(CompressedColumnStorage <Complex> A, int[] p)
 {
     return(Create(A, p, null));
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Compute the Numeric Cholesky factorization, L = chol (A, [pinv parent cp]).
        /// </summary>
        /// <returns>Numeric Cholesky factorization</returns>
        private void Factorize(CompressedColumnStorage <Complex> A, IProgress <double> progress)
        {
            Complex d, lki;
            int     top, i, p, k, cci;

            int n = A.ColumnCount;

            // Allocate workspace.
            var c = new int[n];
            var s = new int[n];

            var x = this.temp;

            var colp   = S.cp;
            var pinv   = S.pinv;
            var parent = S.parent;

            var C = pinv != null?PermuteSym(A, pinv, true) : A;

            var cp = C.ColumnPointers;
            var ci = C.RowIndices;
            var cx = C.Values;

            this.L = CompressedColumnStorage <Complex> .Create(n, n, colp[n]);

            var lp = L.ColumnPointers;
            var li = L.RowIndices;
            var lx = L.Values;

            for (k = 0; k < n; k++)
            {
                lp[k] = c[k] = colp[k];
            }

            double current = 0.0;
            double step    = n / 100.0;

            for (k = 0; k < n; k++) // compute L(k,:) for L*L' = C
            {
                // Progress reporting.
                if (k >= current)
                {
                    current += step;

                    if (progress != null)
                    {
                        progress.Report(k / (double)n);
                    }
                }

                // Find nonzero pattern of L(k,:)
                top  = GraphHelper.EtreeReach(SymbolicColumnStorage.Create(C, false), k, parent, s, c);
                x[k] = 0;                           // x (0:k) is now zero
                for (p = cp[k]; p < cp[k + 1]; p++) // x = full(triu(C(:,k)))
                {
                    if (ci[p] <= k)
                    {
                        x[ci[p]] = cx[p];
                    }
                }
                d    = x[k]; // d = C(k,k)
                x[k] = 0;    // clear x for k+1st iteration

                // Triangular solve
                for (; top < n; top++)       // solve L(0:k-1,0:k-1) * x = C(:,k)
                {
                    i    = s[top];           // s [top..n-1] is pattern of L(k,:)
                    lki  = x[i] / lx[lp[i]]; // L(k,i) = x (i) / L(i,i)
                    x[i] = 0;                // clear x for k+1st iteration
                    cci  = c[i];
                    for (p = lp[i] + 1; p < cci; p++)
                    {
                        x[li[p]] -= lx[p] * lki;
                    }
                    d    -= lki * Complex.Conjugate(lki); // d = d - L(k,i)*L(k,i)
                    p     = c[i]++;
                    li[p] = k;                            // store L(k,i) in column i
                    lx[p] = Complex.Conjugate(lki);
                }
                // Compute L(k,k)
                if (d.Real <= 0 || d.Imaginary != 0)
                {
                    throw new Exception(Resources.MatrixSymmetricPositiveDefinite);
                }

                p     = c[k]++;
                li[p] = k; // store L(k,k) = sqrt (d) in column k
                lx[p] = Complex.Sqrt(d);
            }
            lp[n] = colp[n]; // finalize L
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Sparse Cholesky downdate, L*L' - w*w'
 /// </summary>
 /// <param name="w">The update matrix.</param>
 /// <returns>False, if updated matrix is not positive definite, otherwise true.</returns>
 public bool Downdate(CompressedColumnStorage <Complex> w)
 {
     return(UpDown(-1, w));
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Sparse Cholesky update/downdate, L*L' + sigma*w*w'
        /// </summary>
        /// <param name="sigma">1 = update or -1 = downdate</param>
        /// <param name="w">The update matrix.</param>
        /// <returns>False, if updated matrix is not positive definite, otherwise true.</returns>
        private bool UpDown(int sigma, CompressedColumnStorage <double> w)
        {
            int    n, p, f, j;
            double alpha, gamma, w1, w2;
            double beta = 1, beta2 = 1, delta;

            var parent = symFactor.parent;

            if (parent == null)
            {
                return(false);
            }

            var lp = L.ColumnPointers;
            var li = L.RowIndices;
            var lx = L.Values;

            var cp = w.ColumnPointers;
            var ci = w.RowIndices;
            var cx = w.Values;

            n = L.ColumnCount;

            if ((p = cp[0]) >= cp[1])
            {
                return(true); // return if C empty
            }

            var work = new double[n]; // get workspace

            f = ci[p];
            for (; p < cp[1]; p++)
            {
                // f = min (find (C))
                f = Math.Min(f, ci[p]);
            }

            for (p = cp[0]; p < cp[1]; p++)
            {
                work[ci[p]] = cx[p];
            }

            // Walk path f up to root.
            for (j = f; j != -1; j = parent[j])
            {
                p     = lp[j];
                alpha = work[j] / lx[p]; // alpha = w(j) / L(j,j)
                beta2 = beta * beta + sigma * alpha * alpha;

                if (beta2 <= 0)
                {
                    break;             // TODO: not positive definite, throw?
                }
                beta2 = Math.Sqrt(beta2);
                delta = (sigma > 0) ? (beta / beta2) : (beta2 / beta);
                gamma = sigma * alpha / (beta2 * beta);
                lx[p] = delta * lx[p] + ((sigma > 0) ? (gamma * work[j]) : 0);
                beta  = beta2;

                for (p++; p < lp[j + 1]; p++)
                {
                    w1          = work[li[p]];
                    work[li[p]] = w2 = w1 - alpha * lx[p];
                    lx[p]       = delta * lx[p] + gamma * ((sigma > 0) ? w1 : w2);
                }
            }

            return(beta2 > 0);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Creates a sparse QR factorization.
 /// </summary>
 /// <param name="A">Column-compressed matrix, symmetric positive definite.</param>
 /// <param name="order">Ordering method to use (natural or A+A').</param>
 public static SparseQR Create(CompressedColumnStorage <double> A, ColumnOrdering order)
 {
     return(Create(A, order, null));
 }
Ejemplo n.º 10
0
 protected override CholmodSparse CreateSparse(CompressedColumnStorage <Complex> matrix, List <GCHandle> handles)
 {
     return(CholmodHelper.CreateSparse(matrix, Stype.General, handles));
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Convert a coordinate storage to compressed sparse column (CSC) format.
        /// </summary>
        /// <param name="storage">Coordinate storage.</param>
        /// <param name="cleanup">Remove and sum duplicate entries.</param>
        /// <param name="inplace">Do the conversion in place (re-using the coordinate storage arrays).</param>
        /// <returns>Compressed sparse column storage.</returns>
        internal static CompressedColumnStorage <T> ToCompressedColumnStorage_ <T>(CoordinateStorage <T> storage,
                                                                                   bool cleanup = true, bool inplace = false) where T : struct, IEquatable <T>, IFormattable
        {
            int nrows = storage.RowCount;
            int ncols = storage.ColumnCount;

            int nz = storage.NonZerosCount;

            var result = CompressedColumnStorage <T> .Create(nrows, ncols);

            var ap = result.ColumnPointers = new int[ncols + 1];

            if (nz == 0)
            {
                return(result);
            }

            var values = storage.Values;
            var rowind = storage.RowIndices;
            var colind = storage.ColumnIndices;

            if (inplace)
            {
                ConvertInPlace(ncols, nz, values, rowind, colind, ap);

                result.RowIndices = rowind;
                result.Values     = values;

                // Make sure the data can't be accessed through the coordinate storage.
                storage.Invalidate();
            }
            else
            {
                var columnCounts = new int[ncols];

                for (int k = 0; k < nz; k++)
                {
                    // Count columns
                    columnCounts[colind[k]]++;
                }

                // Get column pointers
                int valueCount = Helper.CumulativeSum(ap, columnCounts, ncols);

                var ai = new int[valueCount];
                var ax = new T[valueCount];

                for (int k = 0; k < nz; k++)
                {
                    int p = columnCounts[colind[k]]++;
                    ai[p] = rowind[k];
                    ax[p] = values[k];
                }

                result.RowIndices = ai;
                result.Values     = ax;
            }

            Helper.SortIndices(result);

            if (cleanup)
            {
                result.Cleanup();
            }

            return(result);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Computes the Kronecker product.
        /// </summary>
        private static CompressedColumnStorage <Complex> Kronecker(CompressedColumnStorage <Complex> A, CompressedColumnStorage <Complex> B)
        {
            var ap = A.ColumnPointers;
            var aj = A.RowIndices;
            var ax = A.Values;

            var bp = B.ColumnPointers;
            var bj = B.RowIndices;
            var bx = B.Values;

            int rowsA = A.RowCount;
            int rowsB = B.RowCount;

            var counts = new int[rowsA * rowsB];

            int k = 0;

            // Count non-zeros in each row of kron(A, B).
            for (int i = 0; i < rowsA; i++)
            {
                for (int j = 0; j < rowsB; j++)
                {
                    counts[k++] = (ap[i + 1] - ap[i]) * (bp[j + 1] - bp[j]);
                }
            }

            int colsA = A.ColumnCount;
            int colsB = B.ColumnCount;

            var C = new SparseMatrix(rowsA * rowsB, colsA * colsB);

            C.ColumnPointers = new int[colsA * colsB + 1];

            int nnz = CumulativeSum(C.ColumnPointers, counts, counts.Length);

            var cj = C.RowIndices = new int[nnz];
            var cx = C.Values = new Complex[nnz];

            k = 0;

            // For each row in A ...
            for (int ia = 0; ia < rowsA; ia++)
            {
                // ... and each row in B ...
                for (int ib = 0; ib < rowsB; ib++)
                {
                    // ... get element a_{ij}
                    for (int j = ap[ia]; j < ap[ia + 1]; j++)
                    {
                        var idx = aj[j];
                        var aij = ax[j];

                        // ... and multiply it with current row of B
                        for (int s = bp[ib]; s < bp[ib + 1]; s++)
                        {
                            cj[k] = (idx * colsB) + bj[s];
                            cx[k] = aij * bx[s];
                            k++;
                        }
                    }
                }
            }

            return(C);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Generate minimum degree ordering of A+A' (if A is symmetric) or A'A.
        /// </summary>
        /// <param name="A">Column-compressed matrix</param>
        /// <param name="order">Column ordering method</param>
        /// <returns>amd(A+A') if A is symmetric, or amd(A'A) otherwise, null on
        /// error or for natural ordering</returns>
        /// <remarks>
        /// See Chapter 7.1 (Fill-reducing orderings: Minimum degree ordering) in
        /// "Direct Methods for Sparse Linear Systems" by Tim Davis.
        /// </remarks>
        public static int[] Generate <T>(CompressedColumnStorage <T> A, ColumnOrdering order)
            where T : struct, IEquatable <T>, IFormattable
        {
            int[] Cp, Ci, P, W, nv, next, head, elen, degree, w, hhead;

            int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
                k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
                cnz, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, n;
            bool ok;
            int  h;

            n = A.ColumnCount;

            if (order == ColumnOrdering.Natural)
            {
                // TODO: return null here?
                return(Permutation.Create(n));
            }

            var C = ConstructMatrix(SymbolicColumnStorage.Create(A), order);

            Cp  = C.ColumnPointers;
            cnz = Cp[n];

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

            // add elbow room to C
            if (!C.Resize(cnz + cnz / 5 + 2 * n))
            {
                return(null);
            }

            P      = new int[n + 1]; // allocate result
            W      = new int[n + 1]; // get workspace
            w      = new int[n + 1];
            degree = new int[n + 1];

            elen = new int[n + 1]; // Initialized to 0's

            // Initialize quotient graph
            for (k = 0; k < n; k++)
            {
                W[k] = Cp[k + 1] - Cp[k];
            }
            W[n]  = 0;
            nzmax = C.RowIndices.Length;
            Ci    = C.RowIndices;

            for (i = 0; i <= n; i++)
            {
                P[i]      = -1;
                w[i]      = 1;    // node i is alive
                degree[i] = W[i]; // degree of node i
            }

            next  = new int[n + 1];
            hhead = new int[n + 1];
            head  = new int[n + 1];
            nv    = new int[n + 1];

            Array.Copy(P, next, n + 1);
            Array.Copy(P, head, n + 1);  // degree list i is empty
            Array.Copy(P, hhead, n + 1); // hash list i is empty
            Array.Copy(w, nv, n + 1);    // node i is just one node

            mark    = Clear(0, 0, w, n); // clear w
            elen[n] = -2;                // n is a dead element
            Cp[n]   = -1;                // n is a root of assembly tree
            w[n]    = 0;                 // n is a dead element

            // Initialize degree lists
            for (i = 0; i < n; i++)
            {
                d = degree[i];
                if (d == 0)       // node i is empty
                {
                    elen[i] = -2; // element i is dead
                    nel++;
                    Cp[i] = -1;   // i is a root of assembly tree
                    w[i]  = 0;
                }
                else if (d > dense)   // node i is dense
                {
                    nv[i]   = 0;      // absorb i into element n
                    elen[i] = -1;     // node i is dead
                    nel++;
                    Cp[i] = -(n + 2); // FLIP(n)
                    nv[n]++;
                }
                else
                {
                    if (head[d] != -1)
                    {
                        P[head[d]] = i;
                    }
                    next[i] = head[d]; // put node i in degree list d
                    head[d] = i;
                }
            }
            while (nel < n) // while (selecting pivots) do
            {
                // Select node of minimum approximate degree
                for (k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++)
                {
                    ;
                }
                if (next[k] != -1)
                {
                    P[next[k]] = -1;
                }
                head[mindeg] = next[k]; // remove k from degree list
                elenk        = elen[k]; // elenk = |Ek|
                nvk          = nv[k];   // # of nodes k represents
                nel         += nvk;     // nv[k] nodes of A eliminated

                // Garbage collection
                if (elenk > 0 && cnz + mindeg >= nzmax)
                {
                    for (j = 0; j < n; j++)
                    {
                        if ((p = Cp[j]) >= 0) // j is a live node or element
                        {
                            Cp[j] = Ci[p];    // save first entry of object
                            Ci[p] = -(j + 2); // first entry is now CS_FLIP(j)
                        }
                    }
                    for (q = 0, p = 0; p < cnz;)      // scan all of memory
                    {
                        if ((j = FLIP(Ci[p++])) >= 0) // found object j
                        {
                            Ci[q] = Cp[j];            // restore first entry of object
                            Cp[j] = q++;              // new pointer to object j
                            for (k3 = 0; k3 < W[j] - 1; k3++)
                            {
                                Ci[q++] = Ci[p++];
                            }
                        }
                    }
                    cnz = q; // Ci [cnz...nzmax-1] now free
                }

                // Construct new element
                dk    = 0;
                nv[k] = -nvk;                   // flag k as in Lk
                p     = Cp[k];
                pk1   = (elenk == 0) ? p : cnz; // do in place if elen[k] == 0
                pk2   = pk1;
                for (k1 = 1; k1 <= elenk + 1; k1++)
                {
                    if (k1 > elenk)
                    {
                        e  = k;            // search the nodes in k
                        pj = p;            // list of nodes starts at Ci[pj]*/
                        ln = W[k] - elenk; // length of list of nodes in k
                    }
                    else
                    {
                        e  = Ci[p++]; // search the nodes in e
                        pj = Cp[e];
                        ln = W[e];    // length of list of nodes in e
                    }
                    for (k2 = 1; k2 <= ln; k2++)
                    {
                        i = Ci[pj++];
                        if ((nvi = nv[i]) <= 0)
                        {
                            continue;     // node i dead, or seen
                        }
                        dk       += nvi;  // degree[Lk] += size of node i
                        nv[i]     = -nvi; // negate nv[i] to denote i in Lk
                        Ci[pk2++] = i;    // place i in Lk
                        if (next[i] != -1)
                        {
                            P[next[i]] = P[i];
                        }
                        if (P[i] != -1) // remove i from degree list
                        {
                            next[P[i]] = next[i];
                        }
                        else
                        {
                            head[degree[i]] = next[i];
                        }
                    }
                    if (e != k)
                    {
                        Cp[e] = -(k + 2); // absorb e into k // FLIP(k)
                        w[e]  = 0;        // e is now a dead element
                    }
                }
                if (elenk != 0)
                {
                    cnz = pk2;   // Ci [cnz...nzmax] is free
                }
                degree[k] = dk;  // external degree of k - |Lk\i|
                Cp[k]     = pk1; // element k is in Ci[pk1..pk2-1]
                W[k]      = pk2 - pk1;
                elen[k]   = -2;  // k is now an element

                // Find set differences
                mark = Clear(mark, lemax, w, n); // clear w if necessary
                for (pk = pk1; pk < pk2; pk++)   // scan 1: find |Le\Lk|
                {
                    i = Ci[pk];
                    if ((eln = elen[i]) <= 0)
                    {
                        continue;                              // skip if elen[i] empty
                    }
                    nvi  = -nv[i];                             // nv [i] was negated
                    wnvi = mark - nvi;
                    for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) // scan Ei
                    {
                        e = Ci[p];
                        if (w[e] >= mark)
                        {
                            w[e] -= nvi;             // decrement |Le\Lk|
                        }
                        else if (w[e] != 0)          // ensure e is a live element
                        {
                            w[e] = degree[e] + wnvi; // 1st time e seen in scan 1
                        }
                    }
                }

                // Degree update
                for (pk = pk1; pk < pk2; pk++) // scan2: degree update
                {
                    i  = Ci[pk];               // consider node i in Lk
                    p1 = Cp[i];
                    p2 = p1 + elen[i] - 1;
                    pn = p1;
                    for (h = 0, d = 0, p = p1; p <= p2; p++) // scan Ei
                    {
                        e = Ci[p];
                        if (w[e] != 0)          // e is an unabsorbed element
                        {
                            dext = w[e] - mark; // dext = |Le\Lk|
                            if (dext > 0)
                            {
                                d       += dext; // sum up the set differences
                                Ci[pn++] = e;    // keep e in Ei
                                h       += e;    // compute the hash of node i
                            }
                            else
                            {
                                Cp[e] = -(k + 2); // aggressive absorb. e.k // FLIP(k)
                                w[e]  = 0;        // e is a dead element
                            }
                        }
                    }
                    elen[i] = pn - p1 + 1; // elen[i] = |Ei|
                    p3      = pn;
                    p4      = p1 + W[i];
                    for (p = p2 + 1; p < p4; p++) // prune edges in Ai
                    {
                        j = Ci[p];
                        if ((nvj = nv[j]) <= 0)
                        {
                            continue;       // node j dead or in Lk
                        }
                        d       += nvj;     // degree(i) += |j|
                        Ci[pn++] = j;       // place j in node list of i
                        h       += j;       // compute hash for node i
                    }
                    if (d == 0)             // check for mass elimination
                    {
                        Cp[i]   = -(k + 2); // absorb i into k // FLIP(k)
                        nvi     = -nv[i];
                        dk     -= nvi;      // |Lk| -= |i|
                        nvk    += nvi;      // |k| += nv[i]
                        nel    += nvi;
                        nv[i]   = 0;
                        elen[i] = -1; // node i is dead
                    }
                    else
                    {
                        degree[i] = Math.Min(degree[i], d);   // update degree(i)
                        Ci[pn]    = Ci[p3];                   // move first node to end
                        Ci[p3]    = Ci[p1];                   // move 1st el. to end of Ei
                        Ci[p1]    = k;                        // add k as 1st element in of Ei
                        W[i]      = pn - p1 + 1;              // new len of adj. list of node i
                        h         = ((h < 0) ? (-h) : h) % n; // finalize hash of i
                        next[i]   = hhead[h];                 // place i in hash bucket
                        hhead[h]  = i;
                        P[i]      = h;                        // save hash of i in last[i]
                    }
                } // scan2 is done
                degree[k] = dk;                               // finalize |Lk|
                lemax     = Math.Max(lemax, dk);
                mark      = Clear(mark + lemax, lemax, w, n); // clear w

                // Supernode detection
                for (pk = pk1; pk < pk2; pk++)
                {
                    i = Ci[pk];
                    if (nv[i] >= 0)
                    {
                        continue;    // skip if i is dead
                    }
                    h        = P[i]; // scan hash bucket of node i
                    i        = hhead[h];
                    hhead[h] = -1;   // hash bucket will be empty
                    for (; i != -1 && next[i] != -1; i = next[i], mark++)
                    {
                        ln  = W[i];
                        eln = elen[i];
                        for (p = Cp[i] + 1; p <= Cp[i] + ln - 1; p++)
                        {
                            w[Ci[p]] = mark;
                        }
                        jlast = i;
                        for (j = next[i]; j != -1;)  // compare i with all j
                        {
                            ok = (W[j] == ln) && (elen[j] == eln);
                            for (p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++)
                            {
                                if (w[Ci[p]] != mark)
                                {
                                    ok = false;                   // compare i and j
                                }
                            }
                            if (ok)                     // i and j are identical
                            {
                                Cp[j]       = -(i + 2); // absorb j into i // FLIP(i)
                                nv[i]      += nv[j];
                                nv[j]       = 0;
                                elen[j]     = -1;      // node j is dead
                                j           = next[j]; // delete j from hash bucket
                                next[jlast] = j;
                            }
                            else
                            {
                                jlast = j; // j and i are different
                                j     = next[j];
                            }
                        }
                    }
                }

                // Finalize new element
                for (p = pk1, pk = pk1; pk < pk2; pk++) // finalize Lk
                {
                    i = Ci[pk];
                    if ((nvi = -nv[i]) <= 0)
                    {
                        continue;                 // skip if i is dead
                    }
                    nv[i] = nvi;                  // restore nv[i]
                    d     = degree[i] + dk - nvi; // compute external degree(i)
                    d     = Math.Min(d, n - nel - nvi);
                    if (head[d] != -1)
                    {
                        P[head[d]] = i;
                    }
                    next[i]   = head[d]; // put i back in degree list
                    P[i]      = -1;
                    head[d]   = i;
                    mindeg    = Math.Min(mindeg, d); // find new minimum degree
                    degree[i] = d;
                    Ci[p++]   = i;                   // place i in Lk
                }
                nv[k] = nvk;                         // # nodes absorbed into k
                if ((W[k] = p - pk1) == 0)           // length of adj list of element k
                {
                    Cp[k] = -1;                      // k is a root of the tree
                    w[k]  = 0;                       // k is now a dead element
                }
                if (elenk != 0)
                {
                    cnz = p;             // free unused space in Lk
                }
            }

            // Postordering
            for (i = 0; i < n; i++)
            {
                Cp[i] = -(Cp[i] + 2);                     // fix assembly tree // FLIP(Cp[i])
            }
            for (j = 0; j <= n; j++)
            {
                head[j] = -1;
            }
            for (j = n; j >= 0; j--) // place unordered nodes in lists
            {
                if (nv[j] > 0)
                {
                    continue;              // skip if j is an element
                }
                next[j]     = head[Cp[j]]; // place j in list of its parent
                head[Cp[j]] = j;
            }
            for (e = n; e >= 0; e--) // place elements in lists
            {
                if (nv[e] <= 0)
                {
                    continue;             // skip unless e is an element
                }
                if (Cp[e] != -1)
                {
                    next[e]     = head[Cp[e]]; // place e in list of its parent
                    head[Cp[e]] = e;
                }
            }
            for (k = 0, i = 0; i <= n; i++) // postorder the assembly tree
            {
                if (Cp[i] == -1)
                {
                    k = GraphHelper.TreeDepthFirstSearch(i, k, head, next, P, w);
                }
            }
            return(P);
        }
 /// <summary>
 /// Compute strongly connected components of matrix.
 /// </summary>
 /// <param name="matrix">column-compressed matrix</param>
 /// <returns>Strongly connected components</returns>
 public static StronglyConnectedComponents Generate <T>(CompressedColumnStorage <T> matrix)
     where T : struct, IEquatable <T>, IFormattable
 {
     return(Generate(SymbolicColumnStorage.Create(matrix), matrix.ColumnCount));
 }
Ejemplo n.º 15
0
 private double ComputeResidual(CompressedColumnStorage <double> A, double[] x, double[] b)
 {
     return(Helper.ComputeResidual(A, x, b));
 }
Ejemplo n.º 16
0
 /// <summary>
 /// Create CHOLMOD sparse matrix from managed type.
 /// </summary>
 /// <param name="matrix">The source matrix.</param>
 /// <param name="handles">List of handles.</param>
 /// <returns></returns>
 protected abstract CholmodSparse CreateSparse(CompressedColumnStorage <T> matrix, List <GCHandle> handles);
Ejemplo n.º 17
0
 /// <summary>
 /// Sparse Cholesky update, L*L' + w*w'
 /// </summary>
 /// <param name="w">The update matrix.</param>
 /// <returns>False, if updated matrix is not pos
 /// itive definite, otherwise true.</returns>
 public bool Update(CompressedColumnStorage <double> w)
 {
     return(UpDown(1, w));
 }
Ejemplo n.º 18
0
        /// <summary>
        /// Compute coarse and then fine Dulmage-Mendelsohn decomposition. seed
        /// optionally selects a randomized algorithm.
        /// </summary>
        /// <param name="matrix">column-compressed matrix</param>
        /// <param name="seed">0: natural, -1: reverse, random order otherwise</param>
        /// <returns>Dulmage-Mendelsohn analysis</returns>
        public static DulmageMendelsohn Generate <T>(CompressedColumnStorage <T> matrix, int seed = 0)
            where T : struct, IEquatable <T>, IFormattable
        {
            int i, j, k, cnz, nc, nb1, nb2;

            int[] Cp, ps, rs;
            bool  ok;

            // We are not interested in the actual matrix values.
            var A = SymbolicColumnStorage.Create(matrix);

            // Maximum matching
            int m = A.RowCount;
            int n = A.ColumnCount;

            var result = new DulmageMendelsohn(m, n); // allocate result

            int[] p  = result.p;
            int[] q  = result.q;
            int[] r  = result.r;
            int[] s  = result.s;
            int[] cc = result.cc;
            int[] rr = result.rr;

            int[] jimatch = MaximumMatching.Generate(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
            }
            result.BreadthFirstSearch(A, n, r, s, q, jimatch, m, 0, 1);      // find C1, R1 from C0*/
            ok = result.BreadthFirstSearch(A, m, s, r, p, jimatch, 0, m, 3); // find R3, C3 from R0*/

            if (!ok)
            {
                return(null);
            }

            result.Unmatched(n, s, q, cc, 0);                      // unmatched set C0
            result.Matched(n, s, jimatch, m, p, q, cc, rr, 1, 1);  // set R1 and C1
            result.Matched(n, s, jimatch, m, p, q, cc, rr, 2, -1); // set R2 and C2
            result.Matched(n, s, jimatch, m, p, q, cc, rr, 3, 3);  // set R3 and C3
            result.Unmatched(m, r, p, rr, 3);                      // unmatched set R0

            // Fine decomposition
            int[] pinv = Permutation.Invert(p); // pinv=p'

            var C = SymbolicColumnStorage.Create(matrix);

            A.Permute(pinv, q, C); // C=A(p,q) (it will hold A(R2,C2))

            Cp = C.ColumnPointers;
            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.Reshape(-1, nc);
            if (rr[2] - rr[1] < m) // delete rows R0, R1, and R3 from C
            {
                RowPrune(C, nc, rr);
                cnz = Cp[nc];
                int[] Ci = C.RowIndices;
                if (rr[1] > 0)
                {
                    for (k = 0; k < cnz; k++)
                    {
                        Ci[k] -= rr[1];
                    }
                }
            }
            C.Reshape(nc, -1);
            var scc = FindScc(C, nc); // 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;
            result.nb = nb2;

            // Remove unused space
            Array.Resize(ref result.r, nb2 + 1);
            Array.Resize(ref result.s, nb2 + 1);

            return(result);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Compute the Numeric Cholesky factorization, L = chol (A, [pinv parent cp]).
        /// </summary>
        /// <returns>Numeric Cholesky factorization</returns>
        private void Factorize(CompressedColumnStorage <double> A)
        {
            double d, lki;
            int    top, i, p, k;

            int n = A.ColumnCount;

            // Allocate workspace.
            var c = new int[n];
            var s = new int[n];
            var x = new double[n];

            var colp   = symFactor.cp;
            var pinv   = symFactor.pinv;
            var parent = symFactor.parent;

            var C = pinv != null?PermuteSym(A, pinv, true) : A;

            var cp = C.ColumnPointers;
            var ci = C.RowIndices;
            var cx = C.Values;

            this.L = CompressedColumnStorage <double> .Create(n, n, colp[n]);

            var lp = L.ColumnPointers;
            var li = L.RowIndices;
            var lx = L.Values;

            //var lst = new List<int>();

            var percent = 0;

            for (k = 0; k < n; k++)
            {
                lp[k] = c[k] = colp[k];
            }
            for (k = 0; k < n; k++) // compute L(k,:) for L*L' = C
            {
                if (100 * k / n != percent)
                {
                    Progress = percent = (100 * k) / n;

                    //Console.WriteLine("{0}% solve", percent);
                }

                // Find nonzero pattern of L(k,:)
                top  = GraphHelper.EtreeReach(SymbolicColumnStorage.Create(C, false), k, parent, s, c);
                x[k] = 0;                           // x (0:k) is now zero

                var tmp = cp[k + 1];
                for (p = cp[k]; p < tmp; p++) // x = full(triu(C(:,k)))
                {
                    if (ci[p] <= k)
                    {
                        x[ci[p]] = cx[p];
                    }
                }
                d    = x[k]; // d = C(k,k)
                x[k] = 0;    // clear x for k+1st iteration



                // Triangular solve
                for (; top < n; top++)       // solve L(0:k-1,0:k-1) * x = C(:,k)
                {
                    i    = s[top];           // s [top..n-1] is pattern of L(k,:)
                    lki  = x[i] / lx[lp[i]]; // L(k,i) = x (i) / L(i,i)
                    x[i] = 0;                // clear x for k+1st iteration

                    p = lp[i] + 1;

                    var cci = c[i];
                    for (p = lp[i] + 1; p < cci; p++)
                    {
                        x[li[p]] -= lx[p] * lki;
                    }



                    d    -= lki * lki; // d = d - L(k,i)*L(k,i)
                    p     = c[i]++;
                    li[p] = k;         // store L(k,i) in column i
                    lx[p] = lki;
                }
                // Compute L(k,k)
                if (d <= 0)
                {
                    throw new NotPositiveDefiniteException("not pos def"); // TODO: ex
                }

                p     = c[k]++;
                li[p] = k; // store L(k,k) = sqrt (d) in column k
                lx[p] = Math.Sqrt(d);
            }

            lp[n] = colp[n]; // finalize L
        }
Ejemplo n.º 20
0
        protected override void Solve()
        {
            InitNeuronCell();
            //if (SomaOn) { U.SetSubVector(0, myCell.vertCount, setSoma(U, myCell.somaID, vstart)); }
            int         nT;             // Number of Time steps
            List <bool> channels = new List <bool> {
                false, false, false
            };                                                                      // For adding/removing channels

            // TODO: NEED TO DO THIS BETTER
            if (HK_auto)
            {
                h = 0.1 * NeuronCell.edgeLengths.Average();
                //if (h > 0.29) { h = 0.29; }
                if (h <= 1)
                {
                    k = h / 140;
                }
                if (h <= 0.5)
                {
                    k = h / 70;
                }
                if (h <= 0.25)
                {
                    k = h / 35;
                }
                if (h <= 0.12)
                {
                    k = h / 18;
                }
                if (h <= 0.06)
                {
                    k = h / 9;
                }
                if (h <= 0.03)
                {
                    k = h / 5;
                }
            }

            // Number of time steps
            nT = (int)System.Math.Floor(endTime / k);

            // set some constants for the HINES matrix
            double diffConst = (1 / (2 * res * cap));
            double cfl       = diffConst * k / h;

            // reaction vector
            Vector        R          = Vector.Build.Dense(NeuronCell.vertCount);
            List <double> reactConst = new List <double> {
                gk, gna, gl, ek, ena, el
            };

            // temporary voltage vector
            Vector tempV = Vector.Build.Dense(NeuronCell.vertCount);

            // Construct sparse RHS and LHS in coordinate storage format, no zeros are stored
            List <CoordinateStorage <double> > sparse_stencils = makeSparseStencils(NeuronCell, h, k, diffConst);

            // Compress the sparse matrices
            CompressedColumnStorage <double> r_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[0]);  //null;

            CompressedColumnStorage <double> l_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[1]);  //null;

            // Permutation matrix----------------------------------------------------------------------//
            int[] p = new int[NeuronCell.vertCount];
            p = Permutation.Create(NeuronCell.vertCount, 0);

            CompressedColumnStorage <double> Id_csc = CompressedColumnStorage <double> .CreateDiagonal(NeuronCell.vertCount, 1);

            Id_csc.PermuteRows(p);
            //--------------------------------------------------------------------------------------------//

            // for solving Ax = b problem
            double[] b = new double[NeuronCell.vertCount];

            // Apply column ordering to A to reduce fill-in.
            //var order = ColumnOrdering.MinimumDegreeAtPlusA;

            // Create Cholesky factorization setup

            var chl = SparseCholesky.Create(l_csc, p);

            //var chl = SparseCholesky.Create(l_csc, order);
            try
            {
                for (i = 0; i < nT; i++)
                {
                    if (SomaOn)
                    {
                        U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart));
                    }
                    mutex.WaitOne();

                    r_csc.Multiply(U.ToArray(), b);             // Peform b = rhs * U_curr
                    // Diffusion solver
                    chl.Solve(b, b);

                    // Set U_next = b
                    U.SetSubVector(0, NeuronCell.vertCount, Vector.Build.DenseOfArray(b));

                    // Save voltage from diffusion step for state probabilities
                    tempV.SetSubVector(0, NeuronCell.vertCount, U);

                    // Reaction
                    channels[0] = na_ONOFF;
                    channels[1] = k_ONOFF;
                    channels[2] = leak_ONOFF;
                    R.SetSubVector(0, NeuronCell.vertCount, reactF(reactConst, U, N, M, H, channels, NeuronCell.boundaryID));
                    R.Multiply(k / cap, R);

                    // This is the solution for the voltage after the reaction is included!
                    U.Add(R, U);

                    //Now update state variables using FE on M,N,H
                    N.Add(fN(tempV, N).Multiply(k), N);
                    M.Add(fM(tempV, M).Multiply(k), M);
                    H.Add(fH(tempV, H).Multiply(k), H);

                    //Always reset to IC conditions and boundary conditions (for now)
                    U.SetSubVector(0, NeuronCell.vertCount, boundaryConditions(U, NeuronCell.boundaryID));
                    if (SomaOn)
                    {
                        U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart));
                    }
                    mutex.ReleaseMutex();
                }
            }
            catch (Exception e)
            {
                GameManager.instance.DebugLogThreadSafe(e);
            }

            GameManager.instance.DebugLogSafe("Simulation Over.");
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Sparse Cholesky update/downdate, L*L' + sigma*w*w'
        /// </summary>
        /// <param name="sigma">1 = update or -1 = downdate</param>
        /// <param name="w">The update matrix.</param>
        /// <returns>False, if updated matrix is not positive definite, otherwise true.</returns>
        private bool UpDown(int sigma, CompressedColumnStorage <Complex> w)
        {
            int     n, p, f, j;
            Complex alpha, gamma, w1, w2, phase;
            double  beta = 1, beta2 = 1, delta;

            var parent = S.parent;

            if (parent == null)
            {
                return(false);
            }

            var lp = L.ColumnPointers;
            var li = L.RowIndices;
            var lx = L.Values;

            var cp = w.ColumnPointers;
            var ci = w.RowIndices;
            var cx = w.Values;

            n = L.ColumnCount;

            if ((p = cp[0]) >= cp[1])
            {
                return(true); // return if C empty
            }

            var work = new Complex[n]; // get workspace

            f = ci[p];
            for (; p < cp[1]; p++)
            {
                // f = min (find (C))
                f = Math.Min(f, ci[p]);
            }

            for (p = cp[0]; p < cp[1]; p++)
            {
                work[ci[p]] = cx[p];
            }

            // Walk path f up to root.
            for (j = f; j != -1; j = parent[j])
            {
                p     = lp[j];
                alpha = work[j] / lx[p]; // alpha = w(j) / L(j,j)
                beta2 = beta * beta + sigma * (alpha * Complex.Conjugate(alpha)).Real;

                if (beta2 <= 0)
                {
                    break;
                }

                beta2 = Math.Sqrt(beta2);
                delta = (sigma > 0) ? (beta / beta2) : (beta2 / beta);
                gamma = sigma * Complex.Conjugate(alpha) / (beta2 * beta);
                lx[p] = delta * lx[p] + ((sigma > 0) ? (gamma * work[j]) : 0);
                beta  = beta2;

                phase  = Complex.Abs(lx[p]) / lx[p]; // phase = abs(L(j,j)) / L(j,j)
                lx[p] *= phase;                      // L(j,j) = L(j,j) * phase

                for (p++; p < lp[j + 1]; p++)
                {
                    w1          = work[li[p]];
                    work[li[p]] = w2 = w1 - alpha * lx[p];
                    lx[p]       = delta * lx[p] + gamma * ((sigma > 0) ? w1 : w2);
                    lx[p]      *= phase; // L(i,j) = L(i,j) * phase
                }
            }

            return(beta2 > 0);
        }
Ejemplo n.º 22
0
    private static void test01()

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    TEST01 tests ccs_WRITE using a tiny matrix.
    //
    //  Discussion:
    //
    //    This test uses a trivial matrix whose full representation is:
    //
    //          2  3  0  0  0
    //          3  0  4  0  6
    //      A = 0 -1 -3  2  0
    //          0  0  1  0  0
    //          0  4  2  0  1
    //
    //    The 1-based CCS representation is
    //
    //      #  ICC  CCC  ACC
    //     --  ---  ---  ---
    //      1    1    1    2
    //      2    2         3
    //
    //      3    1    3    3
    //      4    3        -1
    //      5    5         4
    //
    //      6    2    6    4
    //      7    3        -3
    //      8    4         1
    //      9    5         2
    //
    //     10    3   10    2
    //
    //     11    2   11    6
    //     12    5         1
    //
    //     13    *   13
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    18 July 2014
    //
    //  Author:
    //
    //    John Burkardt
    //
    {
        const int N   = 5;
        const int NCC = 12;

        double[] acc =
        {
            2.0,  3.0,
            3.0, -1.0, 4.0,
            4.0, -3.0, 1.0, 2.0,
            2.0,
            6.0, 1.0
        }

        ;
        int[] ccc =
        {
            1, 3, 6, 10, 11, 13
        }

        ;
        int[] icc =
        {
            1, 2,
            1, 3, 5,
            2, 3, 4, 5,
            3,
            2, 5
        }

        ;
        const string prefix = "simple";

        Console.WriteLine("");
        Console.WriteLine("TEST01");
        Console.WriteLine("  Write a sparse matrix in CCS format to 3 files.");
        //
        //  Full storage statistics
        //
        Console.WriteLine("");
        Console.WriteLine("  Full rows    M = " + N + "");
        Console.WriteLine("  Full columns N = " + N + "");
        Console.WriteLine("  Full storage   = " + N * N + "");
        //
        //  Decrement the 1-based data.
        //
        typeMethods.i4vec_dec(N + 1, ref ccc);
        typeMethods.i4vec_dec(NCC, ref icc);
        //
        //  Print the CCS matrix.
        //
        CompressedColumnStorage.ccs_print(N, N, NCC, icc, ccc, acc, "  The matrix in 0-based CCS format:");
        //
        //  Write the matrix to 3 files.
        //
        CompressedColumnStorage.ccs_write(prefix, NCC, N, icc, ccc, acc);
    }
Ejemplo n.º 23
0
        Complex[] temp; // workspace

        #region Static methods

        /// <summary>
        /// Creates a sparse Cholesky factorization.
        /// </summary>
        /// <param name="A">Column-compressed matrix, symmetric positive definite.</param>
        /// <param name="order">Ordering method to use (natural or A+A').</param>
        public static SparseCholesky Create(CompressedColumnStorage <Complex> A, ColumnOrdering order)
        {
            return(Create(A, order, null));
        }
Ejemplo n.º 24
0
        /// <summary>
        /// [L,U,pinv] = lu(A, [q lnz unz]). lnz and unz can be guess.
        /// </summary>
        private void Factorize(CompressedColumnStorage <Complex> A, double tol, IProgress <double> progress)
        {
            int[] q = S.q;

            int i;
            int lnz = S.lnz;
            int unz = S.unz;

            this.L = CompressedColumnStorage <Complex> .Create(n, n, lnz);

            this.U = CompressedColumnStorage <Complex> .Create(n, n, unz);

            this.pinv = new int[n];

            // Workspace
            var x  = this.temp;
            var xi = new int[2 * n];

            for (i = 0; i < n; i++)
            {
                // No rows pivotal yet.
                pinv[i] = -1;
            }

            lnz = unz = 0;

            int     ipiv, top, p, col;
            Complex pivot;
            double  a, t;

            int[]     li, ui;
            int[]     lp = L.ColumnPointers;
            int[]     up = U.ColumnPointers;
            Complex[] lx, ux;

            double current = 0.0;
            double step    = n / 100.0;

            // Now compute L(:,k) and U(:,k)
            for (int k = 0; k < n; k++)
            {
                // Progress reporting.
                if (k >= current)
                {
                    current += step;

                    if (progress != null)
                    {
                        progress.Report(k / (double)n);
                    }
                }

                // Triangular solve
                lp[k] = lnz; // L(:,k) starts here
                up[k] = unz; // U(:,k) starts here

                if (lnz + n > L.Values.Length)
                {
                    L.Resize(2 * L.Values.Length + n);
                }
                if (unz + n > U.Values.Length)
                {
                    U.Resize(2 * U.Values.Length + n);
                }

                li  = L.RowIndices;
                ui  = U.RowIndices;
                lx  = L.Values;
                ux  = U.Values;
                col = q != null ? (q[k]) : k;
                top = SolveSp(L, A, col, xi, x, pinv, true);  // x = L\A(:,col)

                // Find pivot
                ipiv = -1;
                a    = -1;
                for (p = top; p < n; p++)
                {
                    i = xi[p];       // x(i) is nonzero
                    if (pinv[i] < 0) // Row i is not yet pivotal
                    {
                        if ((t = Complex.Abs(x[i])) > a)
                        {
                            a    = t; // Largest pivot candidate so far
                            ipiv = i;
                        }
                    }
                    else // x(i) is the entry U(pinv[i],k)
                    {
                        ui[unz]   = pinv[i];
                        ux[unz++] = x[i];
                    }
                }

                if (ipiv == -1 || a <= 0.0)
                {
                    throw new Exception("No pivot element found.");
                }

                if (pinv[col] < 0 && Complex.Abs(x[col]) >= a * tol)
                {
                    ipiv = col;
                }

                // Divide by pivot
                pivot      = x[ipiv];     // the chosen pivot
                ui[unz]    = k;           // last entry in U(:,k) is U(k,k)
                ux[unz++]  = pivot;
                pinv[ipiv] = k;           // ipiv is the kth pivot row
                li[lnz]    = ipiv;        // first entry in L(:,k) is L(k,k) = 1
                lx[lnz++]  = 1.0;
                for (p = top; p < n; p++) // L(k+1:n,k) = x / pivot
                {
                    i = xi[p];
                    if (pinv[i] < 0)              // x(i) is an entry in L(:,k)
                    {
                        li[lnz]   = i;            // save unpermuted row in L
                        lx[lnz++] = x[i] / pivot; // scale pivot column
                    }
                    x[i] = 0.0;                   // x [0..n-1] = 0 for next k
                }
            }

            // Finalize L and U
            lp[n] = lnz;
            up[n] = unz;
            li    = L.RowIndices; // fix row indices of L for final pinv
            for (p = 0; p < lnz; p++)
            {
                li[p] = pinv[li[p]];
            }

            // Remove extra space from L and U
            L.Resize(0);
            U.Resize(0);
        }
Ejemplo n.º 25
0
 /// <summary>
 /// Apply the ith Householder vector to x.
 /// </summary>
 protected abstract bool ApplyHouseholder(CompressedColumnStorage <T> V, int i, double beta, T[] x);
Ejemplo n.º 26
0
        Complex[] temp; // workspace

        #region Static methods

        /// <summary>
        /// Creates a LU factorization.
        /// </summary>
        /// <param name="A">Column-compressed matrix, must be square.</param>
        /// <param name="order">Ordering method to use (natural or A+A').</param>
        /// <param name="tol">Partial pivoting tolerance (form 0.0 to 1.0).</param>
        public static SparseLU Create(CompressedColumnStorage <Complex> A, ColumnOrdering order,
                                      double tol)
        {
            return(Create(A, order, tol, null));
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Ordering and symbolic analysis for a LDL' factorization.
        /// </summary>
        /// <param name="order">Column ordering.</param>
        /// <param name="A">Matrix to factorize.</param>
        private void SymbolicAnalysis(ColumnOrdering order, CompressedColumnStorage <double> A)
        {
            int n = A.ColumnCount;

            var sym = this.S = new SymbolicFactorization();

            var ap = A.ColumnPointers;
            var ai = A.RowIndices;

            // P = amd(A+A') or natural
            var P    = AMD.Generate(A, order);
            var Pinv = Permutation.Invert(P);

            // Output: column pointers and elimination tree.
            var lp     = new int[n + 1];
            var parent = new int[n];

            // Workspace
            var lnz  = new int[n];
            var flag = new int[n];

            int i, k, p, kk, p2;

            for (k = 0; k < n; k++)
            {
                // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k)
                parent[k] = -1;                         // parent of k is not yet known
                flag[k]   = k;                          // mark node k as visited
                lnz[k]    = 0;                          // count of nonzeros in column k of L
                kk        = (P != null) ? (P[k]) : (k); // kth original, or permuted, column
                p2        = ap[kk + 1];
                for (p = ap[kk]; p < p2; p++)
                {
                    // A(i,k) is nonzero (original or permuted A)
                    i = (Pinv != null) ? (Pinv[ai[p]]) : (ai[p]);
                    if (i < k)
                    {
                        // follow path from i to root of etree, stop at flagged node
                        for (; flag[i] != k; i = parent[i])
                        {
                            // find parent of i if not yet determined
                            if (parent[i] == -1)
                            {
                                parent[i] = k;
                            }
                            lnz[i]++;    // L(k,i) is nonzero
                            flag[i] = k; // mark i as visited
                        }
                    }
                }
            }

            // construct Lp index array from Lnz column counts
            lp[0] = 0;
            for (k = 0; k < n; k++)
            {
                lp[k + 1] = lp[k] + lnz[k];
            }

            sym.parent = parent;
            sym.cp     = lp;
            sym.q      = P;
            sym.pinv   = Pinv;
        }
Ejemplo n.º 28
0
 /// <summary>
 /// Creates a LU factorization.
 /// </summary>
 /// <param name="A">Column-compressed matrix, must be square.</param>
 /// <param name="order">Ordering method to use (natural or A+A').</param>
 /// <param name="tol">Partial pivoting tolerance (form 0.0 to 1.0).</param>
 /// <param name="progress">Report progress (range from 0.0 to 1.0).</param>
 public static SparseLU Create(CompressedColumnStorage <Complex> A, ColumnOrdering order,
                               double tol, IProgress <double> progress)
 {
     return(Create(A, AMD.Generate(A, order), tol, progress));
 }
Ejemplo n.º 29
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CholeskySolver"/> class.
 /// </summary>
 /// <param name="a">A.</param>
 public CholeskySolver(CompressedColumnStorage a)
 {
     A = a;
 }
Ejemplo n.º 30
0
 /// <summary>
 /// Creates a LU factorization.
 /// </summary>
 /// <param name="A">Column-compressed matrix, must be square.</param>
 /// <param name="p">Fill-reducing column permutation.</param>
 /// <param name="tol">Partial pivoting tolerance (form 0.0 to 1.0).</param>
 public static SparseLU Create(CompressedColumnStorage <Complex> A, int[] p, double tol)
 {
     return(Create(A, p, tol, null));
 }