svdutil.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <stdarg.h>
00004 #include <string.h>
00005 #include <errno.h>
00006 #include <math.h>
00007 #include <sys/types.h>
00008 #include <sys/stat.h>
00009 
00010 
00011 #if defined(_WIN32)
00012    #include <Winsock2.h>
00013    #define popen(X,Y) _popen(X,Y)
00014    #define pclose(X) _pclose(X)
00015 #elif defined(linux) || defined(__linux) || defined(__CYGWIN__) || defined(__APPLE__)
00016    #include <netinet/in.h>
00017 #else
00018    #error "Unsupported OS\n"
00019 #endif
00020 
00021 
00022 #include "svdlib.h"
00023 #include "svdutil.h"
00024 
00025 #define BUNZIP2  "bzip2 -d"
00026 #define BZIP2    "bzip2 -1"
00027 #define UNZIP    "gzip -d"
00028 #define ZIP      "gzip -1"
00029 #define COMPRESS "compress"
00030 
00031 #define MAX_FILENAME 512
00032 #define MAX_PIPES    64
00033 static FILE *Pipe[MAX_PIPES];
00034 static int numPipes = 0;
00035 
00036 long *svd_longArray(long size, char empty, char *name) {
00037   long *a;
00038   if (empty) a = (long *) calloc(size, sizeof(long));
00039   else a = (long *) malloc(size * sizeof(long));
00040   if (!a) {
00041     perror(name);
00042     /* exit(errno); */
00043   }
00044   return a;
00045 }
00046 
00047 double *svd_doubleArray(long size, char empty, char *name) {
00048   double *a;
00049   if (empty) a = (double *) calloc(size, sizeof(double));
00050   else a = (double *) malloc(size * sizeof(double));
00051   if (!a) {
00052     perror(name);
00053     /* exit(errno); */
00054   }
00055   return a;
00056 }
00057 
00058 void svd_beep(void) {
00059   fputc('\a', stderr);
00060   fflush(stderr);
00061 }
00062 
00063 void svd_debug(char *fmt, ...) {
00064   va_list args;
00065   va_start(args, fmt);
00066   vfprintf(stderr, fmt, args);
00067   va_end(args);
00068 }
00069 
00070 void svd_error(char *fmt, ...) {
00071   va_list args;
00072   va_start(args, fmt);
00073   svd_beep();
00074   fprintf(stderr, "ERROR: ");
00075   vfprintf(stderr, fmt, args);
00076   fprintf(stderr, "\n");
00077   va_end(args);
00078 }
00079 
00080 void svd_fatalError(char *fmt, ...) {
00081   va_list args;
00082   va_start(args, fmt);
00083   svd_beep();
00084   fprintf(stderr, "ERROR: ");
00085   vfprintf(stderr, fmt, args);
00086   fprintf(stderr, "\a\n");
00087   va_end(args);
00088   exit(1);
00089 }
00090 
00091 static void registerPipe(FILE *p) {
00092   if (numPipes >= MAX_PIPES) svd_error("Too many pipes open");
00093   Pipe[numPipes++] = p;
00094 }
00095 
00096 static char isPipe(FILE *p) {
00097   int i;
00098   for (i = 0; i < numPipes && Pipe[i] != p; i++);
00099   if (i == numPipes) return FALSE;
00100   Pipe[i] = Pipe[--numPipes];
00101   return TRUE;
00102 }
00103 
00104 static FILE *openPipe(char *pipeName, char *mode) {
00105   FILE *pipe;
00106   fflush(stdout);
00107   if ((pipe = popen(pipeName, mode))) registerPipe(pipe);
00108   return pipe;
00109 }
00110 
00111 static FILE *readZippedFile(char *command, char *fileName) {
00112   char buf[MAX_FILENAME];
00113   sprintf(buf, "%s < %s 2>/dev/null", command, fileName);
00114   return openPipe(buf, "r");
00115 }
00116 
00117 FILE *svd_fatalReadFile(char *filename) {
00118   FILE *file;
00119   if (!(file = svd_readFile(filename)))
00120     svd_fatalError("couldn't read the file %s", filename);
00121   return file;
00122 }
00123 
00124 static int stringEndsIn(char *s, char *t) {
00125   int ls = strlen(s);
00126   int lt = strlen(t);
00127   if (ls < lt) return FALSE;
00128   return (strcmp(s + ls - lt, t)) ? FALSE : TRUE;
00129 }
00130 
00131 /* Will silently return NULL if file couldn't be opened */
00132 FILE *svd_readFile(char *fileName) {
00133   char fileBuf[MAX_FILENAME];
00134   struct stat statbuf;
00135 
00136   /* Special file name */
00137   if (!strcmp(fileName, "-"))
00138     return stdin;
00139   
00140   /* If it is a pipe */
00141   if (fileName[0] == '|')
00142     return openPipe(fileName + 1, "r");
00143 
00144   /* Check if already ends in .gz or .Z and assume compressed */
00145   if (stringEndsIn(fileName, ".gz") || stringEndsIn(fileName, ".Z")) {
00146     if (!stat(fileName, &statbuf))
00147       return readZippedFile(UNZIP, fileName);
00148     return NULL;
00149   }
00150   /* Check if already ends in .bz or .bz2 and assume compressed */
00151   if (stringEndsIn(fileName, ".bz") || stringEndsIn(fileName, ".bz2")) {
00152     if (!stat(fileName, &statbuf))
00153       return readZippedFile(BUNZIP2, fileName);
00154     return NULL;
00155   }
00156   /* Try just opening normally */
00157   if (!stat(fileName, &statbuf))
00158     return fopen(fileName, "r");
00159   /* Try adding .gz */
00160   sprintf(fileBuf, "%s.gz", fileName);
00161   if (!stat(fileBuf, &statbuf))
00162     return readZippedFile(UNZIP, fileBuf);
00163   /* Try adding .Z */
00164   sprintf(fileBuf, "%s.Z", fileName);
00165   if (!stat(fileBuf, &statbuf))
00166     return readZippedFile(UNZIP, fileBuf);
00167   /* Try adding .bz2 */
00168   sprintf(fileBuf, "%s.bz2", fileName);
00169   if (!stat(fileBuf, &statbuf))
00170     return readZippedFile(BUNZIP2, fileBuf);
00171   /* Try adding .bz */
00172   sprintf(fileBuf, "%s.bz", fileName);
00173   if (!stat(fileBuf, &statbuf))
00174     return readZippedFile(BUNZIP2, fileBuf);
00175 
00176   return NULL;
00177 }
00178 
00179 static FILE *writeZippedFile(char *fileName, char append) {
00180   char buf[MAX_FILENAME];
00181   const char *op = (append) ? ">>" : ">";
00182   if (stringEndsIn(fileName, ".bz2") || stringEndsIn(fileName, ".bz"))
00183     sprintf(buf, "%s %s \"%s\"", BZIP2, op, fileName);
00184   else if (stringEndsIn(fileName, ".Z"))
00185     sprintf(buf, "%s %s \"%s\"", COMPRESS, op, fileName);
00186   else
00187     sprintf(buf, "%s %s \"%s\"", ZIP, op, fileName);
00188   return openPipe(buf, "w");
00189 }
00190 
00191 FILE *svd_writeFile(char *fileName, char append) {
00192   /* Special file name */
00193   if (!strcmp(fileName, "-"))
00194     return stdout;
00195   
00196   /* If it is a pipe */
00197   if (fileName[0] == '|')
00198     return openPipe(fileName + 1, "w");
00199 
00200   /* Check if ends in .gz, .Z, .bz, .bz2 */
00201   if (stringEndsIn(fileName, ".gz") || stringEndsIn(fileName, ".Z") ||
00202       stringEndsIn(fileName, ".bz") || stringEndsIn(fileName, ".bz2"))
00203     return writeZippedFile(fileName, append);
00204   return (append) ? fopen(fileName, "a") : fopen(fileName, "w");
00205 }
00206 
00207 /* Could be a file or a stream. */
00208 void svd_closeFile(FILE *file) {
00209   if (file == stdin || file == stdout) return;
00210   if (isPipe(file)) pclose(file);
00211   else fclose(file);
00212 }
00213 
00214 
00215 char svd_readBinInt(FILE *file, int *val) {
00216   int x;
00217   if (fread(&x, sizeof(int), 1, file) == 1) {
00218     *val = ntohl(x);
00219     return FALSE;
00220   }
00221   return TRUE;
00222 }
00223 
00224 /* This reads a float in network order and converts to a real in host order. */
00225 char svd_readBinFloat(FILE *file, float *val) {
00226   int x;
00227   float y;
00228   if (fread(&x, sizeof(int), 1, file) == 1) {
00229     x = ntohl(x);
00230     y = *((float *) &x);
00231     *val = y;
00232     return FALSE;
00233   }
00234   return TRUE;
00235 }
00236 
00237 char svd_writeBinInt(FILE *file, int x) {
00238   int y = htonl(x);
00239   if (fwrite(&y, sizeof(int), 1, file) != 1) return TRUE;
00240   return FALSE;
00241 }
00242 
00243 /* This takes a real in host order and writes a float in network order. */
00244 char svd_writeBinFloat(FILE *file, float r) {
00245   int y = htonl(*((int *) &r));
00246   if (fwrite(&y, sizeof(int), 1, file) != 1) return TRUE;
00247   return FALSE;
00248 }
00249 
00250 
00251 /************************************************************** 
00252  * returns |a| if b is positive; else fsign returns -|a|      *
00253  **************************************************************/ 
00254 double svd_fsign(double a, double b) {
00255   if ((a>=0.0 && b>=0.0) || (a<0.0 && b<0.0))return(a);
00256   else return -a;
00257 }
00258 
00259 /************************************************************** 
00260  * returns the larger of two double precision numbers         *
00261  **************************************************************/ 
00262 double svd_dmax(double a, double b) {
00263    return (a > b) ? a : b;
00264 }
00265 
00266 /************************************************************** 
00267  * returns the smaller of two double precision numbers        *
00268  **************************************************************/ 
00269 double svd_dmin(double a, double b) {
00270   return (a < b) ? a : b;
00271 }
00272 
00273 /************************************************************** 
00274  * returns the larger of two integers                         *
00275  **************************************************************/ 
00276 long svd_imax(long a, long b) {
00277   return (a > b) ? a : b;
00278 }
00279 
00280 /************************************************************** 
00281  * returns the smaller of two integers                        *
00282  **************************************************************/ 
00283 long svd_imin(long a, long b) {
00284   return (a < b) ? a : b;
00285 }
00286 
00287 /************************************************************** 
00288  * Function scales a vector by a constant.                    *
00289  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00290  **************************************************************/ 
00291 void svd_dscal(long n, double da, double *dx, long incx) {
00292   long i;
00293   
00294   if (n <= 0 || incx == 0) return;
00295   if (incx < 0) dx += (-n+1) * incx;
00296   for (i=0; i < n; i++) {
00297     *dx *= da;
00298     dx += incx;
00299   }
00300   return;
00301 }
00302 
00303 /************************************************************** 
00304  * function scales a vector by a constant.                    *
00305  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00306  **************************************************************/ 
00307 void svd_datx(long n, double da, double *dx, long incx, double *dy, long incy) {
00308   long i;
00309   
00310   if (n <= 0 || incx == 0 || incy == 0 || da == 0.0) return;
00311   if (incx == 1 && incy == 1) 
00312     for (i=0; i < n; i++) *dy++ = da * (*dx++);
00313   
00314   else {
00315     if (incx < 0) dx += (-n+1) * incx;
00316     if (incy < 0) dy += (-n+1) * incy;
00317     for (i=0; i < n; i++) {
00318       *dy = da * (*dx);
00319       dx += incx;
00320       dy += incy;
00321     }
00322   }
00323   return;
00324 }
00325 
00326 /************************************************************** 
00327  * Function copies a vector x to a vector y                   *
00328  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00329  **************************************************************/ 
00330 void svd_dcopy(long n, double *dx, long incx, double *dy, long incy) {
00331   long i;
00332   
00333   if (n <= 0 || incx == 0 || incy == 0) return;
00334   if (incx == 1 && incy == 1) 
00335     for (i=0; i < n; i++) *dy++ = *dx++;
00336   
00337   else {
00338     if (incx < 0) dx += (-n+1) * incx;
00339     if (incy < 0) dy += (-n+1) * incy;
00340     for (i=0; i < n; i++) {
00341       *dy = *dx;
00342       dx += incx;
00343       dy += incy;
00344     }
00345   }
00346   return;
00347 }
00348 
00349 /************************************************************** 
00350  * Function forms the dot product of two vectors.             *
00351  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00352  **************************************************************/ 
00353 double svd_ddot(long n, double *dx, long incx, double *dy, long incy) {
00354   long i;
00355   double dot_product;
00356   
00357   if (n <= 0 || incx == 0 || incy == 0) return(0.0);
00358   dot_product = 0.0;
00359   if (incx == 1 && incy == 1) 
00360     for (i=0; i < n; i++) dot_product += (*dx++) * (*dy++);
00361   else {
00362     if (incx < 0) dx += (-n+1) * incx;
00363     if (incy < 0) dy += (-n+1) * incy;
00364     for (i=0; i < n; i++) {
00365       dot_product += (*dx) * (*dy);
00366       dx += incx;
00367       dy += incy;
00368       }
00369   }
00370   return(dot_product);
00371 }
00372 
00373 /************************************************************** 
00374  * Constant times a vector plus a vector                      *
00375  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00376  **************************************************************/ 
00377 void svd_daxpy (long n, double da, double *dx, long incx, double *dy, long incy) {
00378   long i;
00379   
00380   if (n <= 0 || incx == 0 || incy == 0 || da == 0.0) return;
00381   if (incx == 1 && incy == 1) 
00382     for (i=0; i < n; i++) {
00383       *dy += da * (*dx++);
00384       dy++;
00385     }
00386   else {
00387     if (incx < 0) dx += (-n+1) * incx;
00388     if (incy < 0) dy += (-n+1) * incy;
00389     for (i=0; i < n; i++) {
00390       *dy += da * (*dx);
00391       dx += incx;
00392       dy += incy;
00393     }
00394   }
00395   return;
00396 }
00397 
00398 /********************************************************************* 
00399  * Function sorts array1 and array2 into increasing order for array1 *
00400  *********************************************************************/
00401 void svd_dsort2(long igap, long n, double *array1, double *array2) {
00402   double temp;
00403   long i, j, index;
00404   
00405   if (!igap) return;
00406   else {
00407     for (i = igap; i < n; i++) {
00408       j = i - igap;
00409       index = i;
00410       while (j >= 0 && array1[j] > array1[index]) {
00411         temp = array1[j];
00412         array1[j] = array1[index];
00413         array1[index] = temp;
00414         temp = array2[j];
00415         array2[j] = array2[index];
00416         array2[index] = temp;
00417         j -= igap;
00418         index = j + igap;
00419       }
00420     } 
00421   }
00422   svd_dsort2(igap/2,n,array1,array2);
00423 }
00424 
00425 /************************************************************** 
00426  * Function interchanges two vectors                          *
00427  * Based on Fortran-77 routine from Linpack by J. Dongarra    *
00428  **************************************************************/ 
00429 void svd_dswap(long n, double *dx, long incx, double *dy, long incy) {
00430   long i;
00431   double dtemp;
00432   
00433   if (n <= 0 || incx == 0 || incy == 0) return;
00434   if (incx == 1 && incy == 1) {
00435     for (i=0; i < n; i++) {
00436       dtemp = *dy;
00437       *dy++ = *dx;
00438       *dx++ = dtemp;
00439     }   
00440   }
00441   else {
00442     if (incx < 0) dx += (-n+1) * incx;
00443     if (incy < 0) dy += (-n+1) * incy;
00444     for (i=0; i < n; i++) {
00445       dtemp = *dy;
00446       *dy = *dx;
00447       *dx = dtemp;
00448       dx += incx;
00449       dy += incy;
00450     }
00451   }
00452 }
00453 
00454 /***************************************************************** 
00455  * Function finds the index of element having max. absolute value*
00456  * based on FORTRAN 77 routine from Linpack by J. Dongarra       *
00457  *****************************************************************/ 
00458 long svd_idamax(long n, double *dx, long incx) {
00459   long ix,i,imax;
00460   double dtemp, dmax;
00461   
00462   if (n < 1) return(-1);
00463   if (n == 1) return(0);
00464   if (incx == 0) return(-1);
00465   
00466   if (incx < 0) ix = (-n+1) * incx;
00467   else ix = 0;
00468   imax = ix;
00469   dx += ix;
00470   dmax = fabs(*dx);
00471   for (i=1; i < n; i++) {
00472     ix += incx;
00473     dx += incx;
00474     dtemp = fabs(*dx);
00475     if (dtemp > dmax) {
00476       dmax = dtemp;
00477       imax = ix;
00478     }
00479   }
00480   return(imax);
00481 }
00482 
00483 /**************************************************************
00484  * multiplication of matrix B by vector x, where B = A'A,     *
00485  * and A is nrow by ncol (nrow >> ncol). Hence, B is of order *
00486  * n = ncol (y stores product vector).                        *
00487  **************************************************************/
00488 void svd_opb(SMat A, double *x, double *y, double *temp) {
00489   long i, j, end;
00490   long *pointr = A->pointr, *rowind = A->rowind;
00491   double *value = A->value;
00492   long n = A->cols;
00493 
00494   SVDCount[SVD_MXV] += 2;
00495   memset(y, 0, n * sizeof(double));
00496   for (i = 0; i < A->rows; i++) temp[i] = 0.0;
00497   
00498   for (i = 0; i < A->cols; i++) {
00499     end = pointr[i+1];
00500     for (j = pointr[i]; j < end; j++) 
00501       temp[rowind[j]] += value[j] * (*x); 
00502     x++;
00503   }
00504   for (i = 0; i < A->cols; i++) {
00505     end = pointr[i+1];
00506     for (j = pointr[i]; j < end; j++) 
00507       *y += value[j] * temp[rowind[j]];
00508     y++;
00509   }
00510   return;
00511 }
00512 
00513 /***********************************************************
00514  * multiplication of matrix A by vector x, where A is      *
00515  * nrow by ncol (nrow >> ncol).  y stores product vector.  *
00516  ***********************************************************/
00517 void svd_opa(SMat A, double *x, double *y) {
00518   long end, i, j;
00519   long *pointr = A->pointr, *rowind = A->rowind;
00520   double *value = A->value;
00521    
00522   SVDCount[SVD_MXV]++;
00523   memset(y, 0, A->rows * sizeof(double));
00524   
00525   for (i = 0; i < A->cols; i++) {
00526     end = pointr[i+1];
00527     for (j = pointr[i]; j < end; j++)
00528       y[rowind[j]] += value[j] * x[i]; 
00529   }
00530   return;
00531 }
00532 
00533 
00534 /***********************************************************************
00535  *                                                                     *
00536  *                              random()                               *
00537  *                        (double precision)                           *
00538  ***********************************************************************/
00539 /***********************************************************************
00540 
00541    Description
00542    -----------
00543 
00544    This is a translation of a Fortran-77 uniform random number
00545    generator.  The code is based  on  theory and suggestions  given in
00546    D. E. Knuth (1969),  vol  2.  The argument to the function should 
00547    be initialized to an arbitrary integer prior to the first call to 
00548    random.  The calling program should  not  alter  the value of the
00549    argument between subsequent calls to random.  Random returns values
00550    within the interval (0,1).
00551 
00552 
00553    Arguments 
00554    ---------
00555 
00556    (input)
00557    iy      an integer seed whose value must not be altered by the caller
00558            between subsequent calls
00559 
00560    (output)
00561    random  a double precision random number between (0,1)
00562 
00563  ***********************************************************************/
00564 double svd_random2(long *iy) {
00565    static long m2 = 0;
00566    static long ia, ic, mic;
00567    static double halfm, s;
00568 
00569    /* If first entry, compute (max int) / 2 */
00570    if (!m2) {
00571       m2 = 1 << (8 * (int)sizeof(int) - 2); 
00572       halfm = m2;
00573 
00574       /* compute multiplier and increment for linear congruential 
00575        * method */
00576       ia = 8 * (long)(halfm * atan(1.0) / 8.0) + 5;
00577       ic = 2 * (long)(halfm * (0.5 - sqrt(3.0)/6.0)) + 1;
00578       mic = (m2-ic) + m2;
00579 
00580       /* s is the scale factor for converting to floating point */
00581       s = 0.5 / halfm;
00582    }
00583 
00584    /* compute next random number */
00585    *iy = *iy * ia;
00586 
00587    /* for computers which do not allow integer overflow on addition */
00588    if (*iy > mic) *iy = (*iy - m2) - m2;
00589 
00590    *iy = *iy + ic;
00591 
00592    /* for computers whose word length for addition is greater than
00593     * for multiplication */
00594    if (*iy / 2 > m2) *iy = (*iy - m2) - m2;
00595   
00596    /* for computers whose integer overflow affects the sign bit */
00597    if (*iy < 0) *iy = (*iy + m2) + m2;
00598 
00599    return((double)(*iy) * s);
00600 }
00601 
00602 /************************************************************** 
00603  *                                                            *
00604  * Function finds sqrt(a^2 + b^2) without overflow or         *
00605  * destructive underflow.                                     *
00606  *                                                            *
00607  **************************************************************/ 
00608 /************************************************************** 
00609 
00610    Funtions used
00611    -------------
00612 
00613    UTILITY      dmax, dmin
00614 
00615  **************************************************************/ 
00616 double svd_pythag(double a, double b) {
00617    double p, r, s, t, u, temp;
00618 
00619    p = svd_dmax(fabs(a), fabs(b));
00620    if (p != 0.0) {
00621       temp = svd_dmin(fabs(a), fabs(b)) / p;
00622       r = temp * temp; 
00623       t = 4.0 + r;
00624       while (t != 4.0) {
00625          s = r / t;
00626          u = 1.0 + 2.0 * s;
00627          p *= u;
00628          temp = s / u;
00629          r *= temp * temp;
00630          t = 4.0 + r;
00631       }
00632    }
00633    return(p);
00634 }
00635