Beispiel #1
0
        /// <summary>
        /// Creates the eigenvalue decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">The square matrix A.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="matrixA"/> is non-square (rectangular).
        /// </exception>
        public EigenvalueDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            {
                throw new ArgumentNullException("matrixA");
            }
            if (matrixA.IsSquare == false)
            {
                throw new ArgumentException("The matrix A must be square.", "matrixA");
            }

            _n = matrixA.NumberOfColumns;
            _d = new VectorF(_n);
            _e = new VectorF(_n);

            _isSymmetric = matrixA.IsSymmetric;

            if (_isSymmetric)
            {
                _v = matrixA.Clone();

                // Tridiagonalize.
                ReduceToTridiagonal();

                // Diagonalize.
                TridiagonalToQL();
            }
            else
            {
                _v = new MatrixF(_n, _n);

                // Abort if A contains NaN values.
                // If we continue with NaN values, we run into an infinite loop.
                for (int i = 0; i < _n; i++)
                {
                    for (int j = 0; j < _n; j++)
                    {
                        if (Numeric.IsNaN(matrixA[i, j]))
                        {
                            _e.Set(float.NaN);
                            _v.Set(float.NaN);
                            _d.Set(float.NaN);
                            return;
                        }
                    }
                }

                // Storage of nonsymmetric Hessenberg form.
                MatrixF matrixH = matrixA.Clone();
                // Working storage for nonsymmetric algorithm.
                float[] ort = new float[_n];

                // Reduce to Hessenberg form.
                ReduceToHessenberg(matrixH, ort);

                // Reduce Hessenberg to real Schur form.
                HessenbergToRealSchur(matrixH);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Creates the QR decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">
        /// The matrix A. (Can be rectangular. NumberOfRows must be ≥ NumberOfColumns.)
        /// </param>
        /// <remarks>
        /// The QR decomposition is computed by Householder reflections.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows must be greater than or equal to the number of columns.
        /// </exception>
        public QRDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            {
                throw new ArgumentNullException("matrixA");
            }
            if (matrixA.NumberOfRows < matrixA.NumberOfColumns)
            {
                throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");
            }

            // Initialize.
            _qr        = matrixA.Clone();
            _m         = matrixA.NumberOfRows;
            _n         = matrixA.NumberOfColumns;
            _rDiagonal = new float[_n];

            // Main loop.
            for (int k = 0; k < _n; k++)
            {
                // Compute 2-norm of k-th column without under/overflow.
                float norm = 0;
                for (int i = k; i < _m; i++)
                {
                    norm = MathHelper.Hypotenuse(norm, _qr[i, k]);
                }

                if (norm != 0) // TODO: Maybe a comparison with an epsilon tolerance is required here!?
                {
                    // Form k-th Householder vector.
                    if (_qr[k, k] < 0)
                    {
                        norm = -norm;
                    }
                    for (int i = k; i < _m; i++)
                    {
                        _qr[i, k] /= norm;
                    }
                    _qr[k, k] += 1;

                    // Apply transformation to remaining columns.
                    for (int j = k + 1; j < _n; j++)
                    {
                        float s = 0;
                        for (int i = k; i < _m; i++)
                        {
                            s += _qr[i, k] * _qr[i, j];
                        }
                        s = -s / _qr[k, k];
                        for (int i = k; i < _m; i++)
                        {
                            _qr[i, j] += s * _qr[i, k];
                        }
                    }
                }
                _rDiagonal[k] = -norm;
            }
        }
        //--------------------------------------------------------------
        /// <summary>
        /// Creates the eigenvalue decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">The square matrix A.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="matrixA"/> is non-square (rectangular).
        /// </exception>
        public EigenvalueDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            throw new ArgumentNullException("matrixA");
              if (matrixA.IsSquare == false)
            throw new ArgumentException("The matrix A must be square.", "matrixA");

              _n = matrixA.NumberOfColumns;
              _d = new VectorF(_n);
              _e = new VectorF(_n);

              _isSymmetric = matrixA.IsSymmetric;

              if (_isSymmetric)
              {
            _v = matrixA.Clone();

            // Tridiagonalize.
            ReduceToTridiagonal();

            // Diagonalize.
            TridiagonalToQL();
              }
              else
              {
            _v = new MatrixF(_n, _n);

            // Abort if A contains NaN values.
            // If we continue with NaN values, we run into an infinite loop.
            for (int i = 0; i < _n; i++)
            {
              for (int j = 0; j < _n; j++)
              {
            if (Numeric.IsNaN(matrixA[i, j]))
            {
              _e.Set(float.NaN);
              _v.Set(float.NaN);
              _d.Set(float.NaN);
              return;
            }
              }
            }

            // Storage of nonsymmetric Hessenberg form.
            MatrixF matrixH = matrixA.Clone();
            // Working storage for nonsymmetric algorithm.
            float[] ort = new float[_n];

            // Reduce to Hessenberg form.
            ReduceToHessenberg(matrixH, ort);

            // Reduce Hessenberg to real Schur form.
            HessenbergToRealSchur(matrixH);
              }
        }
Beispiel #4
0
        /// <summary>
        /// Returns the least squares solution for the equation <c>A * X = B</c>.
        /// </summary>
        /// <param name="matrixB">The matrix B with as many rows as A and any number of columns.</param>
        /// <returns>X with the least squares solution.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixB"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows does not match.
        /// </exception>
        /// <exception cref="MathematicsException">
        /// The matrix A does not have full rank.
        /// </exception>
        public MatrixF SolveLinearEquations(MatrixF matrixB)
        {
            if (matrixB == null)
            {
                throw new ArgumentNullException("matrixB");
            }
            if (matrixB.NumberOfRows != _m)
            {
                throw new ArgumentException("The number of rows does not match.", "matrixB");
            }
            if (HasNumericallyFullRank == false)
            {
                throw new MathematicsException("The matrix does not have full rank.");
            }

            // Copy right hand side
            MatrixF x = matrixB.Clone();

            // Compute Y = transpose(Q)*B
            for (int k = 0; k < _n; k++)
            {
                for (int j = 0; j < matrixB.NumberOfColumns; j++)
                {
                    float s = 0;
                    for (int i = k; i < _m; i++)
                    {
                        s += _qr[i, k] * x[i, j];
                    }
                    s = -s / _qr[k, k];
                    for (int i = k; i < _m; i++)
                    {
                        x[i, j] += s * _qr[i, k];
                    }
                }
            }
            // Solve R*X = Y.
            for (int k = _n - 1; k >= 0; k--)
            {
                for (int j = 0; j < matrixB.NumberOfColumns; j++)
                {
                    x[k, j] /= _rDiagonal[k];
                }
                for (int i = 0; i < k; i++)
                {
                    for (int j = 0; j < matrixB.NumberOfColumns; j++)
                    {
                        x[i, j] -= x[k, j] * _qr[i, k];
                    }
                }
            }
            return(x.GetSubmatrix(0, _n - 1, 0, matrixB.NumberOfColumns - 1));
        }
        /// <summary>
        /// Solves the equation <c>A * X = B</c>.
        /// </summary>
        /// <param name="matrixB">The matrix B with as many rows as A and any number of columns.</param>
        /// <returns>X, so that <c>A * X = B</c>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixB"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows does not match.
        /// </exception>
        /// <exception cref="MathematicsException">
        /// The matrix A is not symmetric and positive definite.
        /// </exception>
        public MatrixF SolveLinearEquations(MatrixF matrixB)
        {
            if (matrixB == null)
            {
                throw new ArgumentNullException("matrixB");
            }
            if (matrixB.NumberOfRows != L.NumberOfRows)
            {
                throw new ArgumentException("The number of rows does not match.", "matrixB");
            }
            if (IsSymmetricPositiveDefinite == false)
            {
                throw new MathematicsException("The original matrix A is not symmetric and positive definite.");
            }

            // Initialize x as a copy of B.
            MatrixF x = matrixB.Clone();

            // Solve L*Y = B.
            for (int k = 0; k < L.NumberOfRows; k++)
            {
                for (int j = 0; j < matrixB.NumberOfColumns; j++)
                {
                    for (int i = 0; i < k; i++)
                    {
                        x[k, j] -= x[i, j] * L[k, i];
                    }
                    x[k, j] /= L[k, k];
                }
            }

            // Solve transpose(L) * X = Y.
            for (int k = L.NumberOfRows - 1; k >= 0; k--)
            {
                for (int j = 0; j < matrixB.NumberOfColumns; j++)
                {
                    for (int i = k + 1; i < L.NumberOfRows; i++)
                    {
                        x[k, j] -= x[i, j] * L[i, k];
                    }
                    x[k, j] /= L[k, k];
                }
            }
            return(x);
        }
Beispiel #6
0
        //--------------------------------------------------------------
        /// <summary>
        /// Creates the QR decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">
        /// The matrix A. (Can be rectangular. NumberOfRows must be ≥ NumberOfColumns.)
        /// </param>
        /// <remarks>
        /// The QR decomposition is computed by Householder reflections.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows must be greater than or equal to the number of columns.
        /// </exception>
        public QRDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            throw new ArgumentNullException("matrixA");
              if (matrixA.NumberOfRows < matrixA.NumberOfColumns)
            throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");

              // Initialize.
              _qr = matrixA.Clone();
              _m = matrixA.NumberOfRows;
              _n = matrixA.NumberOfColumns;
              _rDiagonal = new float[_n];

              // Main loop.
              for (int k = 0; k < _n; k++)
              {
            // Compute 2-norm of k-th column without under/overflow.
            float norm = 0;
            for (int i = k; i < _m; i++)
              norm = MathHelper.Hypotenuse(norm, _qr[i, k]);

            if (norm != 0)   // TODO: Maybe a comparison with an epsilon tolerance is required here!?
            {
              // Form k-th Householder vector.
              if (_qr[k, k] < 0)
            norm = -norm;
              for (int i = k; i < _m; i++)
            _qr[i, k] /= norm;
              _qr[k, k] += 1;

              // Apply transformation to remaining columns.
              for (int j = k + 1; j < _n; j++)
              {
            float s = 0;
            for (int i = k; i < _m; i++)
              s += _qr[i, k] * _qr[i, j];
            s = -s / _qr[k, k];
            for (int i = k; i < _m; i++)
              _qr[i, j] += s * _qr[i, k];
              }
            }
            _rDiagonal[k] = -norm;
              }
        }
Beispiel #7
0
        public void Absolute()
        {
            float[] values = new float[] { -1.0f, -2.0f, -3.0f,
                                     -4.0f, -5.0f, -6.0f,
                                     -7.0f, -8.0f, -9.0f };
              MatrixF m = new MatrixF(3, 3, values, MatrixOrder.RowMajor);

              MatrixF absolute = m.Clone();
              absolute.Absolute();
              for (int i = 0; i < absolute.NumberOfRows; i++)
            for (int j = 0; j < absolute.NumberOfColumns; j++)
              Assert.AreEqual(i * absolute.NumberOfColumns + j + 1, absolute[i, j]);

              absolute = MatrixF.Absolute(m);
              for (int i = 0; i < absolute.NumberOfRows; i++)
            for (int j = 0; j < absolute.NumberOfColumns; j++)
              Assert.AreEqual(i * absolute.NumberOfColumns + j + 1, absolute[i, j]);

              values = new float[] { 1.0f, 2.0f, 3.0f,
                             4.0f, 5.0f, 6.0f,
                             7.0f, 8.0f, 9.0f };
              m = new MatrixF(3, 3, values, MatrixOrder.RowMajor);

              absolute = m.Clone();
              absolute.Absolute();
              for (int i = 0; i < absolute.NumberOfRows; i++)
            for (int j = 0; j < absolute.NumberOfColumns; j++)
              Assert.AreEqual(i * absolute.NumberOfColumns + j + 1, absolute[i, j]);

              absolute = MatrixF.Absolute(m);
              for (int i = 0; i < absolute.NumberOfRows; i++)
            for (int j = 0; j < absolute.NumberOfColumns; j++)
              Assert.AreEqual(i * absolute.NumberOfColumns + j + 1, absolute[i, j]);

              Assert.IsNull(MatrixF.Absolute(null));
        }
Beispiel #8
0
        //--------------------------------------------------------------
        /// <summary>
        /// Returns the least squares solution for the equation <c>A * X = B</c>.
        /// </summary>
        /// <param name="matrixB">The matrix B with as many rows as A and any number of columns.</param>
        /// <returns>X with the least squares solution.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixB"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows does not match.
        /// </exception>
        /// <exception cref="MathematicsException">
        /// The matrix A does not have full rank.
        /// </exception>
        public MatrixF SolveLinearEquations(MatrixF matrixB)
        {
            if (matrixB == null)
            throw new ArgumentNullException("matrixB");
              if (matrixB.NumberOfRows != _m)
            throw new ArgumentException("The number of rows does not match.", "matrixB");
              if (HasNumericallyFullRank == false)
            throw new MathematicsException("The matrix does not have full rank.");

              // Copy right hand side
              MatrixF x = matrixB.Clone();

              // Compute Y = transpose(Q)*B
              for (int k = 0; k < _n; k++)
              {
            for (int j = 0; j < matrixB.NumberOfColumns; j++)
            {
              float s = 0;
              for (int i = k; i < _m; i++)
            s += _qr[i, k] * x[i, j];
              s = -s / _qr[k, k];
              for (int i = k; i < _m; i++)
            x[i, j] += s * _qr[i, k];
            }
              }
              // Solve R*X = Y.
              for (int k = _n - 1; k >= 0; k--)
              {
            for (int j = 0; j < matrixB.NumberOfColumns; j++)
              x[k, j] /= _rDiagonal[k];
            for (int i = 0; i < k; i++)
              for (int j = 0; j < matrixB.NumberOfColumns; j++)
            x[i, j] -= x[k, j] * _qr[i, k];
              }
              return x.GetSubmatrix(0, _n - 1, 0, matrixB.NumberOfColumns - 1);
        }
        //--------------------------------------------------------------
        /// <summary>
        /// Solves the equation <c>A * X = B</c>.
        /// </summary>
        /// <param name="matrixB">The matrix B with as many rows as A and any number of columns.</param>
        /// <returns>X, so that <c>A * X = B</c>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixB"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows does not match.
        /// </exception>
        /// <exception cref="MathematicsException">
        /// The matrix A is not symmetric and positive definite.
        /// </exception>
        public MatrixF SolveLinearEquations(MatrixF matrixB)
        {
            if (matrixB == null)
            throw new ArgumentNullException("matrixB");
              if (matrixB.NumberOfRows != L.NumberOfRows)
            throw new ArgumentException("The number of rows does not match.", "matrixB");
              if (IsSymmetricPositiveDefinite == false)
            throw new MathematicsException("The original matrix A is not symmetric and positive definite.");

              // Initialize x as a copy of B.
              MatrixF x = matrixB.Clone();

              // Solve L*Y = B.
              for (int k = 0; k < L.NumberOfRows; k++)
              {
            for (int j = 0; j < matrixB.NumberOfColumns; j++)
            {
              for (int i = 0; i < k; i++)
            x[k, j] -= x[i, j] * L[k, i];
              x[k, j] /= L[k, k];
            }
              }

              // Solve transpose(L) * X = Y.
              for (int k = L.NumberOfRows - 1; k >= 0; k--)
              {
            for (int j = 0; j < matrixB.NumberOfColumns; j++)
            {
              for (int i = k + 1; i < L.NumberOfRows; i++)
            x[k, j] -= x[i, j] * L[i, k];
              x[k, j] /= L[k, k];
            }
              }
              return x;
        }
Beispiel #10
0
        public void Invert()
        {
            Assert.AreEqual(MatrixF.CreateIdentity(3, 3), MatrixF.CreateIdentity(3, 3).Inverse);

              MatrixF m = new MatrixF(new float[,] {{1, 2, 3, 4},
                                            {2, 5, 8, 3},
                                            {7, 6, -1, 1},
                                            {4, 9, 7, 7}});
              MatrixF inverse = m.Clone();
              m.Invert();
              VectorF v = new VectorF(4, 1);
              VectorF w = m * v;
              Assert.IsTrue(VectorF.AreNumericallyEqual(v, inverse * w));
              Assert.IsTrue(MatrixF.AreNumericallyEqual(MatrixF.CreateIdentity(4, 4), m * inverse));

              m = new MatrixF(new float[,] {{1, 2, 3},
                                    {2, 5, 8},
                                    {7, 6, -1},
                                    {4, 9, 7}});
              // To check the pseudo-inverse we use the definition: A*A.Transposed*A = A
              // see http://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse
              inverse = m.Clone();
              inverse.Invert();
              Assert.IsTrue(MatrixF.AreNumericallyEqual(m, m * inverse * m));
        }
Beispiel #11
0
 public void Clone()
 {
     MatrixF m = new MatrixF(3, 4, rowMajor, MatrixOrder.RowMajor);
       var o = m.Clone();
       Assert.AreEqual(m, o);
 }
Beispiel #12
0
        public void TryInvert()
        {
            // Regular, square
              MatrixF m = new MatrixF(new float[,] {{1, 2, 3, 4},
                                            {2, 5, 8, 3},
                                            {7, 6, -1, 1},
                                            {4, 9, 7, 7}});
              MatrixF inverse = m.Clone();
              Assert.AreEqual(true, m.TryInvert());
              Assert.IsTrue(MatrixF.AreNumericallyEqual(MatrixF.CreateIdentity(4, 4), m * inverse));

              // Full column rank, rectangular
              m = new MatrixF(new float[,] {{1, 2, 3},
                                    {2, 5, 8},
                                    {7, 6, -1},
                                    {4, 9, 7}});
              inverse = m.Clone();
              Assert.AreEqual(true, m.TryInvert());
              Assert.IsTrue(MatrixF.AreNumericallyEqual(m, m * inverse * m));

              // singular
              m = new MatrixF(new float[,] {{1, 2, 3},
                                    {2, 5, 8},
                                    {3, 7, 11}});
              inverse = m.Clone();
              Assert.AreEqual(false, m.TryInvert());
        }
        public SingularValueDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            throw new ArgumentNullException("matrixA");

              // Derived from LINPACK code.
              // Initialize.
              _m = matrixA.NumberOfRows;
              _n = matrixA.NumberOfColumns;
              MatrixF matrixAClone = matrixA.Clone();

              if (_m < _n)
            throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");

              int nu = Math.Min(_m, _n);
              _s = new VectorF(Math.Min(_m + 1, _n));
              _u = new MatrixF(_m, nu);     //Jama getU() returns new Matrix(U,_m,Math.min(_m+1,_n)) ?!
              _v = new MatrixF(_n, _n);
              float[] e = new float[_n];
              float[] work = new float[_m];

              // Abort if A contains NaN values.
              // If we continue with NaN values, we run into an infinite loop.
              for (int i = 0; i < _m; i++)
              {
            for (int j = 0; j < _n; j++)
            {
              if (Numeric.IsNaN(matrixA[i, j]))
              {
            _u.Set(float.NaN);
            _v.Set(float.NaN);
            _s.Set(float.NaN);
            return;
              }
            }
              }

              // By default, we calculate U and V. To calculate only U or V we can set one of the following
              // two constants to false. (This optimization is not yet tested.)
              const bool wantu = true;
              const bool wantv = true;

              // Reduce A to bidiagonal form, storing the diagonal elements
              // in s and the super-diagonal elements in e.

              int nct = Math.Min(_m - 1, _n);
              int nrt = Math.Max(0, Math.Min(_n - 2, _m));
              for (int k = 0; k < Math.Max(nct, nrt); k++)
              {
            if (k < nct)
            {
              // Compute the transformation for the k-th column and
              // place the k-th diagonal in s[k].
              // Compute 2-norm of k-th column without under/overflow.
              _s[k] = 0;
              for (int i = k; i < _m; i++)
            _s[k] = MathHelper.Hypotenuse(_s[k], matrixAClone[i, k]);

              if (_s[k] != 0)
              {
            if (matrixAClone[k, k] < 0)
              _s[k] = -_s[k];

            for (int i = k; i < _m; i++)
              matrixAClone[i, k] /= _s[k];

            matrixAClone[k, k] += 1;
              }

              _s[k] = -_s[k];
            }
            for (int j = k + 1; j < _n; j++)
            {
              if ((k < nct) && (_s[k] != 0))
              {
            // Apply the transformation.
            float t = 0;
            for (int i = k; i < _m; i++)
              t += matrixAClone[i, k] * matrixAClone[i, j];

            t = -t / matrixAClone[k, k];
            for (int i = k; i < _m; i++)
              matrixAClone[i, j] += t * matrixAClone[i, k];
              }

              // Place the k-th row of A into e for the
              // subsequent calculation of the row transformation.

              e[j] = matrixAClone[k, j];
            }

            if (wantu & (k < nct))
            {
              // Place the transformation in U for subsequent back
              // multiplication.
              for (int i = k; i < _m; i++)
            _u[i, k] = matrixAClone[i, k];
            }

            if (k < nrt)
            {
              // Compute the k-th row transformation and place the
              // k-th super-diagonal in e[k].
              // Compute 2-norm without under/overflow.
              e[k] = 0;
              for (int i = k + 1; i < _n; i++)
            e[k] = MathHelper.Hypotenuse(e[k], e[i]);

              if (e[k] != 0)
              {
            if (e[k + 1] < 0)
              e[k] = -e[k];

            for (int i = k + 1; i < _n; i++)
              e[i] /= e[k];

            e[k + 1] += 1;
              }

              e[k] = -e[k];
              if ((k + 1 < _m) && (e[k] != 0))
              {
            // Apply the transformation.

            for (int i = k + 1; i < _m; i++)
              work[i] = 0;

            for (int j = k + 1; j < _n; j++)
              for (int i = k + 1; i < _m; i++)
                work[i] += e[j] * matrixAClone[i, j];

            for (int j = k + 1; j < _n; j++)
            {
              float t = -e[j] / e[k + 1];
              for (int i = k + 1; i < _m; i++)
                matrixAClone[i, j] += t * work[i];
            }
              }

              if (wantv)
              {
            // Place the transformation in V for subsequent
            // back multiplication.
            for (int i = k + 1; i < _n; i++)
              _v[i, k] = e[i];
              }
            }
              }

              // Set up the final bidiagonal matrix or order p.

              int p = Math.Min(_n, _m + 1);
              if (nct < _n)
            _s[nct] = matrixAClone[nct, nct];

              if (_m < p)
            _s[p - 1] = 0;

              if (nrt + 1 < p)
            e[nrt] = matrixAClone[nrt, p - 1];

              e[p - 1] = 0;

              // If required, generate U.

              if (wantu)
              {
            for (int j = nct; j < nu; j++)
            {
              for (int i = 0; i < _m; i++)
            _u[i, j] = 0;

              _u[j, j] = 1;
            }

            for (int k = nct - 1; k >= 0; k--)
            {
              if (_s[k] != 0)
              {
            for (int j = k + 1; j < nu; j++)
            {
              float t = 0;
              for (int i = k; i < _m; i++)
                t += _u[i, k] * _u[i, j];

              t = -t / _u[k, k];
              for (int i = k; i < _m; i++)
                _u[i, j] += t * _u[i, k];

            }
            for (int i = k; i < _m; i++)
              _u[i, k] = -_u[i, k];

            _u[k, k] = 1 + _u[k, k];
            for (int i = 0; i < k - 1; i++)
              _u[i, k] = 0;
              }
              else
              {
            for (int i = 0; i < _m; i++)
              _u[i, k] = 0;

            _u[k, k] = 1;
              }
            }
              }

              // If required, generate V.
              if (wantv)
              {
            for (int k = _n - 1; k >= 0; k--)
            {
              if ((k < nrt) & (e[k] != 0.0))
              {
            for (int j = k + 1; j < nu; j++)
            {
              float t = 0;
              for (int i = k + 1; i < _n; i++)
                t += _v[i, k] * _v[i, j];

              t = -t / _v[k + 1, k];
              for (int i = k + 1; i < _n; i++)
                _v[i, j] += t * _v[i, k];
            }
              }

              for (int i = 0; i < _n; i++)
            _v[i, k] = 0;

              _v[k, k] = 1;
            }
              }

              // Main iteration loop for the singular values.

              int pp = p - 1;
              int iter = 0;
              double eps = (float)Math.Pow(2, -23);     // 2^-52 for double
              double tiny = (float)Math.Pow(2, -100);   // 2^-100 for float is an estimation by HelmutG
              // Original: 2^-966 for double
              while (p > 0)
              {
            int k, kase;

            // Here is where a test for too many iterations would go.

            // This section of the program inspects for
            // negligible elements in the s and e arrays. On
            // completion the variables kase and k are set as follows.

            // kase = 1     if s(p) and e[k-1] are negligible and k<p
            // kase = 2     if s(k) is negligible and k<p
            // kase = 3     if e[k-1] is negligible, k<p, and
            //              s(k), ..., s(p) are not negligible (qr step).
            // kase = 4     if e(p-1) is negligible (convergence).

            for (k = p - 2; k >= -1; k--)
            {
              if (k == -1)
            break;

              if (Math.Abs(e[k]) <= tiny + eps * (Math.Abs(_s[k]) + Math.Abs(_s[k + 1])))
              {
            e[k] = 0;
            break;
              }
            }

            if (k == p - 2)
            {
              kase = 4;
            }
            else
            {
              int ks;
              for (ks = p - 1; ks >= k; ks--)
              {
            if (ks == k)
              break;

            float t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0);
            if (Math.Abs(_s[ks]) <= tiny + eps * t)
            {
              _s[ks] = 0;
              break;
            }
              }
              if (ks == k)
              {
            kase = 3;
              }
              else if (ks == p - 1)
              {
            kase = 1;
              }
              else
              {
            kase = 2;
            k = ks;
              }
            }

            k++;

            // Perform the task indicated by kase.

            switch (kase)
            {
              // Deflate negligible s(p).
              case 1:
            {
              float f = e[p - 2];
              e[p - 2] = 0;
              for (int j = p - 2; j >= k; j--)
              {
                float t = MathHelper.Hypotenuse(_s[j], f);
                float cs = _s[j] / t;
                float sn = f / t;
                _s[j] = t;
                if (j != k)
                {
                  f = -sn * e[j - 1];
                  e[j - 1] = cs * e[j - 1];
                }

                if (wantv)
                {
                  for (int i = 0; i < _n; i++)
                  {
                    t = cs * _v[i, j] + sn * _v[i, p - 1];
                    _v[i, p - 1] = -sn * _v[i, j] + cs * _v[i, p - 1];
                    _v[i, j] = t;
                  }
                }
              }
            }
            break;

              // Split at negligible s(k).
              case 2:
            {
              float f = e[k - 1];
              e[k - 1] = 0;
              for (int j = k; j < p; j++)
              {
                float t = MathHelper.Hypotenuse(_s[j], f);
                float cs = _s[j] / t;
                float sn = f / t;
                _s[j] = t;
                f = -sn * e[j];
                e[j] = cs * e[j];
                if (wantu)
                {
                  for (int i = 0; i < _m; i++)
                  {
                    t = cs * _u[i, j] + sn * _u[i, k - 1];
                    _u[i, k - 1] = -sn * _u[i, j] + cs * _u[i, k - 1];
                    _u[i, j] = t;
                  }
                }
              }
            }
            break;

              // Perform one qr step.
              case 3:
            {
              // Calculate the shift.

              float scale = Math.Max(Math.Max(Math.Max(Math.Max(
                      Math.Abs(_s[p - 1]), Math.Abs(_s[p - 2])), Math.Abs(e[p - 2])),
                      Math.Abs(_s[k])), Math.Abs(e[k]));
              float sp = _s[p - 1] / scale;
              float spm1 = _s[p - 2] / scale;
              float epm1 = e[p - 2] / scale;
              float sk = _s[k] / scale;
              float ek = e[k] / scale;
              float b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;
              float c = (sp * epm1) * (sp * epm1);
              float shift = 0;
              if ((b != 0.0) | (c != 0.0))
              {
                shift = (float)Math.Sqrt(b * b + c);
                if (b < 0.0)
                  shift = -shift;

                shift = c / (b + shift);
              }
              float f = (sk + sp) * (sk - sp) + shift;
              float g = sk * ek;

              // Chase zeros.

              for (int j = k; j < p - 1; j++)
              {
                float t = MathHelper.Hypotenuse(f, g);
                float cs = f / t;
                float sn = g / t;
                if (j != k)
                  e[j - 1] = t;

                f = cs * _s[j] + sn * e[j];
                e[j] = cs * e[j] - sn * _s[j];
                g = sn * _s[j + 1];
                _s[j + 1] = cs * _s[j + 1];
                if (wantv)
                {
                  for (int i = 0; i < _n; i++)
                  {
                    t = cs * _v[i, j] + sn * _v[i, j + 1];
                    _v[i, j + 1] = -sn * _v[i, j] + cs * _v[i, j + 1];
                    _v[i, j] = t;
                  }
                }

                t = MathHelper.Hypotenuse(f, g);
                cs = f / t;
                sn = g / t;
                _s[j] = t;
                f = cs * e[j] + sn * _s[j + 1];
                _s[j + 1] = -sn * e[j] + cs * _s[j + 1];
                g = sn * e[j + 1];
                e[j + 1] = cs * e[j + 1];
                if (wantu && (j < _m - 1))
                {
                  for (int i = 0; i < _m; i++)
                  {
                    t = cs * _u[i, j] + sn * _u[i, j + 1];
                    _u[i, j + 1] = -sn * _u[i, j] + cs * _u[i, j + 1];
                    _u[i, j] = t;
                  }
                }
              }

              e[p - 2] = f;
              iter = iter + 1;
            }
            break;

              // Convergence.

              case 4:
            {
              // Make the singular values positive.

              if (_s[k] <= 0.0)
              {
                _s[k] = (_s[k] < 0.0 ? -_s[k] : 0);
                if (wantv)
                {
                  for (int i = 0; i <= pp; i++)
                    _v[i, k] = -_v[i, k];
                }
              }

              // Order the singular values.

              while (k < pp)
              {
                if (_s[k] >= _s[k + 1])
                  break;

                float t = _s[k];
                _s[k] = _s[k + 1];
                _s[k + 1] = t;
                if (wantv && (k < _n - 1))
                {
                  for (int i = 0; i < _n; i++)
                  {
                    t = _v[i, k + 1];
                    _v[i, k + 1] = _v[i, k];
                    _v[i, k] = t;
                  }
                }
                if (wantu && (k < _m - 1))
                {
                  for (int i = 0; i < _m; i++)
                  {
                    t = _u[i, k + 1];
                    _u[i, k + 1] = _u[i, k];
                    _u[i, k] = t;
                  }
                }

                k++;
              }

              iter = 0;
              p--;
            }
            break;
            }
              }
        }
Beispiel #14
0
        //--------------------------------------------------------------
        #region Creation and Cleanup
        //--------------------------------------------------------------

        /// <summary>
        /// Creates the LU decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">
        /// The matrix A. (Can be rectangular. Number of rows ≥ number of columns.)
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows must be greater than or equal to the number of columns.
        /// </exception>
        public LUDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            {
                throw new ArgumentNullException("matrixA");
            }
            if (matrixA.NumberOfColumns > matrixA.NumberOfRows)
            {
                throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");
            }

            // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
            _lu          = matrixA.Clone();
            _m           = matrixA.NumberOfRows;
            _n           = matrixA.NumberOfColumns;
            _pivotVector = new int[_m];

            // Initialize with the 0 to m-1.
            for (int i = 0; i < _m; i++)
            {
                _pivotVector[i] = i;
            }

            _pivotSign = 1;

            // Outer loop.
            for (int j = 0; j < _n; j++)
            {
                // Make a copy of the j-th column to localize references.
                float[] luColumnJ = new float[_m];
                for (int i = 0; i < _m; i++)
                {
                    luColumnJ[i] = _lu[i, j];
                }

                // Apply previous transformations.
                for (int i = 0; i < _m; i++)
                {
                    // Most of the time is spent in the following dot product.
                    int   kmax = Math.Min(i, j);
                    float s    = 0;
                    for (int k = 0; k < kmax; k++)
                    {
                        s += _lu[i, k] * luColumnJ[k];
                    }

                    luColumnJ[i] -= s;
                    _lu[i, j]     = luColumnJ[i];
                }

                // Find pivot and exchange if necessary.
                int p = j;
                for (int i = j + 1; i < _m; i++)
                {
                    if (Math.Abs(luColumnJ[i]) > Math.Abs(luColumnJ[p]))
                    {
                        p = i;
                    }
                }

                // Swap lines p and k.
                if (p != j)
                {
                    for (int k = 0; k < _n; k++)
                    {
                        float dummy = _lu[p, k];
                        _lu[p, k] = _lu[j, k];
                        _lu[j, k] = dummy;
                    }

                    MathHelper.Swap(ref _pivotVector[p], ref _pivotVector[j]);

                    _pivotSign = -_pivotSign;
                }

                // Compute multipliers.
                if (j < _m && _lu[j, j] != 0)
                {
                    for (int i = j + 1; i < _m; i++)
                    {
                        _lu[i, j] /= _lu[j, j];
                    }
                }
            }
        }
Beispiel #15
0
        //--------------------------------------------------------------
        /// <summary>
        /// Creates the LU decomposition of the given matrix.
        /// </summary>
        /// <param name="matrixA">
        /// The matrix A. (Can be rectangular. Number of rows ≥ number of columns.)
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="matrixA"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The number of rows must be greater than or equal to the number of columns.
        /// </exception>
        public LUDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            throw new ArgumentNullException("matrixA");
              if (matrixA.NumberOfColumns > matrixA.NumberOfRows)
            throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");

              // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
              _lu = matrixA.Clone();
              _m = matrixA.NumberOfRows;
              _n = matrixA.NumberOfColumns;
              _pivotVector = new int[_m];

              // Initialize with the 0 to m-1.
              for (int i = 0; i < _m; i++)
            _pivotVector[i] = i;

              _pivotSign = 1;

              // Outer loop.
              for (int j = 0; j < _n; j++)
              {
            // Make a copy of the j-th column to localize references.
            float[] luColumnJ = new float[_m];
            for (int i = 0; i < _m; i++)
              luColumnJ[i] = _lu[i, j];

            // Apply previous transformations.
            for (int i = 0; i < _m; i++)
            {
              // Most of the time is spent in the following dot product.
              int kmax = Math.Min(i, j);
              float s = 0;
              for (int k = 0; k < kmax; k++)
            s += _lu[i, k] * luColumnJ[k];

              luColumnJ[i] -= s;
              _lu[i, j] = luColumnJ[i];
            }

            // Find pivot and exchange if necessary.
            int p = j;
            for (int i = j + 1; i < _m; i++)
              if (Math.Abs(luColumnJ[i]) > Math.Abs(luColumnJ[p]))
            p = i;

            // Swap lines p and k.
            if (p != j)
            {
              for (int k = 0; k < _n; k++)
              {
            float dummy = _lu[p, k];
            _lu[p, k] = _lu[j, k];
            _lu[j, k] = dummy;
              }

              MathHelper.Swap(ref _pivotVector[p], ref _pivotVector[j]);

              _pivotSign = -_pivotSign;
            }

            // Compute multipliers.
            if (j < _m && _lu[j, j] != 0)
              for (int i = j + 1; i < _m; i++)
            _lu[i, j] /= _lu[j, j];
              }
        }
        public SingularValueDecompositionF(MatrixF matrixA)
        {
            if (matrixA == null)
            {
                throw new ArgumentNullException("matrixA");
            }

            // Derived from LINPACK code.
            // Initialize.
            _m = matrixA.NumberOfRows;
            _n = matrixA.NumberOfColumns;
            MatrixF matrixAClone = matrixA.Clone();

            if (_m < _n)
            {
                throw new ArgumentException("The number of rows must be greater than or equal to the number of columns.", "matrixA");
            }

            int nu = Math.Min(_m, _n);

            _s = new VectorF(Math.Min(_m + 1, _n));
            _u = new MatrixF(_m, nu); //Jama getU() returns new Matrix(U,_m,Math.min(_m+1,_n)) ?!
            _v = new MatrixF(_n, _n);
            float[] e    = new float[_n];
            float[] work = new float[_m];

            // Abort if A contains NaN values.
            // If we continue with NaN values, we run into an infinite loop.
            for (int i = 0; i < _m; i++)
            {
                for (int j = 0; j < _n; j++)
                {
                    if (Numeric.IsNaN(matrixA[i, j]))
                    {
                        _u.Set(float.NaN);
                        _v.Set(float.NaN);
                        _s.Set(float.NaN);
                        return;
                    }
                }
            }

            // By default, we calculate U and V. To calculate only U or V we can set one of the following
            // two constants to false. (This optimization is not yet tested.)
            const bool wantu = true;
            const bool wantv = true;

            // Reduce A to bidiagonal form, storing the diagonal elements
            // in s and the super-diagonal elements in e.

            int nct = Math.Min(_m - 1, _n);
            int nrt = Math.Max(0, Math.Min(_n - 2, _m));

            for (int k = 0; k < Math.Max(nct, nrt); k++)
            {
                if (k < nct)
                {
                    // Compute the transformation for the k-th column and
                    // place the k-th diagonal in s[k].
                    // Compute 2-norm of k-th column without under/overflow.
                    _s[k] = 0;
                    for (int i = k; i < _m; i++)
                    {
                        _s[k] = MathHelper.Hypotenuse(_s[k], matrixAClone[i, k]);
                    }

                    if (_s[k] != 0)
                    {
                        if (matrixAClone[k, k] < 0)
                        {
                            _s[k] = -_s[k];
                        }

                        for (int i = k; i < _m; i++)
                        {
                            matrixAClone[i, k] /= _s[k];
                        }

                        matrixAClone[k, k] += 1;
                    }

                    _s[k] = -_s[k];
                }
                for (int j = k + 1; j < _n; j++)
                {
                    if ((k < nct) && (_s[k] != 0))
                    {
                        // Apply the transformation.
                        float t = 0;
                        for (int i = k; i < _m; i++)
                        {
                            t += matrixAClone[i, k] * matrixAClone[i, j];
                        }

                        t = -t / matrixAClone[k, k];
                        for (int i = k; i < _m; i++)
                        {
                            matrixAClone[i, j] += t * matrixAClone[i, k];
                        }
                    }

                    // Place the k-th row of A into e for the
                    // subsequent calculation of the row transformation.

                    e[j] = matrixAClone[k, j];
                }

                if (wantu & (k < nct))
                {
                    // Place the transformation in U for subsequent back
                    // multiplication.
                    for (int i = k; i < _m; i++)
                    {
                        _u[i, k] = matrixAClone[i, k];
                    }
                }

                if (k < nrt)
                {
                    // Compute the k-th row transformation and place the
                    // k-th super-diagonal in e[k].
                    // Compute 2-norm without under/overflow.
                    e[k] = 0;
                    for (int i = k + 1; i < _n; i++)
                    {
                        e[k] = MathHelper.Hypotenuse(e[k], e[i]);
                    }

                    if (e[k] != 0)
                    {
                        if (e[k + 1] < 0)
                        {
                            e[k] = -e[k];
                        }

                        for (int i = k + 1; i < _n; i++)
                        {
                            e[i] /= e[k];
                        }

                        e[k + 1] += 1;
                    }

                    e[k] = -e[k];
                    if ((k + 1 < _m) && (e[k] != 0))
                    {
                        // Apply the transformation.

                        for (int i = k + 1; i < _m; i++)
                        {
                            work[i] = 0;
                        }

                        for (int j = k + 1; j < _n; j++)
                        {
                            for (int i = k + 1; i < _m; i++)
                            {
                                work[i] += e[j] * matrixAClone[i, j];
                            }
                        }

                        for (int j = k + 1; j < _n; j++)
                        {
                            float t = -e[j] / e[k + 1];
                            for (int i = k + 1; i < _m; i++)
                            {
                                matrixAClone[i, j] += t * work[i];
                            }
                        }
                    }

                    if (wantv)
                    {
                        // Place the transformation in V for subsequent
                        // back multiplication.
                        for (int i = k + 1; i < _n; i++)
                        {
                            _v[i, k] = e[i];
                        }
                    }
                }
            }

            // Set up the final bidiagonal matrix or order p.

            int p = Math.Min(_n, _m + 1);

            if (nct < _n)
            {
                _s[nct] = matrixAClone[nct, nct];
            }

            if (_m < p)
            {
                _s[p - 1] = 0;
            }

            if (nrt + 1 < p)
            {
                e[nrt] = matrixAClone[nrt, p - 1];
            }

            e[p - 1] = 0;

            // If required, generate U.

            if (wantu)
            {
                for (int j = nct; j < nu; j++)
                {
                    for (int i = 0; i < _m; i++)
                    {
                        _u[i, j] = 0;
                    }

                    _u[j, j] = 1;
                }

                for (int k = nct - 1; k >= 0; k--)
                {
                    if (_s[k] != 0)
                    {
                        for (int j = k + 1; j < nu; j++)
                        {
                            float t = 0;
                            for (int i = k; i < _m; i++)
                            {
                                t += _u[i, k] * _u[i, j];
                            }

                            t = -t / _u[k, k];
                            for (int i = k; i < _m; i++)
                            {
                                _u[i, j] += t * _u[i, k];
                            }
                        }
                        for (int i = k; i < _m; i++)
                        {
                            _u[i, k] = -_u[i, k];
                        }

                        _u[k, k] = 1 + _u[k, k];
                        for (int i = 0; i < k - 1; i++)
                        {
                            _u[i, k] = 0;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < _m; i++)
                        {
                            _u[i, k] = 0;
                        }

                        _u[k, k] = 1;
                    }
                }
            }

            // If required, generate V.
            if (wantv)
            {
                for (int k = _n - 1; k >= 0; k--)
                {
                    if ((k < nrt) & (e[k] != 0.0))
                    {
                        for (int j = k + 1; j < nu; j++)
                        {
                            float t = 0;
                            for (int i = k + 1; i < _n; i++)
                            {
                                t += _v[i, k] * _v[i, j];
                            }

                            t = -t / _v[k + 1, k];
                            for (int i = k + 1; i < _n; i++)
                            {
                                _v[i, j] += t * _v[i, k];
                            }
                        }
                    }

                    for (int i = 0; i < _n; i++)
                    {
                        _v[i, k] = 0;
                    }

                    _v[k, k] = 1;
                }
            }

            // Main iteration loop for the singular values.

            int    pp   = p - 1;
            int    iter = 0;
            double eps  = (float)Math.Pow(2, -23);  // 2^-52 for double
            double tiny = (float)Math.Pow(2, -100); // 2^-100 for float is an estimation by HelmutG

            // Original: 2^-966 for double
            while (p > 0)
            {
                int k, kase;

                // Here is where a test for too many iterations would go.

                // This section of the program inspects for
                // negligible elements in the s and e arrays. On
                // completion the variables kase and k are set as follows.

                // kase = 1     if s(p) and e[k-1] are negligible and k<p
                // kase = 2     if s(k) is negligible and k<p
                // kase = 3     if e[k-1] is negligible, k<p, and
                //              s(k), ..., s(p) are not negligible (qr step).
                // kase = 4     if e(p-1) is negligible (convergence).

                for (k = p - 2; k >= -1; k--)
                {
                    if (k == -1)
                    {
                        break;
                    }

                    if (Math.Abs(e[k]) <= tiny + eps * (Math.Abs(_s[k]) + Math.Abs(_s[k + 1])))
                    {
                        e[k] = 0;
                        break;
                    }
                }

                if (k == p - 2)
                {
                    kase = 4;
                }
                else
                {
                    int ks;
                    for (ks = p - 1; ks >= k; ks--)
                    {
                        if (ks == k)
                        {
                            break;
                        }

                        float t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0);
                        if (Math.Abs(_s[ks]) <= tiny + eps * t)
                        {
                            _s[ks] = 0;
                            break;
                        }
                    }
                    if (ks == k)
                    {
                        kase = 3;
                    }
                    else if (ks == p - 1)
                    {
                        kase = 1;
                    }
                    else
                    {
                        kase = 2;
                        k    = ks;
                    }
                }

                k++;

                // Perform the task indicated by kase.

                switch (kase)
                {
                // Deflate negligible s(p).
                case 1:
                {
                    float f = e[p - 2];
                    e[p - 2] = 0;
                    for (int j = p - 2; j >= k; j--)
                    {
                        float t  = MathHelper.Hypotenuse(_s[j], f);
                        float cs = _s[j] / t;
                        float sn = f / t;
                        _s[j] = t;
                        if (j != k)
                        {
                            f        = -sn * e[j - 1];
                            e[j - 1] = cs * e[j - 1];
                        }

                        if (wantv)
                        {
                            for (int i = 0; i < _n; i++)
                            {
                                t            = cs * _v[i, j] + sn * _v[i, p - 1];
                                _v[i, p - 1] = -sn * _v[i, j] + cs * _v[i, p - 1];
                                _v[i, j]     = t;
                            }
                        }
                    }
                }
                break;

                // Split at negligible s(k).
                case 2:
                {
                    float f = e[k - 1];
                    e[k - 1] = 0;
                    for (int j = k; j < p; j++)
                    {
                        float t  = MathHelper.Hypotenuse(_s[j], f);
                        float cs = _s[j] / t;
                        float sn = f / t;
                        _s[j] = t;
                        f     = -sn * e[j];
                        e[j]  = cs * e[j];
                        if (wantu)
                        {
                            for (int i = 0; i < _m; i++)
                            {
                                t            = cs * _u[i, j] + sn * _u[i, k - 1];
                                _u[i, k - 1] = -sn * _u[i, j] + cs * _u[i, k - 1];
                                _u[i, j]     = t;
                            }
                        }
                    }
                }
                break;

                // Perform one qr step.
                case 3:
                {
                    // Calculate the shift.

                    float scale = Math.Max(Math.Max(Math.Max(Math.Max(
                                                                 Math.Abs(_s[p - 1]), Math.Abs(_s[p - 2])), Math.Abs(e[p - 2])),
                                                    Math.Abs(_s[k])), Math.Abs(e[k]));
                    float sp    = _s[p - 1] / scale;
                    float spm1  = _s[p - 2] / scale;
                    float epm1  = e[p - 2] / scale;
                    float sk    = _s[k] / scale;
                    float ek    = e[k] / scale;
                    float b     = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;
                    float c     = (sp * epm1) * (sp * epm1);
                    float shift = 0;
                    if ((b != 0.0) | (c != 0.0))
                    {
                        shift = (float)Math.Sqrt(b * b + c);
                        if (b < 0.0)
                        {
                            shift = -shift;
                        }

                        shift = c / (b + shift);
                    }
                    float f = (sk + sp) * (sk - sp) + shift;
                    float g = sk * ek;

                    // Chase zeros.

                    for (int j = k; j < p - 1; j++)
                    {
                        float t  = MathHelper.Hypotenuse(f, g);
                        float cs = f / t;
                        float sn = g / t;
                        if (j != k)
                        {
                            e[j - 1] = t;
                        }

                        f         = cs * _s[j] + sn * e[j];
                        e[j]      = cs * e[j] - sn * _s[j];
                        g         = sn * _s[j + 1];
                        _s[j + 1] = cs * _s[j + 1];
                        if (wantv)
                        {
                            for (int i = 0; i < _n; i++)
                            {
                                t            = cs * _v[i, j] + sn * _v[i, j + 1];
                                _v[i, j + 1] = -sn * _v[i, j] + cs * _v[i, j + 1];
                                _v[i, j]     = t;
                            }
                        }

                        t         = MathHelper.Hypotenuse(f, g);
                        cs        = f / t;
                        sn        = g / t;
                        _s[j]     = t;
                        f         = cs * e[j] + sn * _s[j + 1];
                        _s[j + 1] = -sn * e[j] + cs * _s[j + 1];
                        g         = sn * e[j + 1];
                        e[j + 1]  = cs * e[j + 1];
                        if (wantu && (j < _m - 1))
                        {
                            for (int i = 0; i < _m; i++)
                            {
                                t            = cs * _u[i, j] + sn * _u[i, j + 1];
                                _u[i, j + 1] = -sn * _u[i, j] + cs * _u[i, j + 1];
                                _u[i, j]     = t;
                            }
                        }
                    }

                    e[p - 2] = f;
                    iter     = iter + 1;
                }
                break;

                // Convergence.

                case 4:
                {
                    // Make the singular values positive.

                    if (_s[k] <= 0.0)
                    {
                        _s[k] = (_s[k] < 0.0 ? -_s[k] : 0);
                        if (wantv)
                        {
                            for (int i = 0; i <= pp; i++)
                            {
                                _v[i, k] = -_v[i, k];
                            }
                        }
                    }

                    // Order the singular values.

                    while (k < pp)
                    {
                        if (_s[k] >= _s[k + 1])
                        {
                            break;
                        }

                        float t = _s[k];
                        _s[k]     = _s[k + 1];
                        _s[k + 1] = t;
                        if (wantv && (k < _n - 1))
                        {
                            for (int i = 0; i < _n; i++)
                            {
                                t            = _v[i, k + 1];
                                _v[i, k + 1] = _v[i, k];
                                _v[i, k]     = t;
                            }
                        }
                        if (wantu && (k < _m - 1))
                        {
                            for (int i = 0; i < _m; i++)
                            {
                                t            = _u[i, k + 1];
                                _u[i, k + 1] = _u[i, k];
                                _u[i, k]     = t;
                            }
                        }

                        k++;
                    }

                    iter = 0;
                    p--;
                }
                break;
                }
            }
        }