コード例 #1
0
        // ** SVD **

        public static void ExtractSingularValues(double[] a, double[] b, double[] uStore, double[] vStore, int rows, int cols)
        {
            // n is the upper limit index
            int n = cols - 1;

            int count = 0;

            while (count < 32)
            {
                // move the lower boundary up as far as we can
                while ((n > 0) && (Math.Abs(b[n - 1]) <= (2.0E-16) * Math.Abs(a[n - 1] + a[n])))
                {
                    b[n - 1] = 0.0;
                    if (a[n] < 0.0)
                    {
                        a[n] = -a[n];
                        if (vStore != null)
                        {
                            Blas1.dScal(-1.0, vStore, n * cols, 1, cols);
                        }
                    }
                    n--;
                    count = 0;
                }

                if (n == 0)
                {
                    return;
                }

                // p is the upper limit index
                // find any zeros on the diagonal and reduce the problem
                int p = n;
                while (p > 0)
                {
                    if (Math.Abs(b[p - 1]) <= (2.0E-16) * (Math.Abs(a[p]) + Math.Abs(a[p - 1])))
                    {
                        break;
                    }
                    p--;
                    // do we need a better zero test?
                    if (a[p] == 0.0)
                    {
                        //
                        ChaseBidiagonalZero(a, b, p, n, uStore, rows);
                        p++;
                        break;
                    }
                }
                // diagonal zeros will cause the Golulb-Kahn step to reproduce the same matrix,
                // and eventually we will fail with non-convergence

                GolubKahn(a, b, p, n, uStore, vStore, rows, cols);
                count++;
            }

            throw new NonconvergenceException();
        }
コード例 #2
0
        // A Householder reflection matrix is a rank-1 update to the identity.
        //   P = I - b v v^T
        // Unitarity requires b = 2 / |v|^2. To anihilate all but the first components of vector x,
        //   P x = a e_1
        // we must have
        //   v = x +/- |x| e_1
        // that is, all elements the same except the first, from which we have either added or subtracted |x|. This makes
        //   a = -/+ |x|
        // There are two way to handle the sign. One is to simply choose the sign that avoids cancelation when calculating v_1,
        // i.e. + for positive x_1 and - for negative x_1. This works fine, but makes a negative for positive x_1, which is
        // weird-looking (1 0 0 gets turned into -1 0 0). An alternative is to choose the negative sign even for positive x_1,
        // but to avoid cancelation write
        //   v_1 = x_1 - |x| = ( x_1 - |x| ) ( x_1 + |x|) / ( x_1 + |x|) = ( x_1^2 - |x|^2 ) / ( x_1 + |x| )
        //       = - ( x_2^2 + \cdots + x_n^2 ) / ( x_1 + |x| )
        // We have now moved to the second method. Note that v is the same as x except for the first element.

        public static void GenerateHouseholderReflection(double[] store, int offset, int stride, int count, out double a)
        {
            double x0 = store[offset];

            // Compute |x| and u_0.
            double xm, u0;

            if (x0 < 0.0)
            {
                xm = Blas1.dNrm2(store, offset, stride, count);
                u0 = x0 - xm;
            }
            else
            {
                // This method of computing ym and xm does incur and extra square root compared to naively computing x_2 + \cdots + x_n^2,
                // but doing it this way allows us to use dNrm2's over/under-flow prevention when we have large/small elements.
                double ym = Blas1.dNrm2(store, offset + stride, stride, count - 1);
                xm = MoreMath.Hypot(x0, ym);
                // Writing ym / (x0 + xm) * ym instead of ym * ym / (x0 + xm) prevents over/under-flow for large/small ym. Note this will
                // be 0 / 0 = NaN when xm = 0.
                u0 = -ym / (x0 + xm) * ym;
            }

            // Set result element.
            a = xm;

            // If |x| = 0 there is nothing to do; we could have done this a little earlier but the compiler requires us to set a before returning.
            if (xm == 0.0)
            {
                return;
            }

            // Set the new value of u_0
            store[offset] = u0;

            // Rescale to make b = 1.
            double um = Math.Sqrt(xm * Math.Abs(u0));

            if (um > 0.0)
            {
                Blas1.dScal(1.0 / um, store, offset, stride, count);
            }
        }
コード例 #3
0
        // on input:
        // store contains the matrix in column-major order (must have the length dimension^2)
        // permutation contains the row permutation (typically 0, 1, 2, ..., dimension - 1; must have the length dimension^2)
        // parity contains the parity of the row permutation (typically 1; must be 1 or -1)
        // dimension contains the dimension of the matrix (must be non-negative)
        // on output:
        // store is replaced by the L and U matrices, L in the lower-left triangle (with 1s along the diagonal), U in the upper-right triangle
        // permutation is replaced by the row permutation, and parity be the parity of that permutation

        // A = PLU

        public static void LUDecompose(double[] store, int[] permutation, ref int parity, int dimension)
        {
            for (int d = 0; d < dimension; d++)
            {
                int    pivotRow   = -1;
                double pivotValue = 0.0;

                for (int r = d; r < dimension; r++)
                {
                    int    a0 = dimension * d + r;
                    double t  = store[a0] - Blas1.dDot(store, r, dimension, store, dimension * d, 1, d);
                    store[a0] = t;
                    if (Math.Abs(t) > Math.Abs(pivotValue))
                    {
                        pivotRow   = r;
                        pivotValue = t;
                    }
                }

                if (pivotValue == 0.0)
                {
                    throw new DivideByZeroException();
                }

                if (pivotRow != d)
                {
                    // switch rows
                    Blas1.dSwap(store, d, dimension, store, pivotRow, dimension, dimension);
                    int t = permutation[pivotRow];
                    permutation[pivotRow] = permutation[d];
                    permutation[d]        = t;
                    parity = -parity;
                }

                Blas1.dScal(1.0 / pivotValue, store, dimension * d + d + 1, 1, dimension - d - 1);

                for (int c = d + 1; c < dimension; c++)
                {
                    double t = Blas1.dDot(store, d, dimension, store, dimension * c, 1, d);
                    store[dimension * c + d] -= t;
                }
            }
        }
コード例 #4
0
        // inverts the matrix in place
        // the in-place-ness makes this a bit confusing

        public static void GaussJordanInvert(double[] store, int dimension)
        {
            // keep track of row exchanges
            int[] ps = new int[dimension];

            // iterate over dimensions
            for (int k = 0; k < dimension; k++)
            {
                // look for a pivot in the kth column on any lower row
                int    p = k;
                double q = MatrixAlgorithms.GetEntry(store, dimension, dimension, k, k);

                for (int r = k + 1; r < dimension; r++)
                {
                    double s = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k);
                    if (Math.Abs(s) > Math.Abs(q))
                    {
                        p = r;
                        q = s;
                    }
                }
                ps[k] = p;

                // if no non-zero pivot is found, the matrix is singular and cannot be inverted
                if (q == 0.0)
                {
                    throw new DivideByZeroException();
                }

                // if the best pivot was on a lower row, swap it into the kth row
                if (p != k)
                {
                    Blas1.dSwap(store, k, dimension, store, p, dimension, dimension);
                }

                // divide the pivot row by the pivot element, so the diagonal element becomes unity
                MatrixAlgorithms.SetEntry(store, dimension, dimension, k, k, 1.0);
                Blas1.dScal(1.0 / q, store, k, dimension, dimension);

                // add factors to the pivot row to zero all off-diagonal elements in the kth column
                for (int r = 0; r < dimension; r++)
                {
                    if (r == k)
                    {
                        continue;
                    }
                    double a = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k);
                    MatrixAlgorithms.SetEntry(store, dimension, dimension, r, k, 0.0);
                    Blas1.dAxpy(-a, store, k, dimension, store, r, dimension, dimension);
                }
            }

            // unscramble exchanges
            for (int k = dimension - 1; k >= 0; k--)
            {
                int p = ps[k];
                if (p != k)
                {
                    Blas1.dSwap(store, dimension * p, 1, store, dimension * k, 1, dimension);
                }
            }
        }