mmio.c 13 KB

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