Example #1
0
        // more complicated operations: also O(N^3)

        // QR decomposition write A = Q R, where Q is orthogonal (Q^T = Q^{-1}) and R is upper-right triangular.

        // Given a QR decomposition, it is easy to solve Ax=b by writing (QR)x=b, Q(Rx)=b, Rx=y and Qy=b.
        // Then y = Q^T b (an N^2 multiplication) and R x = y is a triangular system (also N^2 to solve).

        // To form a QR decomposition, we apply householder reflections to zero each column in turn.

        // XXXXX    ABCDE    XXXXX    XXXXX    XXXXX    XXXXX
        // XXXXX    0BCDE    0ABCD    0XXXX    0XXXX    0XXXX
        // XXXXX    0BCDE    00BCD    00ABC    00XXX    00XXX
        // XXXXX -> 0BCDE -> 00BCD -> 000BC -> 000AB -> 000XX
        // XXXXX    0BCDE    00BCD    000BC    0000B    0000A
        // XXXXX    0BCDE    00BCD    000BC    0000B    00000
        // XXXXX    0BCDE    00BCD    000BC    0000B    00000

        // This gives us (Q_N \cdots Q_2 Q_1) A = R, so A = (Q_N \cdots Q_2 Q_1)^T R = (Q_1^T Q_2^T \cdots Q_N^T) R

        public static void QRDecompose(double[] store, double[] qtStore, int rows, int cols)
        {
            // loop over columns
            for (int k = 0; k < cols; k++)
            {
                int    offset = rows * k + k;
                int    length = rows - k;
                double a;
                VectorAlgorithms.GenerateHouseholderReflection(store, offset, 1, length, out a);

                // apply P to the other columns of A
                for (int c = k + 1; c < cols; c++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(store, offset, 1, store, rows * c + k, 1, length);
                }

                // apply P to Q to accumulate the transform
                // since Q is rows X rows, its column count is just rows
                for (int c = 0; c < rows; c++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(store, offset, 1, qtStore, rows * c + k, 1, length);
                }

                // we are done with the Householder vector now, so we can zero the first column
                store[offset] = a;
                for (int i = 1; i < length; i++)
                {
                    store[offset + i] = 0.0;
                }
            }
        }
Example #2
0
 /// <summary>
 /// Divides a row vector by a real, scalar constant.
 /// </summary>
 /// <param name="alpha">The real, scalar constant.</param>
 /// <param name="v">The row vector.</param>
 /// <returns>The result.</returns>
 public static RowVector operator /(RowVector v, double alpha)
 {
     if (v == null)
     {
         throw new ArgumentNullException(nameof(v));
     }
     double[] store = VectorAlgorithms.Multiply(1.0 / alpha, v.store, v.offset, v.stride, v.dimension);
     return(new RowVector(store, v.dimension));
 }
Example #3
0
 /// <summary>
 /// Multiplies a column vector by a real, scalar constant.
 /// </summary>
 /// <param name="alpha">The real, scalar constant.</param>
 /// <param name="v">The column vector.</param>
 /// <returns>The product &#x3B1;v.</returns>
 public static ColumnVector operator *(double alpha, ColumnVector v)
 {
     if (v == null)
     {
         throw new ArgumentNullException(nameof(v));
     }
     double[] store = VectorAlgorithms.Multiply(alpha, v.store, v.offset, v.stride, v.dimension);
     return(new ColumnVector(store, v.dimension));
 }
Example #4
0
 public static double[] AccumulateBidiagonalV(double[] store, int rows, int cols)
 {
     //  Q_1 * ... (Q_{n-1} * (Q_n * 1))
     double[] result = SquareMatrixAlgorithms.CreateUnitMatrix(cols);
     for (int k = cols - 2; k >= 0; k--)
     {
         // apply Householder reflection to each column from the left
         for (int j = k + 1; j < cols; j++)
         {
             VectorAlgorithms.ApplyHouseholderReflection(store, (k + 1) * rows + k, rows, result, j * cols + (k + 1), 1, cols - k - 1);
         }
     }
     return(result);
 }
        // The reduction to Hessenberg form via a similiarity transform proceeds as follows. A Householder reflection can
        // zero the non-Householder elements in the first column. Since this is a similiarity transform, we have to apply
        // it from the other side as well. The letters indicate which elements are mixed by each transform.

        // XXXXX    XXXXX    XFFFF
        // XXXXX    ABCDE    AGGGG
        // XXXXX -> 0BCDE -> 0HHHH
        // XXXXX    0BCDE    0IIII
        // XXXXX    0BCDE    0JJJJ

        // Note that if we had tried to zero all the subdiagonal elements, rather than just the (sub+1)-diagonal elements, then the
        // applicaion of the Householder reflection from the other side would have messed with our zeros. But because we only tried
        // for Hessenberg, not upper-right-triangular, form, our zeros are safe. We then do it again for the next column.

        // XXXXX    XXXXX    XXEEE
        // XXXXX    XXXXX    XXFFF
        // 0XXXX -> 0ABCD -> 0AGGG
        // 0XXXX    00BCD    00HHH
        // 0XXXX    00BCD    00III

        // And so on until we are done.

        public static void ReduceToHessenberg(double[] aStore, double[] vStore, int dim)
        {
            int dm2 = dim - 2;

            for (int k = 0; k < dm2; k++)
            {
                // determine a Householder reflection to zero the (sub+1)-diagonal elements of the current column
                int    offset = dim * k + (k + 1);
                int    length = dim - (k + 1);
                double a;
                VectorAlgorithms.GenerateHouseholderReflection(aStore, offset, 1, length, out a);

                // determine P * A
                for (int c = k + 1; c < dim; c++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(aStore, offset, 1, aStore, dim * c + (k + 1), 1, length);
                }
                // determine A * P
                for (int r = 0; r < dim; r++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(aStore, offset, 1, aStore, dim * (k + 1) + r, dim, length);
                }

                // if we are keeping track of the transformation, determine V * P
                if (vStore != null)
                {
                    for (int r = 0; r < dim; r++)
                    {
                        VectorAlgorithms.ApplyHouseholderReflection(aStore, offset, 1, vStore, dim * (k + 1) + r, dim, length);
                    }
                }

                // We are done with our Householder vector, so we can overwrite the space we were using for it with the values produced by
                // the reflection.
                aStore[offset] = a;
                for (int i = 1; i < length; i++)
                {
                    aStore[offset + i] = 0.0;
                }
                //aStore[dim * k + (k + 1)] = a;
                //for (int i = k + 2; i < dim; i++) {
                //    MatrixAlgorithms.SetEntry(aStore, dim, dim, i, k, 0.0);
                //}
                // Not having done this earlier is not a problem because the values in that column do not come into play when computing
                // the effects of the transform on the other entries, i.e. it doesn't "mix" with the other entries
            }
        }
Example #6
0
 /// <summary>
 /// Computes the difference of two column vectors.
 /// </summary>
 /// <param name="v1">The first column vector.</param>
 /// <param name="v2">The second column vector.</param>
 /// <returns>The difference <paramref name="v1"/> - <paramref name="v2"/>.</returns>
 public static RowVector operator -(RowVector v1, RowVector v2)
 {
     if (v1 == null)
     {
         throw new ArgumentNullException(nameof(v1));
     }
     if (v2 == null)
     {
         throw new ArgumentNullException(nameof(v2));
     }
     if (v1.dimension != v2.dimension)
     {
         throw new DimensionMismatchException();
     }
     double[] store = VectorAlgorithms.Subtract(v1.store, v1.offset, v1.stride, v2.store, v2.offset, v2.stride, v1.dimension);
     return(new RowVector(store, v1.dimension));
 }
Example #7
0
        public static double[] AccumulateBidiagonalU(double[] store, int rows, int cols)
        {
            // ((1 *  Q_n) * Q_{n-1}) ... * Q_1
            double[] result = SquareMatrixAlgorithms.CreateUnitMatrix(rows);

            // iterate over Householder reflections
            for (int k = cols - 1; k >= 0; k--)
            {
                // apply Householder reflection to each row from the right
                for (int j = k; j < rows; j++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(store, k * rows + k, 1, result, k * rows + j, rows, rows - k);
                }
            }

            return(result);
        }
Example #8
0
 /// <summary>
 /// Computes the sum of two column vectors.
 /// </summary>
 /// <param name="v1">The first column vector.</param>
 /// <param name="v2">The second column vector.</param>
 /// <returns>The sum <paramref name="v1"/> + <paramref name="v2"/>.</returns>
 public static ColumnVector operator +(ColumnVector v1, ColumnVector v2)
 {
     if (v1 == null)
     {
         throw new ArgumentNullException("v1");
     }
     if (v2 == null)
     {
         throw new ArgumentNullException("v2");
     }
     if (v1.dimension != v2.dimension)
     {
         throw new DimensionMismatchException();
     }
     double[] store = VectorAlgorithms.Add(v1.store, v1.offset, v1.stride, v2.store, v2.offset, v2.stride, v1.dimension);
     return(new ColumnVector(store, v1.dimension));
 }
Example #9
0
        // SVD

        // Bidiagonalization uses seperate left and right Householder reflections to bring a matrix into a form of bandwidth two.

        // XXXXX    ABCDE    XA000    XX000    XX000
        // XXXXX    0BCDE    0BBBB    0ABCD    0XA00
        // XXXXX    0BCDE    0CCCC    00BCD    00BBB
        // XXXXX -> 0BCDE -> 0DDDD -> 00BCD -> 00CCC -> etc
        // XXXXX    0BCDE    0EEEE    00BCD    00DDD
        // XXXXX    0BCDE    0FFFF    00BCD    00EEE
        // XXXXX    0BCDE    0GGGG    00BCD    00FFF

        // The end result is B = U A V, where U and V are different (so this isn't a similiarity transform) orthogonal matrices.

        // Note that we can't get fully diagonal with this approach, because if the right transform tried to zero the first superdiagonal
        // element, it would interfere with the zeros already created.

        // The reslting diagonal and first superdiagonal elements are returned in a and b. The matrix itself is gradually
        // overwritten with the elements of the Householder reflections used. When we are done
        // the matrix is replaced by Householder vector components as follows:

        // APPPP
        // ABQQQ
        // ABCRR
        // ABCDS
        // ABCDE
        // ABCDE

        // where A, B, C, D, E are the Householder reflections applied from the left to zero columns, and P, Q, R, S are
        // the Householder reflections applied from the right to zero rows.

        public static void Bidiagonalize(double[] store, int rows, int cols, out double[] a, out double[] b)
        {
            // This logic is written assuming more rows than columns. If not, bidiagonalize the transpose.
            Debug.Assert(rows >= cols);

            // Allocate space for the diagonal and superdiagonal.
            a = new double[cols];
            b = new double[cols - 1];


            for (int k = 0; k < cols; k++)
            {
                // generate a householder reflection which, when applied from the left, will zero sub-diagonal elements in the kth column
                // use those elements to store the reflection vector; store the resulting diagonal element seperately
                VectorAlgorithms.GenerateHouseholderReflection(store, rows * k + k, 1, rows - k, out a[k]);

                // apply that reflection to all the columns; only subsequent ones are affected since preceeding ones
                // contain only zeros in the subdiagonal rows
                for (int c = k + 1; c < cols; c++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(store, rows * k + k, 1, store, rows * c + k, 1, rows - k);
                }

                if ((k + 1) < cols)
                {
                    // generate a Householder reflection which, when applied from the right, will zero (super+1)-diagonal elements in the kth row
                    // again, store the elements of the reflection vector in the zeroed matrix elements and store the resulting superdiagonal element seperately
                    VectorAlgorithms.GenerateHouseholderReflection(store, rows * (k + 1) + k, rows, cols - (k + 1), out b[k]);

                    // apply the reflection to all the rows; only subsequent ones are affected since the preceeding ones contain only zeros in the
                    // affected columns; the already-zeroed column elements are not distrubed because those columns are not affected
                    // this restriction is why we cannot fully diagonalize using this transform
                    for (int r = k + 1; r < rows; r++)
                    {
                        VectorAlgorithms.ApplyHouseholderReflection(store, rows * (k + 1) + k, rows, store, rows * (k + 1) + r, rows, cols - (k + 1));
                    }
                }
            }
        }
Example #10
0
 /// <summary>
 /// Returns a copy of the row vector.
 /// </summary>
 /// <returns>An independent copy of the row vector.</returns>
 public RowVector Copy()
 {
     double[] copy = VectorAlgorithms.Copy(store, offset, stride, dimension);
     return(new RowVector(copy, dimension));
 }
Example #11
0
 /// <summary>
 /// Returns the transpose of the row vector.
 /// </summary>
 /// <returns>An independent column vector with the same components as the row vector.</returns>
 public ColumnVector Transpose()
 {
     double[] copy = VectorAlgorithms.Copy(store, offset, stride, dimension);
     return(new ColumnVector(copy, dimension));
 }
Example #12
0
 /// <summary>
 /// Returns the vector elements in an independent array.
 /// </summary>
 /// <returns>An array containing the vector element values.</returns>
 public virtual new double[] ToArray()
 {
     return(VectorAlgorithms.Copy(store, offset, stride, dimension));
 }
        private static void FrancisTwoStep(double[] aStore, double[] qStore, int dimension, int a, int n, double sum, double product)
        {
            // to apply the implicit Q theorem, get the first column of what (A - mu I)(A - mu* I) would be
            double[] v = GenerateFirstColumn(aStore, dimension, a, n, sum, product);

            int d = n - a + 1;

            Debug.Assert(d >= 3);

            // generate a householder reflection for this column, and apply it to the matrix
            double e;

            VectorAlgorithms.GenerateHouseholderReflection(v, 0, 1, 3, out e);

            // determine P * A
            for (int c = a; c < dimension; c++)
            {
                VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * c + a, 1, 3);
            }
            // determine A * P
            for (int r = 0; r <= Math.Min(a + 3, n); r++)
            {
                VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * a + r, dimension, 3);
            }
            // determine Q * P
            if (qStore != null)
            {
                for (int r = 0; r < dimension; r++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, qStore, dimension * a + r, dimension, 3);
                }
            }

            //Write(aStore, dimension, dimension);

            // The matrix now looks like this:
            // XXXXXX    ABCDEF    AAAXXX
            // XXXXXX    ABCDEF    BBBXXX
            // 0XXXXX -> ABCDEF -> CCCXXX
            // 00XXXX    00XXXX    DDDXXX
            // 000XXX    000XXX    000XXX
            // 0000XX    0000XX    0000XX
            // Note there are three non-Hessenberg elements. These constitute a "bulge". Now "chase the bulge" down the matrix, using
            // Householder relfections to zero the non-Hessenberg elements of each column in turn.

            for (int k = a; k <= (n - 3); k++)
            {
                // determine the required Householder reflection
                v[0] = aStore[dimension * k + (k + 1)];
                v[1] = aStore[dimension * k + (k + 2)];
                v[2] = aStore[dimension * k + (k + 3)];
                VectorAlgorithms.GenerateHouseholderReflection(v, 0, 1, 3, out e);

                //v = GenerateHouseholderReflection(aStore, dimension * k + k + 1, 1, 3);

                // determine P * A and A * P
                aStore[dimension * k + (k + 1)] = e;
                aStore[dimension * k + (k + 2)] = 0.0;
                aStore[dimension * k + (k + 3)] = 0.0;
                for (int c = k + 1; c < dimension; c++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * c + (k + 1), 1, 3);
                }
                for (int r = 0; r < Math.Max(k + 4, dimension); r++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * (k + 1) + r, dimension, 3);
                }
                // if tracking eigenvalues, determine Q * P
                if (qStore != null)
                {
                    for (int r = 0; r < dimension; r++)
                    {
                        VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, qStore, dimension * (k + 1) + r, dimension, 3);
                    }
                }
            }

            //Write(aStore, dimension, dimension);

            // restoring Householder form in the last column requires only a length-2 Householder reflection
            // a Givens rotation would be another possibility here
            int l = n - 2;

            v[0] = aStore[dimension * l + (l + 1)];
            v[1] = aStore[dimension * l + (l + 2)];
            VectorAlgorithms.GenerateHouseholderReflection(v, 0, 1, 2, out e);
            aStore[dimension * l + (l + 1)] = e;
            aStore[dimension * l + (l + 2)] = 0.0;
            for (int c = l + 1; c < dimension; c++)
            {
                VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * c + (l + 1), 1, 2);
            }
            for (int r = 0; r <= n; r++)
            {
                VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, aStore, dimension * (l + 1) + r, dimension, 2);
            }
            if (qStore != null)
            {
                for (int r = 0; r < dimension; r++)
                {
                    VectorAlgorithms.ApplyHouseholderReflection(v, 0, 1, qStore, dimension * (l + 1) + r, dimension, 2);
                }
            }
            //double cos, sin;
            //GenerateGivensRotation(ref aStore[dimension * l + l + 1], ref aStore[dimension * l + l + 2], out cos, out sin);
        }