Una implementación independiente y con plantilla de SVD está disponible en la biblioteca PVFMM (Ver archivo: include / mat_utils.txx). La biblioteca es de código abierto y está alojada en GitHub. También está disponible para su descarga desde el sitio web de la Universidad de Texas:
Es Algoritmo1 en:
(Cálculo de la descomposición del valor singular, Alan Kaylor Cline, Inderjit S. Dhillon)
- ¿Cuál es el procedimiento para encontrar la disponibilidad de un puesto postdoc en los Estados Unidos?
- ¿Qué está haciendo Jacob Lurie?
- ¿Por qué las humanidades están en contra del acceso abierto?
- ¿Cuáles son los beneficios de seguir un postdoc después de obtener un doctorado?
- ¿Cómo debe verse una propuesta de disertación creativa?
Lo implementé para calcular SVD en precisión cuádruple. Mi implementación no es muy eficiente ya que solo la necesito para el cálculo previo sin conexión.
La función svd
usa la interfaz para dgesvd
en LAPACK, con JOBU = ‘S’ y JOBVT = ‘S’, con la excepción de que los valores singulares no están ordenados.
Este código está disponible gratis sin garantía de ningún tipo.
#include #include #include #include #include #include #definir U (i, j) U _ [(i) * dim [0] + (j)] # define S (i, j) S _ [(i) * dim [1] + (j)] #define V (i, j) V _ [(i) * dim [1] + (j)] plantilla nulo GivensL (T * S_, const size_t dim [2], size_t m, T a, T b) { T r = sqrt (a * a + b * b); T c = a / r; T s = -b / r; #pragma omp paralelo para for (size_t i = 0; i <dim [1]; i ++) { T S0 = S (m + 0, i); T S1 = S (m + 1, i); S (m, i) + = S0 * (c-1); S (m, i) + = S1 * (- s); S (m + 1, i) + = S0 * (s); S (m + 1, i) + = S1 * (c-1); } } plantilla GivensR nulo (T * S_, const size_t dim [2], size_t m, T a, T b) { T r = sqrt (a * a + b * b); T c = a / r; T s = -b / r; #pragma omp paralelo para for (size_t i = 0; i <dim [0]; i ++) { T S0 = S (i, m + 0); T S1 = S (i, m + 1); S (i, m) + = S0 * (c-1); S (i, m) + = S1 * (- s); S (i, m + 1) + = S0 * (s); S (i, m + 1) + = S1 * (c-1); } } plantilla SVD nulo (const size_t dim [2], T * U_, T * S_, T * V_, T eps = -1) { afirmar (dim [0]> = dim [1]); {// Bi-diagonalización size_t n = std :: min (dim [0], dim [1]); std :: vector house_vec (std :: max (dim [0], dim [1])); para (size_t i = 0; i <n; i ++) { // Jefe de familia de columna { T x1 = S (i, i); si (x1 <0) x1 = -x1; T x_inv_norm = 0; para (size_t j = i; j 0) x_inv_norm = 1 / sqrt (x_inv_norm); T alfa = sqrt (1 + x1 * x_inv_norm); T beta = x_inv_norm / alpha; house_vec [i] = - alfa; para (size_t j = i + 1; j <dim [0]; j ++) { house_vec [j] = - beta * S (j, i); } if (S (i, i) <0) para (size_t j = i + 1; j <dim [0]; j ++) { house_vec [j] = - house_vec [j]; } } #pragma omp paralelo para para (size_t k = i; k <dim [1]; k ++) { T dot_prod = 0; para (size_t j = i; j <dim [0]; j ++) { dot_prod + = S (j, k) * house_vec [j]; } para (size_t j = i; j <dim [0]; j ++) { S (j, k) - = dot_prod * house_vec [j]; } } #pragma omp paralelo para para (size_t k = 0; k <dim [0]; k ++) { T dot_prod = 0; para (size_t j = i; j <dim [0]; j ++) { dot_prod + = U (k, j) * house_vec [j]; } para (size_t j = i; j = n-1) continúa; { T x1 = S (i, i + 1); si (x1 <0) x1 = -x1; T x_inv_norm = 0; para (size_t j = i + 1; j 0) x_inv_norm = 1 / sqrt (x_inv_norm); T alfa = sqrt (1 + x1 * x_inv_norm); T beta = x_inv_norm / alpha; house_vec [i + 1] = - alfa; para (size_t j = i + 2; j <dim [1]; j ++) { house_vec [j] = - beta * S (i, j); } if (S (i, i + 1) <0) para (size_t j = i + 2; j <dim [1]; j ++) { house_vec [j] = - house_vec [j]; } } #pragma omp paralelo para para (size_t k = i; k <dim [0]; k ++) { T dot_prod = 0; para (size_t j = i + 1; j <dim [1]; j ++) { dot_prod + = S (k, j) * house_vec [j]; } para (size_t j = i + 1; j <dim [1]; j ++) { S (k, j) - = dot_prod * house_vec [j]; } } #pragma omp paralelo para para (size_t k = 0; k <dim [1]; k ++) { T dot_prod = 0; para (size_t j = i + 1; j <dim [1]; j ++) { dot_prod + = V (j, k) * house_vec [j]; } para (size_t j = i + 1; j <dim [1]; j ++) { V (j, k) - = dot_prod * house_vec [j]; } } } } size_t k0 = 0; si (eps 1.0) eps * = 0.5; eps * = 64.0; } while (k0 <dim [1] -1) {// Diagonalización T S_max = 0.0; para (size_t i = 0; i S (i, i)? S_max: S (i, i)); while (k0 <dim [1] -1 && fabs (S (k0, k0 + 1)) <= eps * S_max) k0 ++; if (k0 == dim [1] -1) continuar; size_t n = k0 + 2; while (n eps * S_max) n ++; T alfa = 0; T beta = 0; {// Calcular mu TC [2] [2]; C [0] [0] = S (n-2, n-2) * S (n-2, n-2); si (n-k0> 2) C [0] [0] + = S (n-3, n-2) * S (n-3, n-2); C [0] [1] = S (n-2, n-2) * S (n-2, n-1); C [1] [0] = S (n-2, n-2) * S (n-2, n-1); C [1] [1] = S (n-1, n-1) * S (n-1, n-1) + S (n-2, n-1) * S (n-2, n-1 ); T b = - (C [0] [0] + C [1] [1]) / 2; T c = C [0] [0] * C [1] [1] - C [0] [1] * C [1] [0]; T d = 0; if (b * bc> 0) d = sqrt (b * bc); más{ T b = (C [0] [0] -C [1] [1]) / 2; T c = -C [0] [1] * C [1] [0]; if (b * bc> 0) d = sqrt (b * bc); } T lambda1 = -b + d; T lambda2 = -bd; T d1 = lambda1-C [1] [1]; d1 = (d1 <0? -d1: d1); T d2 = lambda2-C [1] [1]; d2 = (d2 <0? -d2: d2); T mu = (d1 <d2 \ lambda lambda1: lambda2); alfa = S (k0, k0) * S (k0, k0) -mu; beta = S (k0, k0) * S (k0, k0 + 1); } para (size_t k = k0; k <n-1; k ++) { size_t dimU [2] = {dim [0], dim [0]}; size_t dimV [2] = {dim [1], dim [1]}; GivensR (S_, dim, k, alfa, beta); GivensL (V_, dimV, k, alfa, beta); alfa = S (k, k); beta = S (k + 1, k); GivensL (S_, dim, k, alfa, beta); GivensR (U_, dimU, k, alfa, beta); alfa = S (k, k + 1); beta = S (k, k + 2); } {// Haz S bi-diagonal nuevamente para (size_t i0 = k0; i0 <n-1; i0 ++) { para (size_t i1 = 0; i1 i1 || i0 + 1 <i1) S (i0, i1) = 0; } } para (size_t i0 = 0; i0 <dim [0]; i0 ++) { para (size_t i1 = k0; i1 i1 || i0 + 1 <i1) S (i0, i1) = 0; } } para (size_t i = 0; i <dim [1] -1; i ++) { if (fabs (S (i, i + 1)) <= eps * S_max) { S (i, i + 1) = 0; } } } } } #undef U #undef S #undef V plantilla svd vacío en línea (char * JOBU, char * JOBVT, int * M, int * N, T * A, int * LDA, T * S, T * U, int * LDU, T * VT, int * LDVT, T * WORK, int * LWORK, int * INFO) { afirmar (* JOBU == 'S'); afirmar (* JOBVT == 'S'); const size_t dim [2] = {std :: max (* N, * M), std :: min (* N, * M)}; T * U_ = nueva T [dim [0] * dim [0]]; memset (U_, 0, dim [0] * dim [0] * sizeof (T)); T * V_ = nueva T [dim [1] * dim [1]]; memset (V_, 0, dim [1] * dim [1] * sizeof (T)); T * S_ = nueva T [dim [0] * dim [1]]; const size_t lda = * LDA; const size_t ldu = * LDU; const size_t ldv = * LDVT; if (dim [1] == * M) { para (size_t i = 0; i <dim [0]; i ++) for (size_t j = 0; j <dim [1]; j ++) { S_ [i * dim [1] + j] = A [i * lda + j]; } }más{ para (size_t i = 0; i <dim [0]; i ++) for (size_t j = 0; j <dim [1]; j ++) { S_ [i * dim [1] + j] = A [j * lda + i]; } } for (size_t i = 0; i <dim [0]; i ++) { U_ [i * dim [0] + i] = 1; } for (size_t i = 0; i <dim [1]; i ++) { V_ [i * dim [1] + i] = 1; } SVD (dim, U_, S_, V_, (T) -1); for (size_t i = 0; i <dim [1]; i ++) {// Set S S [i] = S_ [i * dim [1] + i]; } if (dim [1] == * M) {// Establecer U para (size_t i = 0; i <dim [1]; i ++) para (size_t j = 0; j <* M; j ++) { U [j + ldu * i] = V_ [j + i * dim [1]] * (S [i] <0.0? -1.0: 1.0); } }más{ para (size_t i = 0; i <dim [1]; i ++) para (size_t j = 0; j <* M; j ++) { U [j + ldu * i] = U_ [i + j * dim [0]] * (S [i] <0.0? -1.0: 1.0); } } if (dim [0] == * N) {// Establecer V para (size_t i = 0; i <* N; i ++) for (size_t j = 0; j <dim [1]; j ++) { VT [j + ldv * i] = U_ [j + i * dim [0]]; } }más{ para (size_t i = 0; i <* N; i ++) for (size_t j = 0; j <dim [1]; j ++) { VT [j + ldv * i] = V_ [i + j * dim [1]]; } } for (size_t i = 0; i <dim [1]; i ++) { S [i] = S [i] * (S [i] <0.0? -1.0: 1.0); } eliminar [] U_; eliminar [] S_; eliminar [] V_; * INFORMACIÓN = 0; } int main () { typedef double Real_t; int n1 = 45, n2 = 27; // Crear matriz Real_t * M = nuevo Real_t [n1 * n2]; para (size_t i = 0; i <n1 * n2; i ++) M [i] = drand48 (); int m = n2; int n = n1; int k = (m <n? m: n); Real_t * tU = nuevo Real_t [m * k]; Real_t * tS = nuevo Real_t [k]; Real_t * tVT = nuevo Real_t [k * n]; {// Calcular SVD int INFO = 0; char JOBU = 'S'; char JOBVT = 'S'; int wssize = 3 * (m n? m: n); int wssize1 = 5 * (m wssize1? wssize: wssize1); Real_t * wsbuf = nuevo Real_t [wssize]; svd (& JOBU, & JOBVT, & m, & n, & M [0], & m, & tS [0], & tU [0], & m, & tVT [0], & k, wsbuf, & wssize, & INFO); eliminar [] wsbuf; } {// Error de verificación Real_t max_err = 0; para (size_t i0 = 0; i0 <m; i0 ++) para (size_t i1 = 0; i1 <n; i1 ++) { Real_t E = M [i1 * m + i0]; para (size_t i2 = 0; i2 <k; i2 ++) E- = tU [i2 * m + i0] * tS [i2] * tVT [i1 * k + i2]; if (max_err <fabs (E)) max_err = fabs (E); } std :: cout << max_err << '\ n'; } eliminar [] tU; eliminar [] tS; eliminar [] tVT; eliminar [] M; devuelve 0; }