QLNet.SVD.SVD C# (CSharp) Метод

SVD() публичный Метод

public SVD ( Matrix M ) : System
M Matrix
Результат System
        public SVD(Matrix M)
        {
            Matrix A;

            /* The implementation requires that rows > columns.
               If this is not the case, we decompose M^T instead.
               Swapping the resulting U and V gives the desired
               result for M as

               M^T = U S V^T           (decomposition of M^T)

               M = (U S V^T)^T         (transpose)

               M = (V^T^T S^T U^T)     ((AB)^T = B^T A^T)

               M = V S U^T             (idempotence of transposition,
                                        symmetry of diagonal matrix S)
            */

            if (M.rows() >= M.columns()) {
                A = new Matrix(M);
                transpose_ = false;
            } else {
                A = Matrix.transpose(M);
                transpose_ = true;
            }

            m_ = A.rows();
            n_ = A.columns();

            // we're sure that m_ >= n_
            s_ = new Vector(n_);
            U_ = new Matrix(m_, n_);
            V_ = new Matrix(n_, n_);
            Vector e = new Vector(n_);
            Vector work = new Vector(m_);
            int i, j, k;

            // 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, n_ - 2);
            for (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 (i = k; i < m_; i++) {
                        s_[k] = hypot(s_[k], A[i, k]);
                    }
                    if (s_[k] != 0.0) {
                        if (A[k, k] < 0.0) {
                            s_[k] = -s_[k];
                        }
                        for (i = k; i < m_; i++) {
                            A[i, k] /= s_[k];
                        }
                        A[k, k] += 1.0;
                    }
                    s_[k] = -s_[k];
                }
                for (j = k + 1; j < n_; j++) {
                    if ((k < nct) && (s_[k] != 0.0)) {

                        // Apply the transformation.
                        double t = 0;
                        for (i = k; i < m_; i++) {
                            t += A[i, k] * A[i, j];
                        }
                        t = -t / A[k, k];
                        for (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 (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 (i = k + 1; i < n_; i++) {
                        e[k] = hypot(e[k], e[i]);
                    }
                    if (e[k] != 0.0) {
                        if (e[k + 1] < 0.0) {
                            e[k] = -e[k];
                        }
                        for (i = k + 1; i < n_; i++) {
                            e[i] /= e[k];
                        }
                        e[k + 1] += 1.0;
                    }
                    e[k] = -e[k];
                    if ((k + 1 < m_) & (e[k] != 0.0)) {
                        // Apply the transformation.
                        for (i = k + 1; i < m_; i++) {
                            work[i] = 0.0;
                        }
                        for (j = k + 1; j < n_; j++) {
                            for (i = k + 1; i < m_; i++) {
                                work[i] += e[j] * A[i, j];
                            }
                        }
                        for (j = k + 1; j < n_; j++) {
                            double t = -e[j] / e[k + 1];
                            for (i = k + 1; i < m_; i++) {
                                A[i, j] += t * work[i];
                            }
                        }
                    }

                    // Place the transformation in V for subsequent back multiplication.
                    for (i = k + 1; i < n_; i++) {
                        V_[i, k] = e[i];
                    }
                }
            }

            // Set up the final bidiagonal matrix or order n.
            if (nct < n_) {
                s_[nct] = A[nct, nct];
            }
            if (nrt + 1 < n_) {
                e[nrt] = A[nrt, n_ - 1];
            }
            e[n_ - 1] = 0.0;

            // generate U
            for (j = nct; j < n_; j++) {
                for (i = 0; i < m_; i++) {
                    U_[i, j] = 0.0;
                }
                U_[j, j] = 1.0;
            }
            for (k = nct - 1; k >= 0; --k) {
                if (s_[k] != 0.0) {
                    for (j = k + 1; j < n_; ++j) {
                        double t = 0;
                        for (i = k; i < m_; i++) {
                            t += U_[i, k] * U_[i, j];
                        }
                        t = -t / U_[k, k];
                        for (i = k; i < m_; i++) {
                            U_[i, j] += t * U_[i, k];
                        }
                    }
                    for (i = k; i < m_; i++) {
                        U_[i, k] = -U_[i, k];
                    }
                    U_[k, k] = 1.0 + U_[k, k];
                    for (i = 0; i < k - 1; i++) {
                        U_[i, k] = 0.0;
                    }
                } else {
                    for (i = 0; i < m_; i++) {
                        U_[i, k] = 0.0;
                    }
                    U_[k, k] = 1.0;
                }
            }

            // generate V
            for (k = n_ - 1; k >= 0; --k) {
                if ((k < nrt) & (e[k] != 0.0)) {
                    for (j = k + 1; j < n_; ++j) {
                        double t = 0;
                        for (i = k + 1; i < n_; i++) {
                            t += V_[i, k] * V_[i, j];
                        }
                        t = -t / V_[k + 1, k];
                        for (i = k + 1; i < n_; i++) {
                            V_[i, j] += t * V_[i, k];
                        }
                    }
                }
                for (i = 0; i < n_; i++) {
                    V_[i, k] = 0.0;
                }
                V_[k, k] = 1.0;
            }

            // Main iteration loop for the singular values.
            int p = n_, pp = p - 1;
            int iter = 0;
            double eps = Math.Pow(2.0, -52.0);
            while (p > 0) {
                int 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]) <= eps * (Math.Abs(s_[k]) + Math.Abs(s_[k + 1]))) {
                        e[k] = 0.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 ? Math.Abs(e[ks]) : 0) +
                            (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0);
                        if (Math.Abs(s_[ks]) <= eps * t) {
                            s_[ks] = 0.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.0;
                            for (j = p - 2; j >= k; --j) {
                                double t = hypot(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 (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.0;
                            for (j = k; j < p; j++) {
                                double t = hypot(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 (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 = 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]));
                            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.0;
                            double c = (sp * epm1) * (sp * epm1);
                            double shift = 0.0;
                            if ((b != 0.0) | (c != 0.0)) {
                                shift = Math.Sqrt(b * b + c);
                                if (b < 0.0) {
                                    shift = -shift;
                                }
                                shift = c / (b + shift);
                            }
                            double f = (sk + sp) * (sk - sp) + shift;
                            double g = sk * ek;

                            // Chase zeros.
                            for (j = k; j < p - 1; j++) {
                                double t = hypot(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 (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 = hypot(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 (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.0);
                                for (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;
                                }
                                s_.swap(k, k + 1);
                                if (k < n_ - 1) {
                                    for (i = 0; i < n_; i++) {
                                        V_.swap(i, k, i, k + 1);
                                    }
                                }
                                if (k < m_ - 1) {
                                    for (i = 0; i < m_; i++) {
                                        U_.swap(i, k, i, k + 1);
                                    }
                                }
                                k++;
                            }
                            iter = 0;
                            --p;
                        }
                        break;
                }
            }
        }