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