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