/* * Matrix Market I/O library for Titanium * * See http://math.nist.gov/MatrixMarket for details. * * Adapted from C I/O interface provided by MatrixMarket * by Kathy Yelick * */ import java.io.*; import java.util.*; /* * This is an incomplete version of the example code on the Matrix Market * web page, translated into Titanium. */ class MatrixCode { /* matrix encoding style taken from Matrix Market convention */ private char [] typecode; public static final String MATRIX_MARKET_BANNER = "%%MatrixMarket"; public static final String MM_MTX_STR = "matrix"; public static final String MM_ARRAY_STR = "array"; public static final String MM_DENSE_STR = "array"; public static final String MM_COORDINATE_STR = "coordinate"; public static final String MM_SPARSE_STR = "coordinate"; public static final String MM_COMPLEX_STR = "complex"; public static final String MM_REAL_STR = "real"; public static final String MM_INT_STR = "integer"; public static final String MM_GENERAL_STR = "general"; public static final String MM_SYMM_STR = "symmetric"; public static final String MM_HERM_STR = "hermitian"; public static final String MM_SKEW_STR = "skew-symmetric"; public static final String MM_PATTERN_STR = "pattern"; public MatrixCode () { typecode = new char [4]; clear(); } public void setMatrix() { typecode[0] = 'M'; } public void setCoordinate() { typecode[1] = 'C'; } public void setArray() { typecode[1] = 'A'; } public void setDense () { setArray(); } public void setSparse () { setCoordinate(); } public void setComplex () { typecode[2] = 'C'; } public void setReal () { typecode[2] = 'R'; } public void setPattern () { typecode[2] = 'P'; } public void setInteger () { typecode[2] = 'I'; } public void setSymmetric () { typecode[3] = 'S'; } public void setGeneral () { typecode[3] = 'G'; } public void setSkew () { typecode[3] = 'K'; } public void setHermitian () { typecode[3] = 'H';} public void clear () { typecode[0] = typecode[1] = typecode[2] = ' '; typecode[3] = 'G'; } public boolean isMatrix() { return ((typecode)[0]=='M'); } public boolean isSparse () { return (typecode[1]=='C'); } public boolean isCoordinate () { return (typecode[1]=='C'); } public boolean isDense () { return (typecode[1]=='A'); } public boolean isArray () { return (typecode[1]=='A'); } public boolean isComplex () { return (typecode[2]=='C'); } public boolean isReal () { return (typecode[2]=='R'); } public boolean isPattern () { return (typecode[2]=='P'); } public boolean isInteger () { return (typecode[2]=='I'); } public boolean isSymmetric () { return (typecode[3]=='S'); } public boolean isGeneral () { return (typecode[3]=='G'); } public boolean isSkew () { return (typecode[3]=='K'); } public boolean isHermitian () { return (typecode[3]=='H'); } public boolean isValid() { if (!isMatrix()) return false; if (isDense() && isPattern()) return false; if (isReal() && isHermitian()) return false; if (isPattern() && (isHermitian() || isSkew())) return false; return true; } public String toString() { // doesn't limit string length as in C version of the code String result = ""; /* should check for MTX type */ result += MM_MTX_STR; /* check for CRD or ARR matrix */ if (isSparse()) result += MM_SPARSE_STR; else if (isDense()) result += MM_DENSE_STR; else return null; /* check for element data type */ if (isReal()) result += MM_REAL_STR; else if (isComplex()) result += MM_COMPLEX_STR; else if (isPattern()) result += MM_PATTERN_STR; else if (isInteger()) result += MM_INT_STR; else return null; /* check for symmetry type */ if (isGeneral()) result += MM_GENERAL_STR; else if (isSymmetric()) result += MM_SYMM_STR; else if (isHermitian()) result += MM_HERM_STR; else if (isSkew()) result += MM_SKEW_STR; else return null; return result; } } class MatrixSize { public int n; public int m; public int nz; } class MMIO { public static MatrixCode mmReadBanner(DataInputStream dis) throws IOException { MatrixCode matcode = new MatrixCode(); StringTokenizer line; String banner; String mtx; String crd; String dataType; String storageScheme; try { line = new StringTokenizer(dis.readLine().toLowerCase()); banner = line.nextToken(); mtx = line.nextToken(); crd = line.nextToken(); dataType = line.nextToken(); storageScheme = line.nextToken(); } catch (NoSuchElementException e) { throw new IOException("Unable to parse header information"); } /* check for banner */ if (!banner.equals(MatrixCode.MATRIX_MARKET_BANNER.toLowerCase())) { System.out.println(banner); throw new IOException("File does not contain Matrix Market banner"); } /* first field should be "mtx" */ if (!mtx.equals(MatrixCode.MM_MTX_STR)) { throw new IOException("Missing mtx field in file header."); } matcode.setMatrix(); /* second field describes whether this is a sparse matrix (in coordinate storage) or a dense array */ if (crd.equals(MatrixCode.MM_SPARSE_STR)) { matcode.setSparse(); } else if (crd.equals(MatrixCode.MM_DENSE_STR)) { matcode.setDense(); } else { throw new IOException("Matrix type in file not supported"); } /* third field */ if (dataType.equals(MatrixCode.MM_REAL_STR)) { matcode.setReal(); } else if (dataType.equals(MatrixCode.MM_COMPLEX_STR)) { matcode.setComplex(); } else if (dataType.equals(MatrixCode.MM_PATTERN_STR)) { matcode.setPattern(); } else if (dataType.equals(MatrixCode.MM_INT_STR)) { matcode.setInteger(); } else { throw new IOException("Matrix type in file not supported"); } /* fourth field */ if (storageScheme.equals(MatrixCode.MM_GENERAL_STR)) { matcode.setGeneral(); } else if (storageScheme.equals(MatrixCode.MM_SYMM_STR)) { matcode.setSymmetric(); } else if (storageScheme.equals(MatrixCode.MM_HERM_STR)) { matcode.setHermitian(); } else if (storageScheme.equals(MatrixCode.MM_SKEW_STR)) { matcode.setSkew(); } else { throw new IOException("Matrix type in file not supported"); } return matcode; } public static MatrixSize readMtxCrdSize(DataInputStream dis) throws IOException { String line; /* continue scanning until you reach the end-of-comments */ do { line = dis.readLine(); } while (line.charAt(0) == '%'); StringTokenizer tokenizer = new StringTokenizer(line); /* line[] is either blank or has M,N, nz */ /* Assume all three are there. */ MatrixSize matsz = new MatrixSize(); matsz.m = Integer.parseInt(tokenizer.nextToken()); matsz.n = Integer.parseInt(tokenizer.nextToken()); matsz.nz = Integer.parseInt(tokenizer.nextToken()); return matsz; } public static MatMarket CSRLoad(String filename) throws IOException { int k, m, n, nz; MatrixCode matcode; DataInputStream dis = new DataInputStream(new FileInputStream(filename)); matcode = mmReadBanner(dis); if (!matcode.isSparse() || !matcode.isSymmetric() || !matcode.isReal()) { System.out.println("Sorry, this application does not support "); System.out.println("Market Market type: [" + matcode + " ]\n"); return new MatMarket(); } /* find out size of sparse matrix .... */ MatrixSize ms = readMtxCrdSize(dis); m = ms.m; n = ms.n; nz = 2*ms.nz-m; // blow up into non-symmetric format /* reserve memory for matrices */ MatrixEntry [1d] entries = new MatrixEntry [0:nz-1]; for (k = 0; k < nz; k++) { int row, col; double data; String tmp = dis.readLine(); StringTokenizer line = new StringTokenizer(tmp); row = Integer.parseInt(line.nextToken()); col = Integer.parseInt(line.nextToken()); String tmpds = line.nextToken(); Double tmpd = new Double(tmpds); data = (tmpd.doubleValue()); row -= 1; /* adjust to 0-based */ col -= 1; entries[k] = new MatrixEntry(row, col, data); if (row != col) { /* Fill out the other half... */ k += 1; entries[k] = new MatrixEntry(col, row, data); } } dis.close(); return new MatMarket(entries, m); } }