mmio.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. * Matrix Market I/O library for ANSI C
  3. *
  4. * See http://math.nist.gov/MatrixMarket for details.
  5. *
  6. *
  7. */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <ctype.h>
  12. #include "mmio.h"
  13. int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
  14. double **val_, int **I_, int **J_)
  15. {
  16. FILE *f;
  17. MM_typecode matcode;
  18. int M, N, nz;
  19. int i;
  20. double *val;
  21. int *I, *J;
  22. if ((f = fopen(fname, "r")) == NULL)
  23. return -1;
  24. if (mm_read_banner(f, &matcode) != 0)
  25. {
  26. printf("mm_read_unsymetric: Could not process Matrix Market banner ");
  27. printf(" in file [%s]\n", fname);
  28. return -1;
  29. }
  30. if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
  31. mm_is_sparse(matcode)))
  32. {
  33. fprintf(stderr, "Sorry, this application does not support ");
  34. fprintf(stderr, "Market Market type: [%s]\n",
  35. mm_typecode_to_str(matcode));
  36. return -1;
  37. }
  38. /* find out size of sparse matrix: M, N, nz .... */
  39. if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
  40. {
  41. fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
  42. return -1;
  43. }
  44. *M_ = M;
  45. *N_ = N;
  46. *nz_ = nz;
  47. /* reseve memory for matrices */
  48. I = (int *) malloc(nz * sizeof(int));
  49. J = (int *) malloc(nz * sizeof(int));
  50. val = (double *) malloc(nz * sizeof(double));
  51. *val_ = val;
  52. *I_ = I;
  53. *J_ = J;
  54. /* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
  55. /* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
  56. /* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
  57. for (i=0; i<nz; i++)
  58. {
  59. fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]);
  60. I[i]--; /* adjust from 1-based to 0-based */
  61. J[i]--;
  62. }
  63. fclose(f);
  64. return 0;
  65. }
  66. int mm_is_valid(MM_typecode matcode)
  67. {
  68. if (!mm_is_matrix(matcode)) return 0;
  69. if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
  70. if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
  71. if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
  72. mm_is_skew(matcode))) return 0;
  73. return 1;
  74. }
  75. int mm_read_banner(FILE *f, MM_typecode *matcode)
  76. {
  77. char line[MM_MAX_LINE_LENGTH];
  78. char banner[MM_MAX_TOKEN_LENGTH];
  79. char mtx[MM_MAX_TOKEN_LENGTH];
  80. char crd[MM_MAX_TOKEN_LENGTH];
  81. char data_type[MM_MAX_TOKEN_LENGTH];
  82. char storage_scheme[MM_MAX_TOKEN_LENGTH];
  83. char *p;
  84. mm_clear_typecode(matcode);
  85. if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
  86. return MM_PREMATURE_EOF;
  87. if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
  88. storage_scheme) != 5)
  89. return MM_PREMATURE_EOF;
  90. for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
  91. for (p=crd; *p!='\0'; *p=tolower(*p),p++);
  92. for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
  93. for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
  94. /* check for banner */
  95. if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
  96. return MM_NO_HEADER;
  97. /* first field should be "mtx" */
  98. if (strcmp(mtx, MM_MTX_STR) != 0)
  99. return MM_UNSUPPORTED_TYPE;
  100. mm_set_matrix(matcode);
  101. /* second field describes whether this is a sparse matrix (in coordinate
  102. storgae) or a dense array */
  103. if (strcmp(crd, MM_SPARSE_STR) == 0)
  104. mm_set_sparse(matcode);
  105. else
  106. if (strcmp(crd, MM_DENSE_STR) == 0)
  107. mm_set_dense(matcode);
  108. else
  109. return MM_UNSUPPORTED_TYPE;
  110. /* third field */
  111. if (strcmp(data_type, MM_REAL_STR) == 0)
  112. mm_set_real(matcode);
  113. else
  114. if (strcmp(data_type, MM_COMPLEX_STR) == 0)
  115. mm_set_complex(matcode);
  116. else
  117. if (strcmp(data_type, MM_PATTERN_STR) == 0)
  118. mm_set_pattern(matcode);
  119. else
  120. if (strcmp(data_type, MM_INT_STR) == 0)
  121. mm_set_integer(matcode);
  122. else
  123. return MM_UNSUPPORTED_TYPE;
  124. /* fourth field */
  125. if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
  126. mm_set_general(matcode);
  127. else
  128. if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
  129. mm_set_symmetric(matcode);
  130. else
  131. if (strcmp(storage_scheme, MM_HERM_STR) == 0)
  132. mm_set_hermitian(matcode);
  133. else
  134. if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
  135. mm_set_skew(matcode);
  136. else
  137. return MM_UNSUPPORTED_TYPE;
  138. return 0;
  139. }
  140. int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
  141. {
  142. if (fprintf(f, "%d %d %d\n", M, N, nz) != 3)
  143. return MM_COULD_NOT_WRITE_FILE;
  144. else
  145. return 0;
  146. }
  147. int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
  148. {
  149. char line[MM_MAX_LINE_LENGTH];
  150. int num_items_read;
  151. /* set return null parameter values, in case we exit with errors */
  152. *M = *N = *nz = 0;
  153. /* now continue scanning until you reach the end-of-comments */
  154. do
  155. {
  156. if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
  157. return MM_PREMATURE_EOF;
  158. }while (line[0] == '%');
  159. /* line[] is either blank or has M,N, nz */
  160. if (sscanf(line, "%d %d %d", M, N, nz) == 3)
  161. return 0;
  162. else
  163. do
  164. {
  165. num_items_read = fscanf(f, "%d %d %d", M, N, nz);
  166. if (num_items_read == EOF) return MM_PREMATURE_EOF;
  167. }
  168. while (num_items_read != 3);
  169. return 0;
  170. }
  171. int mm_read_mtx_array_size(FILE *f, int *M, int *N)
  172. {
  173. char line[MM_MAX_LINE_LENGTH];
  174. int num_items_read;
  175. /* set return null parameter values, in case we exit with errors */
  176. *M = *N = 0;
  177. /* now continue scanning until you reach the end-of-comments */
  178. do
  179. {
  180. if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
  181. return MM_PREMATURE_EOF;
  182. }while (line[0] == '%');
  183. /* line[] is either blank or has M,N, nz */
  184. if (sscanf(line, "%d %d", M, N) == 2)
  185. return 0;
  186. else /* we have a blank line */
  187. do
  188. {
  189. num_items_read = fscanf(f, "%d %d", M, N);
  190. if (num_items_read == EOF) return MM_PREMATURE_EOF;
  191. }
  192. while (num_items_read != 2);
  193. return 0;
  194. }
  195. int mm_write_mtx_array_size(FILE *f, int M, int N)
  196. {
  197. if (fprintf(f, "%d %d\n", M, N) != 2)
  198. return MM_COULD_NOT_WRITE_FILE;
  199. else
  200. return 0;
  201. }
  202. /*-------------------------------------------------------------------------*/
  203. /******************************************************************/
  204. /* use when I[], J[], and val[]J, and val[] are already allocated */
  205. /******************************************************************/
  206. int mm_read_mtx_crd_data(FILE *f, int M __attribute__ ((unused)) ,
  207. int N __attribute__ ((unused)) , int nz, int I[], int J[],
  208. double val[], MM_typecode matcode)
  209. {
  210. int i;
  211. if (mm_is_complex(matcode))
  212. {
  213. for (i=0; i<nz; i++)
  214. if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
  215. != 4) return MM_PREMATURE_EOF;
  216. }
  217. else if (mm_is_real(matcode))
  218. {
  219. for (i=0; i<nz; i++)
  220. {
  221. if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
  222. != 3) return MM_PREMATURE_EOF;
  223. }
  224. }
  225. else if (mm_is_pattern(matcode))
  226. {
  227. for (i=0; i<nz; i++)
  228. if (fscanf(f, "%d %d", &I[i], &J[i])
  229. != 2) return MM_PREMATURE_EOF;
  230. }
  231. else
  232. return MM_UNSUPPORTED_TYPE;
  233. return 0;
  234. }
  235. int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
  236. double *real, double *imag, MM_typecode matcode)
  237. {
  238. if (mm_is_complex(matcode))
  239. {
  240. if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
  241. != 4) return MM_PREMATURE_EOF;
  242. }
  243. else if (mm_is_real(matcode))
  244. {
  245. if (fscanf(f, "%d %d %lg\n", I, J, real)
  246. != 3) return MM_PREMATURE_EOF;
  247. }
  248. else if (mm_is_pattern(matcode))
  249. {
  250. if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
  251. }
  252. else
  253. return MM_UNSUPPORTED_TYPE;
  254. return 0;
  255. }
  256. /************************************************************************
  257. mm_read_mtx_crd() fills M, N, nz, array of values, and return
  258. type code, e.g. 'MCRS'
  259. if matrix is complex, values[] is of size 2*nz,
  260. (nz pairs of real/imaginary values)
  261. ************************************************************************/
  262. int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
  263. double **val, MM_typecode *matcode)
  264. {
  265. int ret_code;
  266. FILE *f;
  267. if (strcmp(fname, "stdin") == 0) f=stdin;
  268. else
  269. if ((f = fopen(fname, "r")) == NULL)
  270. return MM_COULD_NOT_READ_FILE;
  271. if ((ret_code = mm_read_banner(f, matcode)) != 0)
  272. return ret_code;
  273. if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
  274. mm_is_matrix(*matcode)))
  275. return MM_UNSUPPORTED_TYPE;
  276. if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
  277. return ret_code;
  278. *I = (int *) malloc(*nz * sizeof(int));
  279. *J = (int *) malloc(*nz * sizeof(int));
  280. *val = NULL;
  281. if (mm_is_complex(*matcode))
  282. {
  283. *val = (double *) malloc(*nz * 2 * sizeof(double));
  284. ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
  285. *matcode);
  286. if (ret_code != 0) return ret_code;
  287. }
  288. else if (mm_is_real(*matcode))
  289. {
  290. *val = (double *) malloc(*nz * sizeof(double));
  291. ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
  292. *matcode);
  293. if (ret_code != 0) return ret_code;
  294. }
  295. else if (mm_is_pattern(*matcode))
  296. {
  297. ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
  298. *matcode);
  299. if (ret_code != 0) return ret_code;
  300. }
  301. if (f != stdin) fclose(f);
  302. return 0;
  303. }
  304. int mm_write_banner(FILE *f, MM_typecode matcode)
  305. {
  306. char *str = mm_typecode_to_str(matcode);
  307. int ret_code;
  308. ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
  309. free(str);
  310. if (ret_code !=2 )
  311. return MM_COULD_NOT_WRITE_FILE;
  312. else
  313. return 0;
  314. }
  315. int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
  316. double val[], MM_typecode matcode)
  317. {
  318. FILE *f;
  319. int i;
  320. if (strcmp(fname, "stdout") == 0)
  321. f = stdout;
  322. else
  323. if ((f = fopen(fname, "w")) == NULL)
  324. return MM_COULD_NOT_WRITE_FILE;
  325. /* print banner followed by typecode */
  326. fprintf(f, "%s ", MatrixMarketBanner);
  327. fprintf(f, "%s\n", mm_typecode_to_str(matcode));
  328. /* print matrix sizes and nonzeros */
  329. fprintf(f, "%d %d %d\n", M, N, nz);
  330. /* print values */
  331. if (mm_is_pattern(matcode))
  332. for (i=0; i<nz; i++)
  333. fprintf(f, "%d %d\n", I[i], J[i]);
  334. else
  335. if (mm_is_real(matcode))
  336. for (i=0; i<nz; i++)
  337. fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
  338. else
  339. if (mm_is_complex(matcode))
  340. for (i=0; i<nz; i++)
  341. fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
  342. val[2*i+1]);
  343. else
  344. {
  345. if (f != stdout) fclose(f);
  346. return MM_UNSUPPORTED_TYPE;
  347. }
  348. if (f !=stdout) fclose(f);
  349. return 0;
  350. }
  351. /**
  352. * Create a new copy of a string s. mm_strdup() is a common routine, but
  353. * not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
  354. *
  355. */
  356. char *mm_strdup(const char *s)
  357. {
  358. int len = strlen(s);
  359. char *s2 = (char *) malloc((len+1)*sizeof(char));
  360. return strcpy(s2, s);
  361. }
  362. char *mm_typecode_to_str(MM_typecode matcode)
  363. {
  364. char buffer[MM_MAX_LINE_LENGTH];
  365. char *types[4];
  366. // char *mm_strdup(const char *);
  367. int error =0;
  368. /* check for MTX type */
  369. if (mm_is_matrix(matcode))
  370. types[0] = MM_MTX_STR;
  371. else
  372. error=1;
  373. /* check for CRD or ARR matrix */
  374. if (mm_is_sparse(matcode))
  375. types[1] = MM_SPARSE_STR;
  376. else
  377. if (mm_is_dense(matcode))
  378. types[1] = MM_DENSE_STR;
  379. else
  380. return NULL;
  381. /* check for element data type */
  382. if (mm_is_real(matcode))
  383. types[2] = MM_REAL_STR;
  384. else
  385. if (mm_is_complex(matcode))
  386. types[2] = MM_COMPLEX_STR;
  387. else
  388. if (mm_is_pattern(matcode))
  389. types[2] = MM_PATTERN_STR;
  390. else
  391. if (mm_is_integer(matcode))
  392. types[2] = MM_INT_STR;
  393. else
  394. return NULL;
  395. /* check for symmetry type */
  396. if (mm_is_general(matcode))
  397. types[3] = MM_GENERAL_STR;
  398. else
  399. if (mm_is_symmetric(matcode))
  400. types[3] = MM_SYMM_STR;
  401. else
  402. if (mm_is_hermitian(matcode))
  403. types[3] = MM_HERM_STR;
  404. else
  405. if (mm_is_skew(matcode))
  406. types[3] = MM_SKEW_STR;
  407. else
  408. return NULL;
  409. sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
  410. return mm_strdup(buffer);
  411. }