Exemplo n.º 1
0
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            var clone = new QrDecomposition();

            clone.qr    = (Double[, ])qr.Clone();
            clone.Rdiag = (Double[])Rdiag.Clone();
            return(clone);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a new householder decomposition.
        /// </summary>
        /// <param name="matrix">The matrix to decompose.</param>
        public HouseholderDecomposition(Double[,] matrix)
            : base(matrix)
        {
            _QR    = (Double[, ])matrix.Clone();
            _Rdiag = new Double[_columns];

            // Main loop.
            for (int k = 0; k < _columns; k++)
            {
                var nrm = 0.0;

                for (int i = k; i < _rows; i++)
                {
                    nrm = Helpers.Hypot(nrm, _QR[i, k]);
                }

                if (nrm != 0.0)
                {
                    // Form k-th Householder vector.

                    if (_QR[k, k] < 0.0)
                    {
                        nrm = -nrm;
                    }

                    for (var i = k; i < _rows; i++)
                    {
                        _QR[i, k] /= nrm;
                    }

                    _QR[k, k] += 1.0;

                    // Apply transformation to remaining columns.
                    for (var j = k + 1; j < _columns; j++)
                    {
                        var s = 0.0;

                        for (var i = k; i < _rows; i++)
                        {
                            s += _QR[i, k] * _QR[i, j];
                        }

                        s = (-s) / _QR[k, k];

                        for (var i = k; i < _rows; i++)
                        {
                            _QR[i, j] += s * _QR[i, k];
                        }
                    }
                }
                else
                {
                    HasFullRank = false;
                }

                _Rdiag[k] = -nrm;
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Least squares solution of A * X = B
        /// </summary>
        /// <param name="matrix">A Matrix with as many rows as A and any number of columns.</param>
        /// <returns>X that minimizes the two norm of Q*R*X-B.</returns>
        public override Double[,] Solve(Double[,] matrix)
        {
            if (matrix.GetLength(0) != _rows)
            {
                throw new InvalidOperationException(ErrorMessages.RowMismatch);
            }

            if (!HasFullRank)
            {
                throw new InvalidOperationException(ErrorMessages.SingularSource);
            }

            // Copy right hand side
            var nx = matrix.GetLength(1);
            var X  = (Double[, ])matrix.Clone();

            // Compute Y = transpose(Q)*B
            for (var k = 0; k < _columns; k++)
            {
                for (var j = 0; j < nx; j++)
                {
                    var s = 0.0;

                    for (var i = k; i < _rows; i++)
                    {
                        s += _QR[i, k] * X[i, j];
                    }

                    s = (-s) / _QR[k, k];

                    for (var i = k; i < _rows; i++)
                    {
                        X[i, j] += s * _QR[i, k];
                    }
                }
            }

            // Solve R * X = Y;
            for (var k = _columns - 1; k >= 0; k--)
            {
                for (var j = 0; j < nx; j++)
                {
                    X[k, j] /= _Rdiag[k];
                }

                for (var i = 0; i < k; i++)
                {
                    for (var j = 0; j < nx; j++)
                    {
                        X[i, j] -= X[k, j] * _QR[i, k];
                    }
                }
            }

            return(Helpers.SubMatrix(X, 0, _columns, 0, nx));
        }
        /// <summary>
        ///   Construct an eigenvalue decomposition.</summary>
        /// <param name="value">
        ///   The matrix to be decomposed.</param>
        /// <param name="assumeSymmetric">
        ///   Defines if the matrix should be assumed as being symmetric
        ///   regardless if it is or not. Default is <see langword="false"/>.</param>
        /// <param name="inPlace">
        ///   Pass <see langword="true"/> to perform the decomposition in place. The matrix
        ///   <paramref name="value"/> will be destroyed in the process, resulting in less
        ///   memory comsumption.</param>
        public EigenvalueDecomposition(Double[,] value, bool assumeSymmetric, bool inPlace)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            if (value.GetLength(0) != value.GetLength(1))
            {
                throw new ArgumentException("Matrix is not a square matrix.", "value");
            }

            n = value.GetLength(1);
            V = new Double[n, n];
            d = new Double[n];
            e = new Double[n];


            this.symmetric = assumeSymmetric;

            if (this.symmetric)
            {
                V = inPlace ? value : (Double[, ])value.Clone();

                // Tridiagonalize.
                this.tred2();

                // Diagonalize.
                this.tql2();
            }
            else
            {
                H = inPlace ? value : (Double[, ])value.Clone();

                ort = new Double[n];

                // Reduce to Hessenberg form.
                this.orthes();

                // Reduce Hessenberg to real Schur form.
                this.hqr2();
            }
        }
Exemplo n.º 5
0
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        ///
        public object Clone()
        {
            var svd = new SingularValueDecomposition();

            svd.m       = m;
            svd.n       = n;
            svd.s       = (Double[])s.Clone();
            svd.si      = (int[])si.Clone();
            svd.swapped = swapped;
            if (u != null)
            {
                svd.u = (Double[, ])u.Clone();
            }
            if (v != null)
            {
                svd.v = (Double[, ])u.Clone();
            }

            return(svd);
        }
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        ///
        public object Clone()
        {
            var clone = new CholeskyDecomposition();

            clone.L                = (Double[, ])L.Clone();
            clone.D                = (Double[])D.Clone();
            clone.n                = n;
            clone.robust           = robust;
            clone.positiveDefinite = positiveDefinite;
            clone.symmetric        = symmetric;
            return(clone);
        }
        /// <summary>Solve A*X = B</summary>
        /// <param name="matrix">  A Matrix with as many rows as A and any number of columns.
        /// </param>

        public Double[,] Solve(Double[,] matrix)
        {
            if (matrix.GetLength(0) != _dim)
            {
                throw new InvalidOperationException(ErrorMessages.DimensionMismatch);
            }

            if (!_spd)
            {
                throw new InvalidOperationException(ErrorMessages.SpdRequired);
            }

            // Copy right hand side.
            var X  = (Double[, ])matrix.Clone();
            var nx = matrix.GetLength(1);

            // Solve L*Y = B;
            for (var k = 0; k < _dim; k++)
            {
                for (var i = k + 1; i < _dim; i++)
                {
                    for (var j = 0; j < nx; j++)
                    {
                        X[i, j] -= X[k, j] * _L[i, k];
                    }
                }

                for (var j = 0; j < nx; j++)
                {
                    X[k, j] /= _L[k, k];
                }
            }

            // Solve L'*X = Y;
            for (var k = _dim - 1; k >= 0; k--)
            {
                for (var j = 0; j < nx; j++)
                {
                    X[k, j] /= _L[k, k];
                }

                for (var i = 0; i < k; i++)
                {
                    for (var j = 0; j < nx; j++)
                    {
                        X[i, j] -= X[k, j] * _L[k, i];
                    }
                }
            }

            return(X);
        }
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            var clone = new EigenvalueDecomposition();

            clone.d         = (Double[])d.Clone();
            clone.e         = (Double[])e.Clone();
            clone.H         = (Double[, ])H.Clone();
            clone.n         = n;
            clone.ort       = (Double[])ort;
            clone.symmetric = symmetric;
            clone.V         = (Double[, ])V.Clone();
            return(clone);
        }
        /// <summary>
        /// Cholesky algorithm for symmetric and positive definite matrix.
        /// </summary>
        /// <param name="matrix">Square, symmetric matrix.</param>
        /// <returns>Structure to access L and isspd flag.</returns>
        public CholeskyDecomposition(Double[,] matrix)
        {
            // Initialize.
            var A = (Double[, ])matrix.Clone();

            _dim = matrix.GetLength(0);
            _L   = new Double[_dim, _dim];
            _spd = matrix.GetLength(1) == _dim;

            // Main loop.
            for (var i = 0; i < _dim; i++)
            {
                var Lrowi = new Double[_dim];
                var d     = 0.0;

                for (var k = 0; k < _dim; k++)
                {
                    Lrowi[k] = _L[i, k];
                }

                for (int j = 0; j < i; j++)
                {
                    var Lrowj = new Double[_dim];
                    var s     = 0.0;

                    for (var k = 0; k < _dim; k++)
                    {
                        Lrowj[k] = _L[j, k];
                    }

                    for (var k = 0; k < j; k++)
                    {
                        s += Lrowi[k] * Lrowj[k];
                    }

                    s        = (A[i, j] - s) / _L[j, j];
                    Lrowi[j] = s;
                    d       += s * s;
                    _spd     = _spd && (A[j, i] == A[i, j]);
                }

                d        = A[i, i] - d;
                _spd     = _spd & (Math.Abs(d) > 0.0);
                _L[i, i] = Math.Sqrt(d);

                for (var k = i + 1; k < _dim; k++)
                {
                    _L[i, k] = 0.0;
                }
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Creates a new Givens decomposition.
        /// </summary>
        /// <param name="matrix">The matrix to decompose.</param>
        public GivensDecomposition(Double[,] matrix)
            : base(matrix)
        {
            var Q = Helpers.One(_rows);
            var R = (Double[, ])matrix.Clone();

            // Main loop.
            for (var j = 0; j < _columns - 1; j++)
            {
                for (var i = _rows - 1; i > j; i--)
                {
                    var a = R[i - 1, j];
                    var b = R[i, j];
                    var G = Helpers.One(_rows);

                    var beta = Math.Sqrt(a * a + b * b);
                    var s    = -b / beta;
                    var c    = a / beta;

                    G[i - 1, i - 1] = c;
                    G[i - 1, i]     = -s;
                    G[i, i - 1]     = s;
                    G[i, i]         = c;

                    R = Helpers.Multiply(G, R);
                    Q = Helpers.Multiply(Q, Helpers.Transpose(G));
                }
            }

            for (var j = 0; j < _columns; j++)
            {
                if (R[j, j] == 0.0)
                {
                    HasFullRank = false;
                }
            }

            r = R;
            q = Q;
        }
Exemplo n.º 11
0
        /// <summary>Least squares solution of <c>A * X = B</c></summary>
        /// <param name="value">Right-hand-side matrix with as many rows as <c>A</c> and any number of columns.</param>
        /// <returns>A matrix that minimized the two norm of <c>Q * R * X - B</c>.</returns>
        /// <exception cref="T:System.ArgumentException">Matrix row dimensions must be the same.</exception>
        /// <exception cref="T:System.InvalidOperationException">Matrix is rank deficient.</exception>
        public Double[,] Solve(Double[,] value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            if (value.GetLength(0) != qr.GetLength(0))
            {
                throw new ArgumentException("Matrix row dimensions must agree.");
            }

            if (!this.FullRank)
            {
                throw new InvalidOperationException("Matrix is rank deficient.");
            }

            // Copy right hand side
            int count = value.GetLength(1);
            var X     = (Double[, ])value.Clone();
            int m     = qr.GetLength(0);
            int n     = qr.GetLength(1);

            // Compute Y = transpose(Q)*B
            for (int k = 0; k < n; k++)
            {
                for (int j = 0; j < count; j++)
                {
                    Double 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 < count; j++)
                {
                    X[k, j] /= Rdiag[k];
                }

                for (int i = 0; i < k; i++)
                {
                    for (int j = 0; j < count; j++)
                    {
                        X[i, j] -= X[k, j] * qr[i, k];
                    }
                }
            }

            var r = new Double[n, count];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < count; j++)
                {
                    r[i, j] = X[i, j];
                }
            }

            return(r);
        }
Exemplo n.º 12
0
        /// <summary>
        ///   Constructs a new LU decomposition.
        /// </summary>
        /// <param name="value">The matrix A to be decomposed.</param>
        /// <param name="transpose">True if the decomposition should be performed on
        /// the transpose of A rather than A itself, false otherwise. Default is false.</param>
        /// <param name="inPlace">True if the decomposition should be performed over the
        /// <paramref name="value"/> matrix rather than on a copy of it. If true, the
        /// matrix will be destroyed during the decomposition. Default is false.</param>
        ///
        public LuDecomposition(Double[,] value, bool transpose, bool inPlace)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            if (transpose)
            {
                this.lu = value.Transpose(inPlace);
            }
            else
            {
                this.lu = inPlace ? value : (Double[, ])value.Clone();
            }

            this.rows      = lu.GetLength(0);
            this.cols      = lu.GetLength(1);
            this.pivotSign = 1;

            this.pivotVector = new int[rows];
            for (int i = 0; i < rows; i++)
            {
                pivotVector[i] = i;
            }

            var LUcolj = new Double[rows];


            unsafe
            {
                fixed(Double *LU = lu)
                {
                    // Outer loop.
                    for (int j = 0; j < cols; j++)
                    {
                        // Make a copy of the j-th column to localize references.
                        for (int i = 0; i < rows; i++)
                        {
                            LUcolj[i] = lu[i, j];
                        }

                        // Apply previous transformations.
                        for (int i = 0; i < rows; i++)
                        {
                            Double s = 0;

                            // Most of the time is spent in
                            // the following dot product:
                            int     kmax   = Math.Min(i, j);
                            Double *LUrowi = &LU[i * cols];
                            for (int k = 0; k < kmax; k++)
                            {
                                s += LUrowi[k] * LUcolj[k];
                            }

                            LUrowi[j] = LUcolj[i] -= s;
                        }

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

                        if (p != j)
                        {
                            for (int k = 0; k < cols; k++)
                            {
                                var t = lu[p, k];
                                lu[p, k] = lu[j, k];
                                lu[j, k] = t;
                            }

                            int v = pivotVector[p];
                            pivotVector[p] = pivotVector[j];
                            pivotVector[j] = v;

                            pivotSign = -pivotSign;
                        }

                        // Compute multipliers.
                        if (j < rows && lu[j, j] != 0)
                        {
                            for (int i = j + 1; i < rows; i++)
                            {
                                lu[i, j] /= lu[j, j];
                            }
                        }
                    }
                }
            }
        }
        /// <summary>Solves a set of equation systems of type <c>A * X = B</c>.</summary>
        /// <param name="value">Right hand side matrix with as many rows as <c>A</c> and any number of columns.</param>
        /// <returns>Matrix <c>X</c> so that <c>L * L' * X = B</c>.</returns>
        /// <exception cref="T:System.ArgumentException">Matrix dimensions do not match.</exception>
        /// <exception cref="T:System.NonSymmetricMatrixException">Matrix is not symmetric.</exception>
        /// <exception cref="T:System.NonPositiveDefiniteMatrixException">Matrix is not positive-definite.</exception>
        /// <param name="inPlace">True to compute the solving in place, false otherwise.</param>
        ///
        public Double[,] Solve(Double[,] value, bool inPlace)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            if (value.GetLength(0) != n)
            {
                throw new ArgumentException("Argument matrix should have the same number of rows as the decomposed matrix.", "value");
            }

            if (!symmetric)
            {
                throw new NonSymmetricMatrixException("Decomposed matrix is not symmetric.");
            }

            if (!robust && !positiveDefinite)
            {
                throw new NonPositiveDefiniteMatrixException("Decomposed matrix is not positive definite.");
            }


            int count = value.GetLength(1);

            Double[,] B = inPlace ? value : (Double[, ])value.Clone();


            // Solve L*Y = B;
            for (int k = 0; k < n; k++)
            {
                for (int j = 0; j < count; j++)
                {
                    for (int i = 0; i < k; i++)
                    {
                        B[k, j] -= B[i, j] * L[k, i];
                    }

                    B[k, j] /= L[k, k];
                }
            }

            if (robust)
            {
                for (int k = 0; k < n; k++)
                {
                    for (int j = 0; j < count; j++)
                    {
                        B[k, j] /= D[k];
                    }
                }
            }

            // Solve L'*X = Y;
            for (int k = n - 1; k >= 0; k--)
            {
                for (int j = 0; j < count; j++)
                {
                    for (int i = k + 1; i < n; i++)
                    {
                        B[k, j] -= B[i, j] * L[i, k];
                    }

                    B[k, j] /= L[k, k];
                }
            }

            return(B);
        }
Exemplo n.º 14
0
        /// <summary>
        /// LU Decomposition
        /// </summary>
        /// <param name="matrix">Rectangular matrix</param>
        /// <returns>Structure to access L, U and piv.</returns>
        public LUDecomposition(Double[,] matrix)
        {
            // Use a "left-looking", dot-product, Crout / Doolittle algorithm.
            _LU      = (Double[, ])matrix.Clone();
            _rows    = matrix.GetLength(0);
            _columns = matrix.GetLength(1);
            _piv     = new Int32[_rows];

            for (var i = 1; i < _rows; i++)
            {
                _piv[i] = i;
            }

            _pivsign = 1;
            var LUcolj = new Double[_rows];

            // Outer loop.
            for (var j = 0; j < _columns; j++)
            {
                // Make a copy of the j-th column to localize references.
                for (var i = 0; i < _rows; i++)
                {
                    LUcolj[i] = _LU[i, j];
                }

                // Apply previous transformations.
                for (var i = 0; i < _rows; i++)
                {
                    var LUrowi = new Double[_columns];

                    for (var k = 0; k < _columns; k++)
                    {
                        LUrowi[k] = _LU[i, k];
                    }

                    // Most of the time is spent in the following dot product.
                    var kmax = Math.Min(i, j);
                    var s    = 0.0;

                    for (var k = 0; k < kmax; k++)
                    {
                        s += LUrowi[k] * LUcolj[k];
                    }

                    LUrowi[j] = LUcolj[i] -= s;
                }

                // Find pivot and exchange if necessary.
                var p = j;

                for (var i = j + 1; i < _rows; i++)
                {
                    if (Math.Abs(LUcolj[i]) > Math.Abs(LUcolj[p]))
                    {
                        p = i;
                    }
                }

                if (p != j)
                {
                    for (var k = 0; k < _columns; k++)
                    {
                        var t = _LU[p, k];
                        _LU[p, k] = _LU[j, k];
                        _LU[j, k] = t;
                    }

                    var k2 = _piv[p];
                    _piv[p]  = _piv[j];
                    _piv[j]  = k2;
                    _pivsign = -_pivsign;
                }

                // Compute multipliers.

                if (j < _rows & _LU[j, j] != 0.0)
                {
                    for (var i = j + 1; i < _rows; i++)
                    {
                        _LU[i, j] = _LU[i, j] / _LU[j, j];
                    }
                }
            }
        }
Exemplo n.º 15
0
        /// <summary>Constructs a QR decomposition.</summary>
        /// <param name="value">The matrix A to be decomposed.</param>
        /// <param name="transpose">True if the decomposition should be performed on
        /// the transpose of A rather than A itself, false otherwise. Default is false.</param>
        public QrDecomposition(Double[,] value, bool transpose)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            if ((!transpose && value.GetLength(0) < value.GetLength(1)) ||
                (transpose && value.GetLength(1) < value.GetLength(0)))
            {
                throw new ArgumentException("Matrix has more columns than rows.", "value");
            }

            this.qr = transpose ? value.Transpose() : (Double[, ])value.Clone();

            int rows = qr.GetLength(0);
            int cols = qr.GetLength(1);

            this.Rdiag = new Double[cols];

            for (int k = 0; k < cols; k++)
            {
                // Compute 2-norm of k-th column without under/overflow.
                Double nrm = 0;
                for (int i = k; i < rows; i++)
                {
                    nrm = Tools.Hypotenuse(nrm, qr[i, k]);
                }

                if (nrm != 0)
                {
                    // Form k-th Householder vector.
                    if (qr[k, k] < 0)
                    {
                        nrm = -nrm;
                    }

                    for (int i = k; i < rows; i++)
                    {
                        qr[i, k] /= nrm;
                    }

                    qr[k, k] += 1;

                    // Apply transformation to remaining columns.
                    for (int j = k + 1; j < cols; j++)
                    {
                        Double s = 0;

                        for (int i = k; i < rows; i++)
                        {
                            s += qr[i, k] * qr[i, j];
                        }

                        s = -s / qr[k, k];

                        for (int i = k; i < rows; i++)
                        {
                            qr[i, j] += s * qr[i, k];
                        }
                    }
                }

                this.Rdiag[k] = -nrm;
            }
        }
        /// <summary>
        ///   Construct an eigenvalue decomposition.</summary>
        ///
        /// <param name="value">
        ///   The matrix to be decomposed.</param>
        /// <param name="assumeSymmetric">
        ///   Defines if the matrix should be assumed as being symmetric
        ///   regardless if it is or not. Default is <see langword="false"/>.</param>
        /// <param name="inPlace">
        ///   Pass <see langword="true"/> to perform the decomposition in place. The matrix
        ///   <paramref name="value"/> will be destroyed in the process, resulting in less
        ///   memory comsumption.</param>
        /// <param name="sort">
        ///   Pass <see langword="true"/> to sort the eigenvalues and eigenvectors at the end
        ///   of the decomposition.</param>
        ///
        public EigenvalueDecomposition(Double[,] value, bool assumeSymmetric,
                                       bool inPlace = false, bool sort = false)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            if (value.GetLength(0) != value.GetLength(1))
            {
                throw new ArgumentException("Matrix is not a square matrix.", "value");
            }

            n = value.GetLength(1);
            V = new Double[n, n];
            d = new Double[n];
            e = new Double[n];


            this.symmetric = assumeSymmetric;

            if (this.symmetric)
            {
                V = inPlace ? value : (Double[, ])value.Clone();

                // Tridiagonalize.
                this.tred2();

                // Diagonalize.
                this.tql2();
            }
            else
            {
                H = inPlace ? value : (Double[, ])value.Clone();

                ort = new Double[n];

                // Reduce to Hessenberg form.
                this.orthes();

                // Reduce Hessenberg to real Schur form.
                this.hqr2();
            }

            if (sort)
            {
                // Sort eigenvalues and vectors in descending order
                var idx = Vector.Range(n);
                Array.Sort(idx, (i, j) =>
                {
                    if (Math.Abs(d[i]) == Math.Abs(d[j]))
                    {
                        return(-Math.Abs(e[i]).CompareTo(Math.Abs(e[j])));
                    }
                    return(-Math.Abs(d[i]).CompareTo(Math.Abs(d[j])));
                });

                this.d = this.d.Get(idx);
                this.e = this.e.Get(idx);
                this.V = this.V.Get(null, idx);
            }
        }
Exemplo n.º 17
0
        /// <summary>Constructs a new singular value decomposition.</summary>
        /// <param name="value">
        ///   The matrix to be decomposed.</param>
        public SingularValueDecomposition(Double[,] value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            //m should not less than n
            Double[,] a;
            m = value.GetLength(0); // rows
            n = value.GetLength(1); // cols

            if (m < n)
            {
                throw new System.Exception("rows should not less than cols in value matrix");
            }

            // Proceed anyway
            a = (Double[, ])value.Clone();


            int nu = System.Math.Min(m, n);
            int ni = System.Math.Min(m + 1, n);

            s = new Double[ni];
            u = new Double[m, nu];
            v = new Double[n, n];
            Double[] e    = new Double[n];
            Double[] work = new Double[m];

            // Will store ordered sequence of indices after sorting.
            si = new int[ni]; for (int i = 0; i < ni; i++)
            {
                si[i] = i;
            }


            // Reduce A to bidiagonal form, storing the diagonal elements in s and the super-diagonal elements in e.
            int nct = System.Math.Min(m - 1, n);
            int nrt = System.Math.Max(0, System.Math.Min(n - 2, m));

            for (int k = 0; k < System.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] = Hypotenuse(s[k], a[i, k]);
                    }

                    if (s[k] != 0)
                    {
                        if (a[k, k] < 0)
                        {
                            s[k] = -s[k];
                        }

                        for (int i = k; i < m; i++)
                        {
                            a[i, k] /= s[k];
                        }

                        a[k, k] += 1;
                    }

                    s[k] = -s[k];
                }

                for (int j = k + 1; j < n; j++)
                {
                    if ((k < nct) & (s[k] != 0))
                    {
                        // Apply the transformation.
                        Double t = 0;
                        for (int i = k; i < m; i++)
                        {
                            t += a[i, k] * a[i, j];
                        }

                        t = -t / a[k, k];

                        for (int i = k; i < m; i++)
                        {
                            a[i, j] += t * a[i, k];
                        }
                    }

                    // Place the k-th row of A into e for the subsequent calculation of the row transformation.
                    e[j] = a[k, j];
                }


                if (k < nct)
                {
                    // Place the transformation in U for subsequent back
                    // multiplication.
                    for (int i = k; i < m; i++)
                    {
                        u[i, k] = a[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] = 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;
                        }

                        int k1 = k + 1;
                        for (int i = k1; i < m; i++)
                        {
                            for (int j = k1; j < n; j++)
                            {
                                work[i] += e[j] * a[i, j];
                            }
                        }

                        for (int j = k1; j < n; j++)
                        {
                            Double t = -e[j] / e[k1];
                            for (int i = k1; i < m; i++)
                            {
                                a[i, j] += t * work[i];
                            }
                        }
                    }

                    // 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 = System.Math.Min(n, m + 1);

            if (nct < n)
            {
                s[nct] = a[nct, nct];
            }
            if (m < p)
            {
                s[p - 1] = 0;
            }
            if (nrt + 1 < p)
            {
                e[nrt] = a[nrt, p - 1];
            }
            e[p - 1] = 0;

            //generate U.
            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++)
                    {
                        Double 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] = -1.0 * 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;
                }
            }


            //generate V.
            for (int k = n - 1; k >= 0; k--)
            {
                if ((k < nrt) & (e[k] != 0))
                {
                    // TODO: The following is a pseudo correction to make SVD
                    //  work on matrices with n > m (less rows than columns).

                    // For the proper correction, compute the decomposition of the
                    //  transpose of A and swap the left and right eigenvectors

                    // Original line:
                    //   for (int j = k + 1; j < nu; j++)
                    // Pseudo correction:
                    //   for (int j = k + 1; j < n; j++)

                    for (int j = k + 1; j < n; j++) // pseudo-correction
                    {
                        Double 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;

            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 (System.Math.Abs(e[k]) <=
                        tiny + eps * (System.Math.Abs(s[k]) + System.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;
                        }

                        Double t = (ks != p ? System.Math.Abs(e[ks]) : 0) +
                                   (ks != k + 1 ? System.Math.Abs(e[ks - 1]) : 0);
                        if (System.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:
                {
                    Double f = e[p - 2];
                    e[p - 2] = 0;
                    for (int j = p - 2; j >= k; j--)
                    {
                        Double t  = Hypotenuse(s[j], f);
                        Double cs = s[j] / t;
                        Double sn = f / t;
                        s[j] = t;
                        if (j != k)
                        {
                            f        = -sn * e[j - 1];
                            e[j - 1] = cs * e[j - 1];
                        }

                        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:
                {
                    Double f = e[k - 1];
                    e[k - 1] = 0;
                    for (int j = k; j < p; j++)
                    {
                        Double t  = Hypotenuse(s[j], f);
                        Double cs = s[j] / t;
                        Double sn = f / t;
                        s[j] = t;
                        f    = -sn * e[j];
                        e[j] = cs * e[j];

                        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.
                    Double scale = System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Abs(s[p - 1]), System.Math.Abs(s[p - 2])), System.Math.Abs(e[p - 2])), System.Math.Abs(s[k])), System.Math.Abs(e[k]));
                    Double sp    = s[p - 1] / scale;
                    Double spm1  = s[p - 2] / scale;
                    Double epm1  = e[p - 2] / scale;
                    Double sk    = s[k] / scale;
                    Double ek    = e[k] / scale;
                    Double b     = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;
                    Double c     = (sp * epm1) * (sp * epm1);
                    double shift = 0;

                    if ((b != 0) | (c != 0))
                    {
                        if (b < 0)
                        {
                            shift = -System.Math.Sqrt(b * b + c);
                        }
                        else
                        {
                            shift = System.Math.Sqrt(b * b + c);
                        }

                        shift = c / (b + shift);
                    }

                    Double f = (sk + sp) * (sk - sp) + (Double)shift;
                    Double g = sk * ek;

                    // Chase zeros.
                    for (int j = k; j < p - 1; j++)
                    {
                        Double t  = Hypotenuse(f, g);
                        Double cs = f / t;
                        Double 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];

                        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;*/

                            Double vij  = v[i, j];        // *vj;
                            Double vij1 = v[i, j + 1];    // *vj1;

                            t           = cs * vij + sn * vij1;
                            v[i, j + 1] = -sn * vij + cs * vij1;
                            v[i, j]     = t;
                        }

                        t        = 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 (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;*/

                                Double uij  = u[i, j];        // *uj;
                                Double uij1 = u[i, j + 1];    // *uj1;

                                t = cs * uij + sn * uij1;

                                u[i, j + 1] = -sn * uij + cs * uij1;
                                u[i, j]     = t;
                            }
                        }
                    }

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

                // Convergence.
                case 4:
                {
                    // Make the singular values positive.
                    if (s[k] <= 0)
                    {
                        s[k] = (s[k] < 0 ? -s[k] : 0);

                        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;
                        }

                        Double t = s[k];
                        s[k]     = s[k + 1];
                        s[k + 1] = t;

                        int ti = si[k];
                        si[k]     = si[k + 1];
                        si[k + 1] = ti;

                        if (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 (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;
                }
            }
        }
Exemplo n.º 18
0
        /// <summary>
        ///   Constructs a new singular value decomposition.
        /// </summary>
        ///
        /// <param name="value">
        ///   The matrix to be decomposed.</param>
        /// <param name="computeLeftSingularVectors">
        ///   Pass <see langword="true"/> if the left singular vector matrix U
        ///   should be computed. Pass <see langword="false"/> otherwise. Default
        ///   is <see langword="true"/>.</param>
        /// <param name="computeRightSingularVectors">
        ///   Pass <see langword="true"/> if the right singular vector matrix V
        ///   should be computed. Pass <see langword="false"/> otherwise. Default
        ///   is <see langword="true"/>.</param>
        /// <param name="autoTranspose">
        ///   Pass <see langword="true"/> to automatically transpose the value matrix in
        ///   case JAMA's assumptions about the dimensionality of the matrix are violated.
        ///   Pass <see langword="false"/> otherwise. Default is <see langword="false"/>.</param>
        /// <param name="inPlace">
        ///   Pass <see langword="true"/> to perform the decomposition in place. The matrix
        ///   <paramref name="value"/> will be destroyed in the process, resulting in less
        ///   memory comsumption.</param>
        ///
        public unsafe SingularValueDecomposition(Double[,] value,
                                                 bool computeLeftSingularVectors, bool computeRightSingularVectors, bool autoTranspose, bool inPlace)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value", "Matrix cannot be null.");
            }

            Double[,] a;
            m = value.GetLength(0); // rows
            n = value.GetLength(1); // cols

            if (m == 0 || n == 0)
            {
                throw new ArgumentException("Matrix does not have any rows or columns.", "value");
            }



            if (m < n)              // Check if we are violating JAMA's assumption
            {
                if (!autoTranspose) // Yes, check if we should correct it
                {
                    // Warning! This routine is not guaranteed to work when A has less rows
                    //  than columns. If this is the case, you should compute SVD on the
                    //  transpose of A and then swap the left and right eigenvectors.

                    // However, as the solution found can still be useful, the exception below
                    // will not be thrown, and only a warning will be output in the trace.

                    // throw new ArgumentException("Matrix should have more rows than columns.");

                    System.Diagnostics.Trace.WriteLine(
                        "WARNING: Computing SVD on a matrix with more columns than rows.");

                    // Proceed anyway
                    a = inPlace ? value : (Double[, ])value.Clone();
                }
                else
                {
                    // Transposing and swapping
                    a       = value.Transpose(inPlace && m == n);
                    m       = value.GetLength(1);
                    n       = value.GetLength(0);
                    swapped = true;

                    bool aux = computeLeftSingularVectors;
                    computeLeftSingularVectors  = computeRightSingularVectors;
                    computeRightSingularVectors = aux;
                }
            }
            else
            {
                // Input matrix is ok
                a = inPlace ? value : (Double[, ])value.Clone();
            }


            int nu = System.Math.Min(m, n);
            int ni = System.Math.Min(m + 1, n);

            s = new Double[ni];
            u = new Double[m, nu];
            v = new Double[n, n];
            Double[] e     = new Double[n];
            Double[] work  = new Double[m];
            bool     wantu = computeLeftSingularVectors;
            bool     wantv = computeRightSingularVectors;

            fixed(Double *U = u)
            fixed(Double * V = v)
            fixed(Double * A = a)
            {
                // Will store ordered sequence of indices after sorting.
                si = new int[ni]; for (int i = 0; i < ni; i++)
                {
                    si[i] = i;
                }


                // Reduce A to bidiagonal form, storing the diagonal elements in s and the super-diagonal elements in e.
                int nct = System.Math.Min(m - 1, n);
                int nrt = System.Math.Max(0, System.Math.Min(n - 2, m));

                for (int k = 0; k < System.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] = Accord.Math.Tools.Hypotenuse(s[k], a[i, k]);
                        }

                        if (s[k] != 0)
                        {
                            if (a[k, k] < 0)
                            {
                                s[k] = -s[k];
                            }

                            for (int i = k; i < m; i++)
                            {
                                a[i, k] /= s[k];
                            }

                            a[k, k] += 1;
                        }

                        s[k] = -s[k];
                    }

                    for (int j = k + 1; j < n; j++)
                    {
                        Double *ptr_ak = A + k * n + k; // A[k,k]
                        Double *ptr_aj = A + k * n + j; // A[k,j]

                        if ((k < nct) & (s[k] != 0))
                        {
                            // Apply the transformation.
                            Double  t  = 0;
                            Double *ak = ptr_ak;
                            Double *aj = ptr_aj;

                            for (int i = k; i < m; i++)
                            {
                                t  += (*ak) * (*aj);
                                ak += n; aj += n;
                            }

                            t  = -t / *ptr_ak;
                            ak = ptr_ak;
                            aj = ptr_aj;

                            for (int i = k; i < m; i++)
                            {
                                *aj += t * (*ak);
                                ak += n; aj += n;
                            }
                        }

                        // Place the k-th row of A into e for the subsequent calculation of the row transformation.
                        e[j] = *ptr_aj;
                    }


                    if (wantu & (k < nct))
                    {
                        // Place the transformation in U for subsequent back
                        // multiplication.
                        for (int i = k; i < m; i++)
                        {
                            u[i, k] = a[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] = Accord.Math.Tools.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;
                            }

                            int k1 = k + 1;
                            for (int i = k1; i < m; i++)
                            {
                                Double *ai = A + (i * n) + k1;
                                for (int j = k1; j < n; j++, ai++)
                                {
                                    work[i] += e[j] * (*ai);
                                }
                            }

                            for (int j = k1; j < n; j++)
                            {
                                Double  t  = -e[j] / e[k1];
                                Double *aj = A + (k1 * n) + j;
                                for (int i = k1; i < m; i++, aj += n)
                                {
                                    *aj += 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 = System.Math.Min(n, m + 1);

                if (nct < n)
                {
                    s[nct] = a[nct, nct];
                }
                if (m < p)
                {
                    s[p - 1] = 0;
                }
                if (nrt + 1 < p)
                {
                    e[nrt] = a[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)
                        {
                            Double *ptr_uk = U + k * nu + k; // u[k,k]

                            Double *uk, uj;
                            for (int j = k + 1; j < nu; j++)
                            {
                                Double *ptr_uj = U + k * nu + j; // u[k,j]

                                Double t = 0;
                                uk = ptr_uk;
                                uj = ptr_uj;

                                for (int i = k; i < m; i++)
                                {
                                    t  += *uk * *uj;
                                    uk += nu; uj += nu;
                                }

                                t = -t / *ptr_uk;

                                uk = ptr_uk; uj = ptr_uj;
                                for (int i = k; i < m; i++)
                                {
                                    *uj += t * (*uk);
                                    uk += nu; uj += nu;
                                }
                            }

                            uk = ptr_uk;
                            for (int i = k; i < m; i++)
                            {
                                *uk = -(*uk);
                                uk += nu;
                            }

                            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))
                        {
                            // TODO: The following is a pseudo correction to make SVD
                            //  work on matrices with n > m (less rows than columns).

                            // For the proper correction, compute the decomposition of the
                            //  transpose of A and swap the left and right eigenvectors

                            // Original line:
                            //   for (int j = k + 1; j < nu; j++)
                            // Pseudo correction:
                            //   for (int j = k + 1; j < n; j++)

                            for (int j = k + 1; j < n; j++)           // pseudo-correction
                            {
                                Double *ptr_vk = V + (k + 1) * n + k; // v[k + 1, k]
                                Double *ptr_vj = V + (k + 1) * n + j; // v[k + 1, j]

                                Double  t  = 0;
                                Double *vk = ptr_vk;
                                Double *vj = ptr_vj;

                                for (int i = k + 1; i < n; i++)
                                {
                                    t  += *vk * *vj;
                                    vk += n; vj += n;
                                }

                                t = -t / *ptr_vk;

                                vk = ptr_vk; vj = ptr_vj;
                                for (int i = k + 1; i < n; i++)
                                {
                                    *vj += t * (*vk);
                                    vk += n; vj += n;
                                }
                            }
                        }

                        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;

                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 (System.Math.Abs(e[k]) <=
                            tiny + eps * (System.Math.Abs(s[k]) + System.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;
                            }

                            Double t = (ks != p ? System.Math.Abs(e[ks]) : 0) +
                                       (ks != k + 1 ? System.Math.Abs(e[ks - 1]) : 0);
                            if (System.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:
                    {
                        Double f = e[p - 2];
                        e[p - 2] = 0;
                        for (int j = p - 2; j >= k; j--)
                        {
                            Double t  = Accord.Math.Tools.Hypotenuse(s[j], f);
                            Double cs = s[j] / t;
                            Double 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:
                    {
                        Double f = e[k - 1];
                        e[k - 1] = 0;
                        for (int j = k; j < p; j++)
                        {
                            Double t  = Accord.Math.Tools.Hypotenuse(s[j], f);
                            Double cs = s[j] / t;
                            Double 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.
                        Double scale = System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Max(System.Math.Abs(s[p - 1]), System.Math.Abs(s[p - 2])), System.Math.Abs(e[p - 2])), System.Math.Abs(s[k])), System.Math.Abs(e[k]));
                        Double sp    = s[p - 1] / scale;
                        Double spm1  = s[p - 2] / scale;
                        Double epm1  = e[p - 2] / scale;
                        Double sk    = s[k] / scale;
                        Double ek    = e[k] / scale;
                        Double b     = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;
                        Double c     = (sp * epm1) * (sp * epm1);
                        double shift = 0;

                        if ((b != 0) | (c != 0))
                        {
                            if (b < 0)
                            {
                                shift = -System.Math.Sqrt(b * b + c);
                            }
                            else
                            {
                                shift = System.Math.Sqrt(b * b + c);
                            }

                            shift = c / (b + shift);
                        }

                        Double f = (sk + sp) * (sk - sp) + (Double)shift;
                        Double g = sk * ek;

                        // Chase zeros.
                        for (int j = k; j < p - 1; j++)
                        {
                            Double t  = Accord.Math.Tools.Hypotenuse(f, g);
                            Double cs = f / t;
                            Double 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)
                            {
                                unsafe
                                {
                                    fixed(Double *ptr_vj = &v[0, j])
                                    {
                                        Double *vj  = ptr_vj;
                                        Double *vj1 = ptr_vj + 1;

                                        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;*/

                                            Double vij  = *vj;
                                            Double vij1 = *vj1;

                                            t = cs * vij + sn * vij1;
                                            *vj1 = -sn * vij + cs * vij1;
                                            *vj  = t;

                                            vj += n; vj1 += n;
                                        }
                                    }
                                }
                            }

                            t        = Accord.Math.Tools.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))
                            {
                                fixed(Double *ptr_uj = &u[0, j])
                                {
                                    Double *uj  = ptr_uj;
                                    Double *uj1 = ptr_uj + 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;*/

                                        Double uij  = *uj;
                                        Double uij1 = *uj1;

                                        t = cs * uij + sn * uij1;
                                        *uj1 = -sn * uij + cs * uij1;
                                        *uj  = t;

                                        uj += nu; uj1 += nu;
                                    }
                                }
                            }
                        }

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

                    // Convergence.
                    case 4:
                    {
                        // Make the singular values positive.
                        if (s[k] <= 0)
                        {
                            s[k] = (s[k] < 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;
                            }

                            Double t = s[k];
                            s[k]     = s[k + 1];
                            s[k + 1] = t;

                            int ti = si[k];
                            si[k]     = si[k + 1];
                            si[k + 1] = ti;

                            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;
                    }
                }
            }

            // If we are violating JAMA's assumption about
            // the input dimension, we need to swap u and v.
            if (swapped)
            {
                Double[,] temp = this.u;
                this.u         = this.v;
                this.v         = temp;
            }
        }
Exemplo n.º 19
0
        public static void CheckBaumWelch()
        {
            // 状态转移矩阵
            Double[,] A =
            {
                { 0.500, 0.250, 0.250 },
                { 0.375, 0.125, 0.375 },
                { 0.125, 0.675, 0.375 }
            };

            // 混淆矩阵
            Double[,] B =
            {
                { 0.60, 0.20, 0.15, 0.05 },
                { 0.25, 0.25, 0.25, 0.25 },
                { 0.05, 0.10, 0.35, 0.50 }
            };

            // 初始概率向量
            Double[] PI = { 0.63, 0.17, 0.20 };

            // 观察序列
            Int32[] OB = { (Int32)Seaweed.Dry, (Int32)Seaweed.Damp, (Int32)Seaweed.Soggy, (Int32)Seaweed.Dryish, (Int32)Seaweed.Dry };

            // 初始化HMM模型
            HMM hmm = new HMM(A.GetLength(0), B.GetLength(1));

            // 数组克隆,避免损坏原始数据
            hmm.A  = (Double[, ])A.Clone();
            hmm.B  = (Double[, ])B.Clone();
            hmm.PI = (Double[])PI.Clone();

            // 前向-后向算法
            Console.WriteLine("------------Baum-Welch算法-----------------");
            Double LogProbInit, LogProbFinal;
            Int32  Iterations = hmm.BaumWelch(OB, out LogProbInit, out LogProbFinal);

            Console.WriteLine("迭代次数 = {0}", Iterations);
            Console.WriteLine("初始概率 = {0}", Math.Exp(LogProbInit));
            Console.WriteLine("最终概率 = {0}", Math.Exp(LogProbFinal));
            Console.WriteLine();

            // 打印学习后的模型参数
            Console.WriteLine("新的模型参数:");
            Console.WriteLine("PI");
            for (Int32 i = 0; i < hmm.N; i++)
            {
                if (i == 0)
                {
                    Console.Write(hmm.PI[i].ToString("0.000"));
                }
                else
                {
                    Console.Write(" " + hmm.PI[i].ToString("0.000"));
                }
            }
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("A");
            for (Int32 i = 0; i < hmm.N; i++)
            {
                for (Int32 j = 0; j < hmm.N; j++)
                {
                    if (j == 0)
                    {
                        Console.Write(hmm.A[i, j].ToString("0.000"));
                    }
                    else
                    {
                        Console.Write(" " + hmm.A[i, j].ToString("0.000"));
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            Console.WriteLine("B");
            for (Int32 i = 0; i < hmm.N; i++)
            {
                for (Int32 j = 0; j < hmm.M; j++)
                {
                    if (j == 0)
                    {
                        Console.Write(hmm.B[i, j].ToString("0.000"));
                    }
                    else
                    {
                        Console.Write(" " + hmm.B[i, j].ToString("0.000"));
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }