¿Dónde puedo descargar el código de tiempo SVD ++?

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)

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

Puede encontrar el código SVD ++ en el siguiente proyecto de código abierto.

zenogantner / MyMediaLite c #

NicolasHug / Sorpresa pitón

guoguibing / librec java

Intente utilizar LibRec (una biblioteca de Java para sistemas de recomendación)