📄 svd.c
字号:
} } /* Convert A into an orthogonal matrix L */ for (j = N; j > 0 && j--;) { /* Householder column transformation to accumulate L */ double tj = gsl_vector_get (S, j); gsl_matrix_view m = gsl_matrix_submatrix (A, j, j, M - j, N - j); gsl_linalg_householder_hm1 (tj, &m.matrix); } /* unpack R into X V S */ gsl_linalg_SV_decomp (X, V, S, work); /* Multiply L by X, to obtain U = L X, stored in U */ { gsl_vector_view sum = gsl_vector_subvector (work, 0, N); for (i = 0; i < M; i++) { gsl_vector_view L_i = gsl_matrix_row (A, i); gsl_vector_set_zero (&sum.vector); for (j = 0; j < N; j++) { double Lij = gsl_vector_get (&L_i.vector, j); gsl_vector_view X_j = gsl_matrix_row (X, j); gsl_blas_daxpy (Lij, &X_j.vector, &sum.vector); } gsl_vector_memcpy (&L_i.vector, &sum.vector); } } return GSL_SUCCESS;}/* Solves the system A x = b using the SVD factorization * * A = U S V^T * * to obtain x. For M x N systems it finds the solution in the least * squares sense. */intgsl_linalg_SV_solve (const gsl_matrix * U, const gsl_matrix * V, const gsl_vector * S, const gsl_vector * b, gsl_vector * x){ if (U->size1 != b->size) { GSL_ERROR ("first dimension of matrix U must size of vector b", GSL_EBADLEN); } else if (U->size2 != S->size) { GSL_ERROR ("length of vector S must match second dimension of matrix U", GSL_EBADLEN); } else if (V->size1 != V->size2) { GSL_ERROR ("matrix V must be square", GSL_ENOTSQR); } else if (S->size != V->size1) { GSL_ERROR ("length of vector S must match size of matrix V", GSL_EBADLEN); } else if (V->size2 != x->size) { GSL_ERROR ("size of matrix V must match size of vector x", GSL_EBADLEN); } else { const size_t N = U->size2; size_t i; gsl_vector *w = gsl_vector_calloc (N); gsl_blas_dgemv (CblasTrans, 1.0, U, b, 0.0, w); for (i = 0; i < N; i++) { double wi = gsl_vector_get (w, i); double alpha = gsl_vector_get (S, i); if (alpha != 0) alpha = 1.0 / alpha; gsl_vector_set (w, i, alpha * wi); } gsl_blas_dgemv (CblasNoTrans, 1.0, V, w, 0.0, x); gsl_vector_free (w); return GSL_SUCCESS; }}/* This is a the jacobi version *//* Author: G. Jungman *//* * Algorithm due to J.C. Nash, Compact Numerical Methods for * Computers (New York: Wiley and Sons, 1979), chapter 3. * See also Algorithm 4.1 in * James Demmel, Kresimir Veselic, "Jacobi's Method is more * accurate than QR", Lapack Working Note 15 (LAWN15), October 1989. * Available from netlib. * * Based on code by Arthur Kosowsky, Rutgers University * kosowsky@physics.rutgers.edu * * Another relevant paper is, P.P.M. De Rijk, "A One-Sided Jacobi * Algorithm for computing the singular value decomposition on a * vector computer", SIAM Journal of Scientific and Statistical * Computing, Vol 10, No 2, pp 359-371, March 1989. * */intgsl_linalg_SV_decomp_jacobi (gsl_matrix * A, gsl_matrix * Q, gsl_vector * S){ if (A->size1 < A->size2) { /* FIXME: only implemented M>=N case so far */ GSL_ERROR ("svd of MxN matrix, M<N, is not implemented", GSL_EUNIMPL); } else if (Q->size1 != A->size2) { GSL_ERROR ("square matrix Q must match second dimension of matrix A", GSL_EBADLEN); } else if (Q->size1 != Q->size2) { GSL_ERROR ("matrix Q must be square", GSL_ENOTSQR); } else if (S->size != A->size2) { GSL_ERROR ("length of vector S must match second dimension of matrix A", GSL_EBADLEN); } else { const size_t M = A->size1; const size_t N = A->size2; size_t i, j, k; /* Initialize the rotation counter and the sweep counter. */ int count = 1; int sweep = 0; int sweepmax = 5*N; double tolerance = 10 * M * GSL_DBL_EPSILON; /* Always do at least 12 sweeps. */ sweepmax = GSL_MAX (sweepmax, 12); /* Set Q to the identity matrix. */ gsl_matrix_set_identity (Q); /* Store the column error estimates in S, for use during the orthogonalization */ for (j = 0; j < N; j++) { gsl_vector_view cj = gsl_matrix_column (A, j); double sj = gsl_blas_dnrm2 (&cj.vector); gsl_vector_set(S, j, GSL_DBL_EPSILON * sj); } /* Orthogonalize A by plane rotations. */ while (count > 0 && sweep <= sweepmax) { /* Initialize rotation counter. */ count = N * (N - 1) / 2; for (j = 0; j < N - 1; j++) { for (k = j + 1; k < N; k++) { double a = 0.0; double b = 0.0; double p = 0.0; double q = 0.0; double cosine, sine; double v; double abserr_a, abserr_b; int sorted, orthog, noisya, noisyb; gsl_vector_view cj = gsl_matrix_column (A, j); gsl_vector_view ck = gsl_matrix_column (A, k); gsl_blas_ddot (&cj.vector, &ck.vector, &p); p *= 2.0 ; /* equation 9a: p = 2 x.y */ a = gsl_blas_dnrm2 (&cj.vector); b = gsl_blas_dnrm2 (&ck.vector); q = a * a - b * b; v = hypot(p, q); /* test for columns j,k orthogonal, or dominant errors */ abserr_a = gsl_vector_get(S,j); abserr_b = gsl_vector_get(S,k); sorted = (gsl_coerce_double(a) >= gsl_coerce_double(b)); orthog = (fabs (p) <= tolerance * gsl_coerce_double(a * b)); noisya = (a < abserr_a); noisyb = (b < abserr_b); if (sorted && (orthog || noisya || noisyb)) { count--; continue; } /* calculate rotation angles */ if (v == 0 || !sorted) { cosine = 0.0; sine = 1.0; } else { cosine = sqrt((v + q) / (2.0 * v)); sine = p / (2.0 * v * cosine); } /* apply rotation to A */ for (i = 0; i < M; i++) { const double Aik = gsl_matrix_get (A, i, k); const double Aij = gsl_matrix_get (A, i, j); gsl_matrix_set (A, i, j, Aij * cosine + Aik * sine); gsl_matrix_set (A, i, k, -Aij * sine + Aik * cosine); } gsl_vector_set(S, j, fabs(cosine) * abserr_a + fabs(sine) * abserr_b); gsl_vector_set(S, k, fabs(sine) * abserr_a + fabs(cosine) * abserr_b); /* apply rotation to Q */ for (i = 0; i < N; i++) { const double Qij = gsl_matrix_get (Q, i, j); const double Qik = gsl_matrix_get (Q, i, k); gsl_matrix_set (Q, i, j, Qij * cosine + Qik * sine); gsl_matrix_set (Q, i, k, -Qij * sine + Qik * cosine); } } } /* Sweep completed. */ sweep++; } /* * Orthogonalization complete. Compute singular values. */ { double prev_norm = -1.0; for (j = 0; j < N; j++) { gsl_vector_view column = gsl_matrix_column (A, j); double norm = gsl_blas_dnrm2 (&column.vector); /* Determine if singular value is zero, according to the criteria used in the main loop above (i.e. comparison with norm of previous column). */ if (norm == 0.0 || prev_norm == 0.0 || (j > 0 && norm <= tolerance * prev_norm)) { gsl_vector_set (S, j, 0.0); /* singular */ gsl_vector_set_zero (&column.vector); /* annihilate column */ prev_norm = 0.0; } else { gsl_vector_set (S, j, norm); /* non-singular */ gsl_vector_scale (&column.vector, 1.0 / norm); /* normalize column */ prev_norm = norm; } } } if (count > 0) { /* reached sweep limit */ GSL_ERROR ("Jacobi iterations did not reach desired tolerance", GSL_ETOL); } return GSL_SUCCESS; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -