mmio.c 12 KB

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