mmio.c 12 KB

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