示例#1
0
 /// <summary>
 /// Computes the product of two square matrices.
 /// </summary>
 /// <param name="A">The first matrix.</param>
 /// <param name="B">The second matrix.</param>
 /// <returns>The product <paramref name="A"/> * <paramref name="B"/>.</returns>
 /// <remarks>
 /// <para>Note that matrix multiplication is not commutative, i.e. M1*M2 is generally not the same as M2*M1.</para>
 /// <para>Matrix multiplication is an O(N<sup>3</sup>) process.</para>
 /// </remarks>
 /// <exception cref="ArgumentNullException"><paramref name="A"/> or <paramref name="B"/> is <see langword="null"/>.</exception>
 /// <exception cref="DimensionMismatchException">The dimension of <paramref name="A"/> is not the same as the dimension of <paramref name="B"/>.</exception>
 public static SquareMatrix operator *(SquareMatrix A, SquareMatrix B)
 {
     // this is faster than the base operator, because it knows about the underlying structure
     if (A == null)
     {
         throw new ArgumentNullException(nameof(A));
     }
     if (B == null)
     {
         throw new ArgumentNullException(nameof(B));
     }
     if (A.dimension != B.dimension)
     {
         throw new DimensionMismatchException();
     }
     double[] abStore = MatrixAlgorithms.Multiply(
         A.store, A.offset, A.rowStride, A.colStride,
         B.store, B.offset, B.rowStride, B.colStride,
         A.dimension, A.dimension, A.dimension
         );
     return(new SquareMatrix(abStore, A.dimension));
 }
示例#2
0
 /// <summary>
 /// Multiplies two real, rectangular matrices.
 /// </summary>
 /// <param name="A">The first matrix.</param>
 /// <param name="B">The second matrix.</param>
 /// <returns>The product matrix AB.</returns>
 public static RectangularMatrix operator *(RectangularMatrix A, RectangularMatrix B)
 {
     // This is faster than the base operator, because it knows about the underlying storage structure
     if (A == null)
     {
         throw new ArgumentNullException(nameof(A));
     }
     if (B == null)
     {
         throw new ArgumentNullException(nameof(B));
     }
     if (A.cols != B.rows)
     {
         throw new DimensionMismatchException();
     }
     double[] abStore = MatrixAlgorithms.Multiply(
         A.store, A.offset, A.rowStride, A.colStride,
         B.store, B.offset, B.rowStride, B.colStride,
         A.rows, A.cols, B.cols
         );
     return(new RectangularMatrix(abStore, A.rows, B.cols));
 }
示例#3
0
 /// <summary>
 /// Returns the transpose of the matrix.
 /// </summary>
 /// <returns>M<sup>T</sup></returns>
 public RectangularMatrix Transpose()
 {
     double[] tStore = MatrixAlgorithms.Transpose(store, rows, cols);
     return(new RectangularMatrix(tStore, cols, rows));
 }
示例#4
0
 /// <summary>
 /// Computes the inverse of the matrix.
 /// </summary>
 /// <returns>The matrix inverse M<sup>-1</sup>.</returns>
 /// <remarks>
 /// <para>The inverse of a matrix M is a matrix M<sup>-1</sup> such that M<sup>-1</sup>M = I, where I is the identity matrix.</para>
 /// <para>If the matrix is singular, inversion is not possible. In that case, this method will fail with a <see cref="DivideByZeroException"/>.</para>
 /// <para>The inversion of a matrix is an O(N<sup>3</sup>) operation.</para>
 /// </remarks>
 /// <exception cref="DivideByZeroException">The matrix is singular.</exception>
 public SquareMatrix Inverse()
 {
     double[] iStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension);
     SquareMatrixAlgorithms.GaussJordanInvert(iStore, dimension);
     return(new SquareMatrix(iStore, dimension));
 }
示例#5
0
 /// <summary>
 /// Copies the matrix.
 /// </summary>
 /// <returns>An independent copy of the matrix.</returns>
 public SquareMatrix Copy()
 {
     double[] copyStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension);
     return(new SquareMatrix(copyStore, dimension));
 }
示例#6
0
 /// <inheritdoc />
 public override double OneNorm()
 {
     return(MatrixAlgorithms.OneNorm(store, offset, rowStride, colStride, dimension, dimension));
 }
        // EIGENVALUE ALGORITHMS

        //

        public static Complex[] ReduceToRealSchurForm(double[] aStore, double[] qStore, int dimension)
        {
            // keep track of eigenvalues
            Complex[] eigenvalues = new Complex[dimension];

            // keep track of interations
            int count = 0;

            // isolate the upper and lower boundaries of the curent subproblem
            // p is the upper index, n the lower index

            int n = dimension - 1;

            while (n >= 0)
            {
                // move up the matrix from endpoint n, looking for subdiagonal elements negligible compared to the neighboring diagonal elements
                // if we find one, that reduces the problem to the submatrix between p and n
                int p = n;
                while (p > 0)
                {
                    double d = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1));
                    double e = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p - 1));

                    if (d + e == d)
                    {
                        //  double f = d * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p) - MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1));
                        //  double g = e * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p));

                        //  if (f + g == f) {
                        MatrixAlgorithms.SetEntry(aStore, dimension, dimension, p, p - 1, 0.0);
                        break;
                        //  }
                    }

                    p--;
                }

                /*
                 * if (p == n) {
                 *  // one eigenvalue
                 *  // reduce n and re-set count
                 * } else {
                 *  // compute m, matrix elements
                 *  // reduce n and re-set count
                 *  if (p == m) {
                 *      // two eigenvalues
                 *  } else {
                 *      // do step
                 *  }
                 * }
                 */

                //Print(a, dimension, p, n);

                // get the (indexes for) the entries in the trailing 2x2 matrix
                int m    = n - 1;
                int ammi = MatrixAlgorithms.GetIndex(dimension, dimension, m, m);
                int amni = MatrixAlgorithms.GetIndex(dimension, dimension, m, n);
                int anmi = MatrixAlgorithms.GetIndex(dimension, dimension, n, m);
                int anni = MatrixAlgorithms.GetIndex(dimension, dimension, n, n);

                if (n - p > 1)
                {
                    count++;
                    if (count > 32)
                    {
                        throw new NonconvergenceException();
                    }

                    double tr  = aStore[ammi] + aStore[anni];
                    double det = aStore[ammi] * aStore[anni] - aStore[amni] * aStore[anmi];

                    // ad hoc shift
                    if ((count == 8) || (count == 16) || (count == 24))
                    {
                        double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) +
                                   Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n - 1, n - 2));
                        tr  = 2.0 * w;
                        det = w * w;
                    }

                    FrancisTwoStep(aStore, qStore, dimension, p, n, tr, det);
                }
                else
                {
                    if (p == n)
                    {
                        eigenvalues[n] = aStore[anni];
                    }
                    else if (p == m)
                    {
                        double sn, cn;
                        TwoByTwoRealSchur(ref aStore[ammi], ref aStore[amni], ref aStore[anmi], ref aStore[anni], out sn, out cn, out eigenvalues[m], out eigenvalues[n]);

                        // Multiply A from left by the rotation matrix R
                        for (int cc = p + 2; cc < dimension; cc++)
                        {
                            int    i = MatrixAlgorithms.GetIndex(dimension, dimension, p, cc);
                            int    j = MatrixAlgorithms.GetIndex(dimension, dimension, p + 1, cc);
                            double t = aStore[i];
                            aStore[i] = cn * t + sn * aStore[j];
                            aStore[j] = cn * aStore[j] - sn * t;
                        }
                        // Multiply A from the right by R^T
                        for (int rr = 0; rr < p; rr++)
                        {
                            int    i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p);
                            int    j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1);
                            double t = aStore[i];
                            aStore[i] = cn * t + sn * aStore[j];
                            aStore[j] = cn * aStore[j] - sn * t;
                        }
                        // Multiply Q^T from the left by R
                        if (qStore != null)
                        {
                            for (int rr = 0; rr < dimension; rr++)
                            {
                                int    i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p);
                                int    j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1);
                                double t = qStore[i];
                                qStore[i] = cn * t + sn * qStore[j];
                                qStore[j] = cn * qStore[j] - sn * t;
                            }
                        }
                    }

                    n     = p - 1;
                    count = 0;
                }
            }

            return(eigenvalues);
        }
示例#8
0
        // simple specific operations

        /// <summary>
        /// Copies the matrix.
        /// </summary>
        /// <returns>An indpendent copy of the matrix.</returns>
        public RectangularMatrix Copy()
        {
            double[] cStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, rows, cols);
            return(new RectangularMatrix(cStore, rows, cols));
        }
示例#9
0
 /// <summary>
 /// Copies the matrix.
 /// </summary>
 /// <returns>An independent copy of the matrix.</returns>
 public SquareMatrix Copy()
 {
     double[] cStore = MatrixAlgorithms.Copy(store, dimension, dimension);
     return(new SquareMatrix(cStore, dimension));
 }
示例#10
0
 /// <inheritdoc />
 public override double InfinityNorm()
 {
     return(MatrixAlgorithms.InfinityNorm(store, 0, 1, dimension, dimension, dimension));
 }
示例#11
0
 /// <inheritdoc />
 public override double OneNorm()
 {
     return(MatrixAlgorithms.OneNorm(store, 0, 1, dimension, dimension, dimension));
 }
        public static void SchurEigensystem(double[] aStore, int n, out Complex[] eigenvalues, out Complex[][] eigenvectors)
        {
            eigenvalues  = new Complex[n];
            eigenvectors = new Complex[n][];

            int i = n - 1;

            while (i >= 0)
            {
                // find the eigenvector corresponding to the ith eigenvalue

                if ((i == 0) || (MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1) == 0.0))
                {
                    // We have no sub-diagonal element on the ith row. Since
                    //  (XXXXX) ( X )   ( X )
                    //  (XXXXX) ( X )   ( X )
                    //  (  aXX) ( 1 ) = ( a )
                    //  (   XX) ( 0 )   ( 0 )
                    //  (   XX) ( 0 )   ( 0 )
                    // a vector with v[i] = 1, v[j > i] = 0, and v[j < i] properly chosen will be an eigenvector.

                    // the eigenvalue is the ith diagonal element
                    double e = MatrixAlgorithms.GetEntry(aStore, n, n, i, i);

                    // we take the ith component of the eigenvector to be one; higher components must be zero
                    Complex[] v = new Complex[n];
                    v[i] = 1.0;

                    CompleteEigenvector(aStore, n, v, e, i, i - 1);
                    //WriteTransformedEigenvector(i, e, v, n, Q);
                    eigenvectors[i] = v;
                    eigenvalues[i]  = e;

                    i--;
                }
                else
                {
                    // We have a 2x2 sub-block
                    //   ( X X X )
                    //   (  [X X])
                    //   (  [X X])
                    // Find its eigenvalues

                    Complex e1, e2;
                    TwoByTwoEigenvalues(
                        MatrixAlgorithms.GetEntry(aStore, n, n, i - 1, i - 1),
                        MatrixAlgorithms.GetEntry(aStore, n, n, i - 1, i),
                        MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1),
                        MatrixAlgorithms.GetEntry(aStore, n, n, i, i),
                        out e1, out e2
                        );
                    //TwoByTwoEigenvalues(a[i - 1, i - 1], a[i - 1, i], a[i, i - 1], a[i, i], out e1, out e2);

                    // For each eigenvalue, compute the trailing eigenvector components and then the remaining components.
                    // For the trailing components, since
                    //   (a11 a12) ( v1 ) = \lambda ( v1 )
                    //   (a21 a22) ( v2 )           ( v2 )
                    // It follows that
                    //   v1 = (\lambda - a22) / a21 * v2
                    // and we normalize by choosing v2 = 1. Since we are only here if a21 != 0, there is no danger of
                    // dividing by zero, but there may well be a danger that (\lambda - a22) looses significant
                    // precision due to cancelation.

                    Complex[] v = new Complex[n];
                    v[i] = 1.0;
                    //v[i - 1] = (e1 - a[i, i]) / a[i, i - 1];
                    v[i - 1] = (e1 - MatrixAlgorithms.GetEntry(aStore, n, n, i, i)) / MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1);
                    CompleteEigenvector(aStore, n, v, e1, i, i - 2);
                    //WriteTransformedEigenvector(i, e1, v, n, Q);
                    eigenvectors[i] = v;
                    eigenvalues[i]  = e1;

                    v    = new Complex[n];
                    v[i] = 1.0;
                    //v[i - 1] = (e2 - a[i, i]) / a[i, i - 1];
                    v[i - 1] = (e2 - MatrixAlgorithms.GetEntry(aStore, n, n, i, i)) / MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1);
                    CompleteEigenvector(aStore, n, v, e2, i, i - 2);
                    //WriteTransformedEigenvector(i - 1, e2, v, n, Q);
                    eigenvectors[i - 1] = v;
                    eigenvalues[i - 1]  = e2;

                    i -= 2;
                }
            }
        }
        // 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);
                }
            }
        }
        public static Complex[] ExtractEigenvalues(double[] aStore, double[] qStore, int dimension)
        {
            int count = 0;

            // keep track of extracted eigenvalues
            Complex[] lambdas = new Complex[dimension];

            double sum_old = Double.PositiveInfinity;

            int n = dimension - 1;

            while (n >= 0)
            {
                //Write(aStore, dimension, dimension);

                // find the lowest decoupled, unreduced block
                int    a   = n;
                double sum = 0.0;
                while (a > 0)
                {
                    double f = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a)) +
                               Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a - 1, a - 1));
                    double e = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a - 1);
                    if ((f + e) == f)
                    {
                        MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a - 1, 0.0);
                        break;
                    }
                    sum += Math.Abs(e);
                    a--;
                }

                /*
                 * Console.WriteLine("count = {0}", count);
                 * double[] qt = MatrixAlgorithms.Transpose(qStore, dimension, dimension);
                 * double[] qa = MatrixAlgorithms.Multiply(qStore, dimension, dimension, aStore, dimension, dimension);
                 * double[] qaqt = MatrixAlgorithms.Multiply(qa, dimension, dimension, qt, dimension, dimension);
                 * MatrixAlgorithms.PrintMatrix(qaqt, dimension, dimension);
                 */

                // check for maximum numbers of iterations without finding an eigenvalue
                if (count > 32)
                {
                    throw new NonconvergenceException();
                }

                // we are working between a and n, and our block is at least 3 wide

                // reduce if possible, otherwise do a iteration step

                if (a == n)
                {
                    // 1 X 1 block isolated
                    lambdas[a] = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a);
                    n         -= 1;
                    count      = 0;
                    sum_old    = Double.PositiveInfinity;
                }
                else if (a == (n - 1))
                {
                    // 2 X 2 block isolated
                    double Aaa = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a);
                    double Aba = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a);
                    double Aab = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a + 1);
                    double Abb = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a + 1);
                    // eigenvalues are given by the quadratic formula
                    //   e = \frac{a_11 + a22}{2} \pm q
                    // descriminant q^2 = ( \frac{a_11 - a_22}{2} )^2 + a_21 a_1
                    double c  = (Aaa + Abb) / 2.0;
                    double d  = Aaa * Abb - Aba * Aab;
                    double q2 = c * c - d;
                    if (q2 >= 0.0)
                    {
                        // eigenvalues are real

                        double q = Math.Sqrt(q2);
                        if (c >= 0.0)
                        {
                            lambdas[a] = c + q;
                        }
                        else
                        {
                            lambdas[a] = c - q;
                        }
                        // i tried to do this as c + Math.Sign(c) * q, but when c = 0, Math.Sign(c) = 0, not 1
                        lambdas[a + 1] = d / lambdas[a];

                        /*
                         * double sn, cn;
                         * TwoByTwoSchur(ref Aaa, ref Aab, ref Aba, ref Abb, out sn, out cn);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a, Aaa);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a + 1, Aab);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a, Aba);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a + 1, Abb);
                         *
                         * // Multiply A from left by the rotation matrix R
                         * for (int cc = a + 2; cc < dimension; cc++) {
                         *  int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc);
                         *  int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc);
                         *  double t = aStore[i];
                         *  aStore[i] = cn * t + sn * aStore[j];
                         *  aStore[j] = cn * aStore[j] - sn * t;
                         * }
                         * // Multiply A from the right by R^T
                         * for (int rr = 0; rr < a; rr++) {
                         *  int i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a);
                         *  int j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a + 1);
                         *  double t = aStore[i];
                         *  aStore[i] = cn * t + sn * aStore[j];
                         *  aStore[j] = cn * aStore[j] - sn * t;
                         * }
                         * // Multiply Q^T from the left by R
                         * if (qStore != null) {
                         *  for (int cc = 0; cc < dimension; cc++) {
                         *      int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc);
                         *      int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc);
                         *      double t = qStore[i];
                         *      qStore[i] = cn * t + sn * qStore[j];
                         *      qStore[j] = cn * qStore[j] - sn * t;
                         *  }
                         * }
                         *
                         * lambdas[a] = Aaa;
                         * lambdas[a + 1] = Abb;
                         */
                    }
                    else
                    {
                        double q = Math.Sqrt(-q2);
                        lambdas[a]     = new Complex(c, q);
                        lambdas[a + 1] = new Complex(c, -q);
                    }

                    n      -= 2;
                    count   = 0;
                    sum_old = Double.PositiveInfinity;
                }
                else
                {
                    // use the lower-left 2 X 2 matrix to generate an approximate eigenvalue pair

                    int    m   = n - 1;
                    double Amm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m);
                    double Amn = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, n);
                    double Anm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, m);
                    double Ann = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n);

                    // the trace of this 2 X 2 matrix is the sum of its eigenvalues, and its determinate is their product

                    double tr  = Amm + Ann;
                    double det = Amm * Ann - Amn * Anm;

                    // ad hoc shift
                    if ((count == 8) || (count == 16) || (count == 24))
                    {
                        double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) +
                                   Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m - 1));
                        tr  = 2.0 * w;
                        det = w * w;
                    }

                    FrancisTwoStep(aStore, qStore, dimension, a, n, tr, det);
                    sum_old = sum;
                    count++;
                }
            }

            return(lambdas);
        }
示例#15
0
 /// <inheritdoc />
 public override double InfinityNorm()
 {
     return(MatrixAlgorithms.InfinityNorm(store, offset, rowStride, colStride, rows, cols));
 }
示例#16
0
        /*
         * IMatrix IMatrix.Clone () {
         *  return (Clone());
         * }
         */

        /// <summary>
        /// Creates a transpose of the matrix.
        /// </summary>
        /// <returns>The matrix transpose M<sup>T</sup>.</returns>
        public SquareMatrix Transpose()
        {
            double[] tStore = MatrixAlgorithms.Transpose(store, dimension, dimension);
            return(new SquareMatrix(tStore, dimension));
        }
 /// <summary>
 /// The orthogonal matrix Q.
 /// </summary>
 /// <returns>The orthogonal matrix Q.</returns>
 public SquareMatrix QMatrix()
 {
     double[] qStore = MatrixAlgorithms.Transpose(qtStore, dimension, dimension);
     return(new SquareMatrix(qStore, dimension));
 }
示例#18
0
 /// <summary>
 /// Returns the transpose of the matrix.
 /// </summary>
 /// <returns>M<sup>T</sup></returns>
 public RectangularMatrix Transpose()
 {
     // Just copy with rows <-> columns to get transpose
     double[] transpose = MatrixAlgorithms.Copy(store, offset, colStride, rowStride, cols, rows);
     return(new RectangularMatrix(transpose, cols, rows));
 }
 /// <summary>
 /// Returns the left transform matrix.
 /// </summary>
 /// <returns>The matrix U, such that A = U S V<sup>T</sup>.</returns>
 public SquareMatrix LeftTransformMatrix()
 {
     double[] left = MatrixAlgorithms.Transpose(utStore, rows, rows);
     return(new SquareMatrix(left, rows));
 }