예제 #1
0
 public static double[] Subtract(double[] aStore, int aOffset, int aStride, double[] bStore, int bOffset, int bStride, int dimension)
 {
     double[] store = new double[dimension];
     Blas1.dCopy(aStore, aOffset, aStride, store, 0, 1, dimension);
     Blas1.dAxpy(-1.0, bStore, bOffset, bStride, store, 0, 1, dimension);
     return(store);
 }
예제 #2
0
        public static void SortValues(double[] values, double[] utStore, double[] vStore, int rows, int cols)
        {
            // this is a selection sort, an O(N^2) sort which requires fewer swaps than an insertion sort or an O(N ln N) sort

            // loop over ranks
            for (int i = 0; i < cols; i++)
            {
                // find the next largest value
                int    j = i;
                double t = values[i];
                for (int k = i + 1; k < cols; k++)
                {
                    if (values[k] > t)
                    {
                        j = k;
                        t = values[k];
                    }
                }

                // if necessary swap it with the current element
                if (j != i)
                {
                    Global.Swap(ref values[i], ref values[j]);
                    if (utStore != null)
                    {
                        Blas1.dSwap(utStore, i, rows, utStore, j, rows, rows);
                    }
                    if (vStore != null)
                    {
                        Blas1.dSwap(vStore, i * cols, 1, vStore, j * cols, 1, cols);
                    }
                }
            }
        }
예제 #3
0
 public static void SolveLowerLeftTriangular(double[] tStore, double[] x, int xOffset, int dimension)
 {
     for (int r = 0; r < dimension; r++)
     {
         double t = Blas1.dDot(tStore, r, dimension, x, xOffset, 1, r);
         x[xOffset + r] -= t;
     }
 }
예제 #4
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();
        }
예제 #5
0
 public static void SolveUpperRightTriangular(double[] tStore, double[] x, int xOffset, int dimension)
 {
     for (int r = dimension - 1; r >= 0; r--)
     {
         int    i0 = dimension * r + r;
         double t  = Blas1.dDot(tStore, i0 + dimension, dimension, x, xOffset + r + 1, 1, dimension - r - 1);
         x[xOffset + r] = (x[xOffset + r] - t) / tStore[i0];
     }
 }
예제 #6
0
 /// <summary>
 /// Gets the U factor.
 /// </summary>
 /// <returns>The upper-right triangular factor U of the LU decomposition.</returns>
 public SquareMatrix UMatrix()
 {
     double[] uStore = new double[dimension * dimension];
     for (int c = 0; c < dimension; c++)
     {
         Blas1.dCopy(luStore, dimension * c, 1, uStore, dimension * c, 1, c + 1);
     }
     return(new SquareMatrix(uStore, dimension));
 }
예제 #7
0
 /// <inheritdoc />
 public override ColumnVector Column(int c)
 {
     if ((c < 0) || (c >= cols))
     {
         throw new ArgumentOutOfRangeException(nameof(c));
     }
     double[] cStore = new double[rows];
     Blas1.dCopy(store, offset + colStride * c, rowStride, cStore, 0, 1, rows);
     return(new ColumnVector(cStore, rows));
 }
예제 #8
0
 /// <inheritdoc />
 public override RowVector Row(int r)
 {
     if ((r < 0) || (r >= rows))
     {
         throw new ArgumentOutOfRangeException(nameof(r));
     }
     double[] rStore = new double[cols];
     Blas1.dCopy(store, offset + rowStride * r, colStride, rStore, 0, 1, cols);
     return(new RowVector(rStore, cols));
 }
예제 #9
0
        // Apply a Householder transfrom defined by v to the vector x (which may be
        // a column of a matrix, if H is applied from the left, or a row of a matrix
        // if H is applied from the right). On exit v is unchanged, x is changed.
        // We have H = I - \beta v v^T, so H x = x - (\beta v^T x) v.

        public static void ApplyHouseholderReflection(
            double[] uStore, int uOffset, int uStride,
            double[] yStore, int yOffset, int yStride,
            int count
            )
        {
            double s = Blas1.dDot(uStore, uOffset, uStride, yStore, yOffset, yStride, count);

            Blas1.dAxpy(-s, uStore, uOffset, uStride, yStore, yOffset, yStride, count);
        }
예제 #10
0
 /// <summary>
 /// Multiplies a complex column vector by a complex constant.
 /// </summary>
 /// <param name="alpha">The complex constant.</param>
 /// <param name="v">The complex column vector.</param>
 /// <returns>The product &#x3B1;v.</returns>
 /// <exception cref="ArgumentNullException"><paramref name="v"/> is null.</exception>
 public static ComplexColumnVector operator *(Complex alpha, ComplexColumnVector v)
 {
     if (v == null)
     {
         throw new ArgumentNullException(nameof(v));
     }
     Complex[] product = new Complex[v.dimension];
     Blas1.zAxpy(alpha, v.store, v.offset, 1, product, 0, 1, v.dimension);
     return(new ComplexColumnVector(product, 0, v.dimension, false));
 }
예제 #11
0
 /// <summary>
 /// Gets the L factor.
 /// </summary>
 /// <returns>The lower-left triangular factor L of the LU decomposition.</returns>
 /// <remarks>
 /// <para>The pivoted LU decomposition algorithm guarantees that the diagonal entries of this matrix are all one, and
 /// that the magnitudes of the sub-diagonal entries are all less than or equal to one.</para>
 /// </remarks>
 public SquareMatrix LMatrix()
 {
     double[] lStore = new double[dimension * dimension];
     for (int c = 0; c < dimension; c++)
     {
         int i0 = dimension * c + c;
         lStore[i0] = 1.0;
         Blas1.dCopy(luStore, i0 + 1, 1, lStore, i0 + 1, 1, dimension - c - 1);
     }
     return(new SquareMatrix(lStore, dimension));
 }
예제 #12
0
 private static void SwapIndexes(double[] aStore, int[] perm, int dimension, int p, int q)
 {
     if (p == q)
     {
         return;
     }
     Blas1.dSwap(aStore, p, dimension, aStore, q, dimension, dimension);
     Blas1.dSwap(aStore, dimension * p, 1, aStore, dimension * q, 1, dimension);
     if (perm != null)
     {
         Global.Swap <int>(ref perm[p], ref perm[q]);
     }
 }
예제 #13
0
        public static double OneNorm(double[] store, int offset, int rowStride, int colStride, int nRows, int nColumns)
        {
            double norm = 0.0;

            for (int c = 0; c < nColumns; c++)
            {
                double csum = Blas1.dNrm1(store, offset + colStride * c, rowStride, nRows);
                if (csum > norm)
                {
                    norm = csum;
                }
            }
            return(norm);
        }
예제 #14
0
        public static double InfinityNorm(double[] store, int offset, int rowStride, int colStride, int nRows, int nColumns)
        {
            double norm = 0.0;

            for (int r = 0; r < nRows; r++)
            {
                double rsum = Blas1.dNrm1(store, offset + rowStride * r, colStride, nColumns);
                if (rsum > norm)
                {
                    norm = rsum;
                }
            }
            return(norm);
        }
예제 #15
0
        // Solve a triangular system
        //   aIsUpper indicates whether A is upper/right or lower/left
        //   aIsUnit indicates whether A's diagonal elements are all 1 or not
        // The relevent elements of xStore are overwritten by the solution vector

        public static void dTrsv(
            bool aIsUpper, bool aIsUnit, double[] aStore, int aOffset, int aRowStride, int aColStride,
            double[] xStore, int xOffset, int xStride,
            int count
            )
        {
            int aDiagonalStride = aColStride + aRowStride;

            // If A is upper triangular, start at the bottom/right and reverse the direction of progression.
            // This does not affect the passed in variables because integers are pass-by-value.
            if (aIsUpper)
            {
                aOffset         = aOffset + (count - 1) * aDiagonalStride;
                aRowStride      = -aRowStride;
                aColStride      = -aColStride;
                aDiagonalStride = -aDiagonalStride;
                xOffset         = xOffset + (count - 1) * xStride;
                xStride         = -xStride;
            }

            // The index of the first row element to be subtracted in the numerator.
            int aRowIndex = aOffset;
            // The index of the x element to be solved for.
            int xIndex = xOffset;

            // We hoist the aIsUnit test outside the loop and pay the cost of a little repeated code in
            // order to avoid an unnecessary per-loop test. It's possible the compiler could do this for us.
            if (aIsUnit)
            {
                for (int n = 0; n < count; n++)
                {
                    xStore[xIndex] -= Blas1.dDot(aStore, aRowIndex, aColStride, xStore, xOffset, xStride, n);
                    aRowIndex      += aRowStride;
                    xIndex         += xStride;
                }
            }
            else
            {
                int aDiagonalIndex = aOffset;
                for (int n = 0; n < count; n++)
                {
                    xStore[xIndex] -= Blas1.dDot(aStore, aRowIndex, aColStride, xStore, xOffset, xStride, n);
                    xStore[xIndex] /= aStore[aDiagonalIndex];
                    aRowIndex      += aRowStride;
                    aDiagonalIndex += aDiagonalStride;
                    xIndex         += xStride;
                }
            }
        }
예제 #16
0
        /// <summary>
        /// Sort the eigenvalues as specified.
        /// </summary>
        /// <param name="order">The desired ordering.</param>
        public void Sort(OrderBy order)
        {
            // Create an auxiluary array of indexes to sort
            int[] ranks = new int[dimension];
            for (int i = 0; i < ranks.Length; i++)
            {
                ranks[i] = i;
            }

            // Sort indexes in the requested order
            Comparison <int> comparison;

            switch (order)
            {
            case OrderBy.ValueAscending:
                comparison = (int a, int b) => eigenvalues[a].CompareTo(eigenvalues[b]);
                break;

            case OrderBy.ValueDescending:
                comparison = (int a, int b) => eigenvalues[b].CompareTo(eigenvalues[a]);
                break;

            case OrderBy.MagnitudeAscending:
                comparison = (int a, int b) => Math.Abs(eigenvalues[a]).CompareTo(Math.Abs(eigenvalues[b]));
                break;

            case OrderBy.MagnitudeDescending:
                comparison = (int a, int b) => Math.Abs(eigenvalues[b]).CompareTo(Math.Abs(eigenvalues[a]));
                break;

            default:
                throw new NotSupportedException();
            }
            Array.Sort(ranks, comparison);

            // Create new storage in the desired order and discard the old storage
            // This is faster than moving within existing storage since we can move each column just once.
            double[] newEigenvalues        = new double[dimension];
            double[] newEigenvectorStorage = new double[dimension * dimension];
            for (int i = 0; i < ranks.Length; i++)
            {
                newEigenvalues[i] = eigenvalues[ranks[i]];
                Blas1.dCopy(eigenvectorStorage, dimension * ranks[i], 1, newEigenvectorStorage, dimension * i, 1, dimension);
            }
            eigenvalues        = newEigenvalues;
            eigenvectorStorage = newEigenvectorStorage;
        }
예제 #17
0
        // y <- A x + y

        public static void dGemv(
            double[] aStore, int aOffset, int aRowStride, int aColStride,
            double[] xStore, int xOffset, int xStride,
            double[] yStore, int yOffset, int yStride,
            int rows, int cols
            )
        {
            int aIndex = aOffset;
            int yIndex = yOffset;

            for (int n = 0; n < rows; n++)
            {
                yStore[yIndex] += Blas1.dDot(aStore, aIndex, aColStride, xStore, xOffset, xStride, cols);
                aIndex         += aRowStride;
                yIndex         += yStride;
            }
        }
예제 #18
0
        /// <summary>
        /// Computes the inner (scalar or dot) product of a row and a column vector.
        /// </summary>
        /// <param name="v">The row vector.</param>
        /// <param name="u">The column vector.</param>
        /// <returns>The value of the scalar product.</returns>
        public static double operator *(RowVector v, ColumnVector u)
        {
            if (v == null)
            {
                throw new ArgumentNullException(nameof(v));
            }
            if (u == null)
            {
                throw new ArgumentNullException(nameof(u));
            }
            if (v.dimension != u.dimension)
            {
                throw new DimensionMismatchException();
            }
            double p = Blas1.dDot(v.store, v.offset, v.stride, u.store, u.offset, u.stride, v.dimension);

            return(p);
        }
예제 #19
0
 public static double[] Copy(double[] store, int offset, int rowStride, int colStride, int nRows, int nCols)
 {
     double[] copyStore = AllocateStorage(nRows, nCols);
     if ((rowStride == 1) && (colStride == nRows))
     {
         Array.Copy(store, offset, copyStore, 0, copyStore.Length);
     }
     else
     {
         for (int c = 0; c < nCols; c++)
         {
             int sourceIndex = offset + colStride * c;
             int copyIndex   = nRows * c;
             Blas1.dCopy(store, sourceIndex, rowStride, copyStore, copyIndex, 1, nRows);
         }
     }
     return(copyStore);
 }
예제 #20
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;
                }
            }
        }
예제 #21
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);
            }
        }
예제 #22
0
        public static void SolveUpperRightTriangular(double[] tStore, int tRows, int tCols, double[] xStore, int xOffset)
        {
            Debug.Assert(tRows >= tCols);
            // pre-calculate some useful quantities
            int trp1 = tRows + 1;
            int tcm1 = tCols - 1;
            // initialize the x index (to its highest value) the the diagonal t index (to its highest value)
            int xIndex = xOffset + tcm1;
            int tIndex = trp1 * tcm1;

            // do the first, trivial back-substitution
            xStore[xIndex] /= tStore[tIndex];
            // do the remaining back-substitutions, each of which requires subtracting n previously computed x-values
            for (int n = 1; n <= tcm1; n++)
            {
                xIndex -= 1;
                tIndex -= trp1;
                double t = Blas1.dDot(tStore, tIndex + tRows, tRows, xStore, xIndex + 1, 1, n);
                xStore[xIndex] = (xStore[xIndex] - t) / tStore[tIndex];
            }
        }
예제 #23
0
 public static double[] Copy(double[] store, int offset, int stride, int dimension)
 {
     double[] copy = new double[dimension];
     Blas1.dCopy(store, offset, stride, copy, 0, 1, dimension);
     return(copy);
 }
예제 #24
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);
                }
            }
        }
예제 #25
0
 void ICollection <double> .CopyTo(double[] array, int arrayIndex)
 {
     Blas1.dCopy(store, offset, stride, array, arrayIndex, 1, dimension);
 }
예제 #26
0
 /// <summary>
 /// Computes the magnitude of the vector.
 /// </summary>
 /// <returns>The Euclidean norm of the vector.</returns>
 public virtual double Norm()
 {
     return(Blas1.dNrm2(store, offset, stride, dimension));
 }
예제 #27
0
 /// <summary>
 /// Returns a copy of the complex column vector.
 /// </summary>
 /// <returns>An independent copy of the complex column vector.</returns>
 public ComplexColumnVector Copy()
 {
     Complex[] copy = new Complex[dimension];
     Blas1.Copy(store, offset, 1, copy, 0, 1, dimension);
     return(new ComplexColumnVector(copy, 0, dimension, false));
 }
예제 #28
0
 public static double[] Multiply(double alpha, double[] store, int offset, int stride, int dimension)
 {
     double[] product = new double[dimension];
     Blas1.dAxpy(alpha, store, offset, stride, product, 0, 1, dimension);
     return(product);
 }