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
29int 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
96int 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
110int 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
189int 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
197int 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
227int 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
255int 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
271int 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
303int 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
336int 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
389int 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
402int 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
450char *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
458char *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