00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include "svdlib.h"
00004 #include "svdutil.h"
00005
00006 char *SVDVersion = "1.34";
00007 long SVDVerbosity = 1;
00008 long SVDCount[SVD_COUNTERS];
00009
00010 void svdResetCounters(void) {
00011 int i;
00012 for (i = 0; i < SVD_COUNTERS; i++)
00013 SVDCount[i] = 0;
00014 }
00015
00016
00017
00018
00019
00020 DMat svdNewDMat(int rows, int cols) {
00021 int i;
00022 DMat D = (DMat) malloc(sizeof(struct dmat));
00023 if (!D) {perror("svdNewDMat"); return NULL;}
00024 D->rows = rows;
00025 D->cols = cols;
00026
00027 D->value = (double **) malloc(rows * sizeof(double *));
00028 if (!D->value) {SAFE_FREE(D); return NULL;}
00029
00030 D->value[0] = (double *) calloc(rows * cols, sizeof(double));
00031 if (!D->value[0]) {SAFE_FREE(D->value); SAFE_FREE(D); return NULL;}
00032
00033 for (i = 1; i < rows; i++) D->value[i] = D->value[i-1] + cols;
00034 return D;
00035 }
00036
00037 void svdFreeDMat(DMat D) {
00038 if (!D) return;
00039 SAFE_FREE(D->value[0]);
00040 SAFE_FREE(D->value);
00041 free(D);
00042 }
00043
00044
00045 SMat svdNewSMat(int rows, int cols, int vals) {
00046 SMat S = (SMat) calloc(1, sizeof(struct smat));
00047 if (!S) {perror("svdNewSMat"); return NULL;}
00048 S->rows = rows;
00049 S->cols = cols;
00050 S->vals = vals;
00051 S->pointr = svd_longArray(cols + 1, TRUE, "svdNewSMat: pointr");
00052 if (!S->pointr) {svdFreeSMat(S); return NULL;}
00053 S->rowind = svd_longArray(vals, FALSE, "svdNewSMat: rowind");
00054 if (!S->rowind) {svdFreeSMat(S); return NULL;}
00055 S->value = svd_doubleArray(vals, FALSE, "svdNewSMat: value");
00056 if (!S->value) {svdFreeSMat(S); return NULL;}
00057 return S;
00058 }
00059
00060 void svdFreeSMat(SMat S) {
00061 if (!S) return;
00062 SAFE_FREE(S->pointr);
00063 SAFE_FREE(S->rowind);
00064 SAFE_FREE(S->value);
00065 free(S);
00066 }
00067
00068
00069
00070 SVDRec svdNewSVDRec(void) {
00071 SVDRec R = (SVDRec) calloc(1, sizeof(struct svdrec));
00072 if (!R) {perror("svdNewSVDRec"); return NULL;}
00073 return R;
00074 }
00075
00076
00077 void svdFreeSVDRec(SVDRec R) {
00078 if (!R) return;
00079 if (R->Ut) svdFreeDMat(R->Ut);
00080 if (R->S) SAFE_FREE(R->S);
00081 if (R->Vt) svdFreeDMat(R->Vt);
00082 free(R);
00083 }
00084
00085
00086
00087
00088
00089 DMat svdConvertStoD(SMat S) {
00090 int i, c;
00091 DMat D = svdNewDMat(S->rows, S->cols);
00092 if (!D) {
00093 svd_error("svdConvertStoD: failed to allocate D");
00094 return NULL;
00095 }
00096 for (i = 0, c = 0; i < S->vals; i++) {
00097 while (S->pointr[c + 1] <= i) c++;
00098 D->value[S->rowind[i]][c] = S->value[i];
00099 }
00100 return D;
00101 }
00102
00103
00104 SMat svdConvertDtoS(DMat D) {
00105 SMat S;
00106 int i, j, n;
00107 for (i = 0, n = 0; i < D->rows; i++)
00108 for (j = 0; j < D->cols; j++)
00109 if (D->value[i][j] != 0) n++;
00110
00111 S = svdNewSMat(D->rows, D->cols, n);
00112 if (!S) {
00113 svd_error("svdConvertDtoS: failed to allocate S");
00114 return NULL;
00115 }
00116 for (j = 0, n = 0; j < D->cols; j++) {
00117 S->pointr[j] = n;
00118 for (i = 0; i < D->rows; i++)
00119 if (D->value[i][j] != 0) {
00120 S->rowind[n] = i;
00121 S->value[n] = D->value[i][j];
00122 n++;
00123 }
00124 }
00125 S->pointr[S->cols] = S->vals;
00126 return S;
00127 }
00128
00129
00130 DMat svdTransposeD(DMat D) {
00131 int r, c;
00132 DMat N = svdNewDMat(D->cols, D->rows);
00133 for (r = 0; r < D->rows; r++)
00134 for (c = 0; c < D->cols; c++)
00135 N->value[c][r] = D->value[r][c];
00136 return N;
00137 }
00138
00139
00140 SMat svdTransposeS(SMat S) {
00141 int r, c, i, j;
00142 SMat N = svdNewSMat(S->cols, S->rows, S->vals);
00143
00144 for (i = 0; i < S->vals; i++)
00145 N->pointr[S->rowind[i]]++;
00146
00147 N->pointr[S->rows] = S->vals - N->pointr[S->rows - 1];
00148 for (r = S->rows - 1; r > 0; r--)
00149 N->pointr[r] = N->pointr[r+1] - N->pointr[r-1];
00150 N->pointr[0] = 0;
00151
00152 for (c = 0, i = 0; c < S->cols; c++) {
00153 for (; i < S->pointr[c+1]; i++) {
00154 r = S->rowind[i];
00155 j = N->pointr[r+1]++;
00156 N->rowind[j] = c;
00157 N->value[j] = S->value[i];
00158 }
00159 }
00160 return N;
00161 }
00162
00163
00164
00165
00166 void svdWriteDenseArray(double *a, int n, char *filename, char binary) {
00167 int i;
00168 FILE *file = svd_writeFile(filename, FALSE);
00169 if (!file)
00170 return svd_error("svdWriteDenseArray: failed to write %s", filename);
00171 if (binary) {
00172 svd_writeBinInt(file, n);
00173 for (i = 0; i < n; i++)
00174 svd_writeBinFloat(file, (float) a[i]);
00175 } else {
00176 fprintf(file, "%d\n", n);
00177 for (i = 0; i < n; i++)
00178 fprintf(file, "%g\n", a[i]);
00179 }
00180 svd_closeFile(file);
00181 }
00182
00183 double *svdLoadDenseArray(char *filename, int *np, char binary) {
00184 int i, n;
00185 double *a;
00186
00187 FILE *file = svd_readFile(filename);
00188 if (!file) {
00189 svd_error("svdLoadDenseArray: failed to read %s", filename);
00190 return NULL;
00191 }
00192 if (binary) svd_readBinInt(file, np);
00193 else fscanf(file, " %d", np);
00194 n = *np;
00195 a = svd_doubleArray(n, FALSE, "svdLoadDenseArray: a");
00196 if (!a) return NULL;
00197 if (binary) {
00198 float f;
00199 for (i = 0; i < n; i++) {
00200 svd_readBinFloat(file, &f);
00201 a[i] = f;
00202 }
00203 } else {
00204 for (i = 0; i < n; i++)
00205 fscanf(file, " %lf\n", a + i);
00206 }
00207 svd_closeFile(file);
00208 return a;
00209 }
00210
00211
00212
00213
00214
00215 static SMat svdLoadSparseTextHBFile(FILE *file) {
00216 char line[128];
00217 long i, x, rows, cols, vals, num_mat;
00218 SMat S;
00219
00220 if (!fgets(line, 128, file));
00221
00222 if (!fgets(line, 128, file));
00223
00224 if (fscanf(file, "%*s%ld%ld%ld%ld\n",
00225 &rows, &cols, &vals, &num_mat) != 4) {
00226 svd_error("svdLoadSparseTextHBFile: bad file format on line 3");
00227 return NULL;
00228 }
00229 if (num_mat != 0) {
00230 svd_error("svdLoadSparseTextHBFile: I don't know how to handle a file "
00231 "with elemental matrices (last entry on header line 3)");
00232 return NULL;
00233 }
00234
00235 if (!fgets(line, 128, file));
00236
00237 S = svdNewSMat(rows, cols, vals);
00238 if (!S) return NULL;
00239
00240
00241 for (i = 0; i <= S->cols; i++) {
00242 if (fscanf(file, " %ld", &x) != 1) {
00243 svd_error("svdLoadSparseTextHBFile: error reading pointr %d", i);
00244 return NULL;
00245 }
00246 S->pointr[i] = x - 1;
00247 }
00248 S->pointr[S->cols] = S->vals;
00249
00250
00251 for (i = 0; i < S->vals; i++) {
00252 if (fscanf(file, " %ld", &x) != 1) {
00253 svd_error("svdLoadSparseTextHBFile: error reading rowind %d", i);
00254 return NULL;
00255 }
00256 S->rowind[i] = x - 1;
00257 }
00258 for (i = 0; i < S->vals; i++)
00259 if (fscanf(file, " %lf", S->value + i) != 1) {
00260 svd_error("svdLoadSparseTextHBFile: error reading value %d", i);
00261 return NULL;
00262 }
00263 return S;
00264 }
00265
00266 static void svdWriteSparseTextHBFile(SMat S, FILE *file) {
00267 int i;
00268 long col_lines = ((S->cols + 1) / 8) + (((S->cols + 1) % 8) ? 1 : 0);
00269 long row_lines = (S->vals / 8) + ((S->vals % 8) ? 1 : 0);
00270 long total_lines = col_lines + 2 * row_lines;
00271
00272 char title[32];
00273 sprintf(title, "SVDLIBC v. %s", SVDVersion);
00274 fprintf(file, "%-72s%-8s\n", title, "<key>");
00275 fprintf(file, "%14ld%14ld%14ld%14ld%14d\n", total_lines, col_lines,
00276 row_lines, row_lines, 0);
00277 fprintf(file, "%-14s%14ld%14ld%14ld%14d\n", "rra", S->rows, S->cols,
00278 S->vals, 0);
00279 fprintf(file, "%16s%16s%16s%16s\n", "(8i)", "(8i)", "(8e)", "(8e)");
00280
00281 for (i = 0; i <= S->cols; i++)
00282 fprintf(file, "%ld%s", S->pointr[i] + 1, (((i+1) % 8) == 0) ? "\n" : " ");
00283 fprintf(file, "\n");
00284 for (i = 0; i < S->vals; i++)
00285 fprintf(file, "%ld%s", S->rowind[i] + 1, (((i+1) % 8) == 0) ? "\n" : " ");
00286 fprintf(file, "\n");
00287 for (i = 0; i < S->vals; i++)
00288 fprintf(file, "%g%s", S->value[i], (((i+1) % 8) == 0) ? "\n" : " ");
00289 fprintf(file, "\n");
00290 }
00291
00292
00293 static SMat svdLoadSparseTextFile(FILE *file) {
00294 long c, i, n, v, rows, cols, vals;
00295 SMat S;
00296 if (fscanf(file, " %ld %ld %ld", &rows, &cols, &vals) != 3) {
00297 svd_error("svdLoadSparseTextFile: bad file format");
00298 return NULL;
00299 }
00300
00301 S = svdNewSMat(rows, cols, vals);
00302 if (!S) return NULL;
00303
00304 for (c = 0, v = 0; c < cols; c++) {
00305 if (fscanf(file, " %ld", &n) != 1) {
00306 svd_error("svdLoadSparseTextFile: bad file format");
00307 return NULL;
00308 }
00309 S->pointr[c] = v;
00310 for (i = 0; i < n; i++, v++) {
00311 if (fscanf(file, " %ld %lf", S->rowind + v, S->value + v) != 2) {
00312 svd_error("svdLoadSparseTextFile: bad file format");
00313 return NULL;
00314 }
00315 }
00316 }
00317 S->pointr[cols] = vals;
00318 return S;
00319 }
00320
00321 static void svdWriteSparseTextFile(SMat S, FILE *file) {
00322 int c, v;
00323 fprintf(file, "%ld %ld %ld\n", S->rows, S->cols, S->vals);
00324 for (c = 0, v = 0; c < S->cols; c++) {
00325 fprintf(file, "%ld\n", S->pointr[c + 1] - S->pointr[c]);
00326 for (; v < S->pointr[c+1]; v++)
00327 fprintf(file, "%ld %g\n", S->rowind[v], S->value[v]);
00328 }
00329 }
00330
00331
00332 static SMat svdLoadSparseBinaryFile(FILE *file) {
00333 int rows, cols, vals, n, c, i, v, r, e = 0;
00334 float f;
00335 SMat S;
00336 e += svd_readBinInt(file, &rows);
00337 e += svd_readBinInt(file, &cols);
00338 e += svd_readBinInt(file, &vals);
00339 if (e) {
00340 svd_error("svdLoadSparseBinaryFile: bad file format");
00341 return NULL;
00342 }
00343
00344 S = svdNewSMat(rows, cols, vals);
00345 if (!S) return NULL;
00346
00347 for (c = 0, v = 0; c < cols; c++) {
00348 if (svd_readBinInt(file, &n)) {
00349 svd_error("svdLoadSparseBinaryFile: bad file format");
00350 return NULL;
00351 }
00352 S->pointr[c] = v;
00353 for (i = 0; i < n; i++, v++) {
00354 e += svd_readBinInt(file, &r);
00355 e += svd_readBinFloat(file, &f);
00356 if (e) {
00357 svd_error("svdLoadSparseBinaryFile: bad file format");
00358 return NULL;
00359 }
00360 S->rowind[v] = r;
00361 S->value[v] = f;
00362 }
00363 }
00364 S->pointr[cols] = vals;
00365 return S;
00366 }
00367
00368 static void svdWriteSparseBinaryFile(SMat S, FILE *file) {
00369 int c, v;
00370 svd_writeBinInt(file, (int) S->rows);
00371 svd_writeBinInt(file, (int) S->cols);
00372 svd_writeBinInt(file, (int) S->vals);
00373 for (c = 0, v = 0; c < S->cols; c++) {
00374 svd_writeBinInt(file, (int) (S->pointr[c + 1] - S->pointr[c]));
00375 for (; v < S->pointr[c+1]; v++) {
00376 svd_writeBinInt(file, (int) S->rowind[v]);
00377 svd_writeBinFloat(file, (float) S->value[v]);
00378 }
00379 }
00380 }
00381
00382
00383 static DMat svdLoadDenseTextFile(FILE *file) {
00384 long rows, cols, i, j;
00385 DMat D;
00386 if (fscanf(file, " %ld %ld", &rows, &cols) != 2) {
00387 svd_error("svdLoadDenseTextFile: bad file format");
00388 return NULL;
00389 }
00390
00391 D = svdNewDMat(rows, cols);
00392 if (!D) return NULL;
00393
00394 for (i = 0; i < rows; i++)
00395 for (j = 0; j < cols; j++) {
00396 if (fscanf(file, " %lf", &(D->value[i][j])) != 1) {
00397 svd_error("svdLoadDenseTextFile: bad file format");
00398 return NULL;
00399 }
00400 }
00401 return D;
00402 }
00403
00404 static void svdWriteDenseTextFile(DMat D, FILE *file) {
00405 int i, j;
00406 fprintf(file, "%ld %ld\n", D->rows, D->cols);
00407 for (i = 0; i < D->rows; i++)
00408 for (j = 0; j < D->cols; j++)
00409 fprintf(file, "%g%c", D->value[i][j], (j == D->cols - 1) ? '\n' : ' ');
00410 }
00411
00412
00413 static DMat svdLoadDenseBinaryFile(FILE *file) {
00414 int rows, cols, i, j, e = 0;
00415 float f;
00416 DMat D;
00417 e += svd_readBinInt(file, &rows);
00418 e += svd_readBinInt(file, &cols);
00419 if (e) {
00420 svd_error("svdLoadDenseBinaryFile: bad file format");
00421 return NULL;
00422 }
00423
00424 D = svdNewDMat(rows, cols);
00425 if (!D) return NULL;
00426
00427 for (i = 0; i < rows; i++)
00428 for (j = 0; j < cols; j++) {
00429 if (svd_readBinFloat(file, &f)) {
00430 svd_error("svdLoadDenseBinaryFile: bad file format");
00431 return NULL;
00432 }
00433 D->value[i][j] = f;
00434 }
00435 return D;
00436 }
00437
00438 static void svdWriteDenseBinaryFile(DMat D, FILE *file) {
00439 int i, j;
00440 svd_writeBinInt(file, (int) D->rows);
00441 svd_writeBinInt(file, (int) D->cols);
00442 for (i = 0; i < D->rows; i++)
00443 for (j = 0; j < D->cols; j++)
00444 svd_writeBinFloat(file, (float) D->value[i][j]);
00445 }
00446
00447
00448 SMat svdLoadSparseMatrix(char *filename, int format) {
00449 SMat S = NULL;
00450 DMat D = NULL;
00451 FILE *file = svd_fatalReadFile(filename);
00452 switch (format) {
00453 case SVD_F_STH:
00454 S = svdLoadSparseTextHBFile(file);
00455 break;
00456 case SVD_F_ST:
00457 S = svdLoadSparseTextFile(file);
00458 break;
00459 case SVD_F_SB:
00460 S = svdLoadSparseBinaryFile(file);
00461 break;
00462 case SVD_F_DT:
00463 D = svdLoadDenseTextFile(file);
00464 break;
00465 case SVD_F_DB:
00466 D = svdLoadDenseBinaryFile(file);
00467 break;
00468 default: svd_error("svdLoadSparseMatrix: unknown format %d", format);
00469 }
00470 svd_closeFile(file);
00471 if (D) {
00472 S = svdConvertDtoS(D);
00473 svdFreeDMat(D);
00474 }
00475 return S;
00476 }
00477
00478 DMat svdLoadDenseMatrix(char *filename, int format) {
00479 SMat S = NULL;
00480 DMat D = NULL;
00481 FILE *file = svd_fatalReadFile(filename);
00482 switch (format) {
00483 case SVD_F_STH:
00484 S = svdLoadSparseTextHBFile(file);
00485 break;
00486 case SVD_F_ST:
00487 S = svdLoadSparseTextFile(file);
00488 break;
00489 case SVD_F_SB:
00490 S = svdLoadSparseBinaryFile(file);
00491 break;
00492 case SVD_F_DT:
00493 D = svdLoadDenseTextFile(file);
00494 break;
00495 case SVD_F_DB:
00496 D = svdLoadDenseBinaryFile(file);
00497 break;
00498 default: svd_error("svdLoadSparseMatrix: unknown format %d", format);
00499 }
00500 svd_closeFile(file);
00501 if (S) {
00502 D = svdConvertStoD(S);
00503 svdFreeSMat(S);
00504 }
00505 return D;
00506 }
00507
00508 void svdWriteSparseMatrix(SMat S, char *filename, int format) {
00509 DMat D = NULL;
00510 FILE *file = svd_writeFile(filename, FALSE);
00511 if (!file) {
00512 svd_error("svdWriteSparseMatrix: failed to write file %s\n", filename);
00513 return;
00514 }
00515 switch (format) {
00516 case SVD_F_STH:
00517 svdWriteSparseTextHBFile(S, file);
00518 break;
00519 case SVD_F_ST:
00520 svdWriteSparseTextFile(S, file);
00521 break;
00522 case SVD_F_SB:
00523 svdWriteSparseBinaryFile(S, file);
00524 break;
00525 case SVD_F_DT:
00526 D = svdConvertStoD(S);
00527 svdWriteDenseTextFile(D, file);
00528 break;
00529 case SVD_F_DB:
00530 D = svdConvertStoD(S);
00531 svdWriteDenseBinaryFile(D, file);
00532 break;
00533 default: svd_error("svdLoadSparseMatrix: unknown format %d", format);
00534 }
00535 svd_closeFile(file);
00536 if (D) svdFreeDMat(D);
00537 }
00538
00539 void svdWriteDenseMatrix(DMat D, char *filename, int format) {
00540 SMat S = NULL;
00541 FILE *file = svd_writeFile(filename, FALSE);
00542 if (!file) {
00543 svd_error("svdWriteDenseMatrix: failed to write file %s\n", filename);
00544 return;
00545 }
00546 switch (format) {
00547 case SVD_F_STH:
00548 S = svdConvertDtoS(D);
00549 svdWriteSparseTextHBFile(S, file);
00550 break;
00551 case SVD_F_ST:
00552 S = svdConvertDtoS(D);
00553 svdWriteSparseTextFile(S, file);
00554 break;
00555 case SVD_F_SB:
00556 S = svdConvertDtoS(D);
00557 svdWriteSparseBinaryFile(S, file);
00558 break;
00559 case SVD_F_DT:
00560 svdWriteDenseTextFile(D, file);
00561 break;
00562 case SVD_F_DB:
00563 svdWriteDenseBinaryFile(D, file);
00564 break;
00565 default: svd_error("svdLoadSparseMatrix: unknown format %d", format);
00566 }
00567 svd_closeFile(file);
00568 if (S) svdFreeSMat(S);
00569 }