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