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