c======================================================================= c=== RBio/RBread ======================================================= c======================================================================= c RBio: a MATLAB toolbox for reading and writing sparse matrices in c Rutherford/Boeing format. c Copyright (c) 2006, Timothy A. Davis, Univ. Florida. Version 1.0. c----------------------------------------------------------------------- c RBheader: read Rutherford/Boeing header lines c----------------------------------------------------------------------- c c Rutherford/Boeing file type is a 3-character string: c c (1) R: real, C: complex, P: pattern only, I: integer c mkind: R: 0, P: 1, C: 2, I: 3 c c (2) S: symmetric, U: unsymmetric, H: Hermitian, Z: skew symmetric, c R: rectangular c skind: R: -1, U: 0, S: 1, H: 2, Z: 3 c c (3) A: assembled, E: element form c nelnz = 0 for A, number of elements for E c c pattern matrices are given numerical values of 1 (except PZA). c PZA matrices have +1 in the lower triangular part and -1 in c the upper triangular part. c c The matrix is nrow-by-ncol with nnz entries. c For symmetric matrices, Ai and Ax are of size 2*nnz (the upper c triangular part is constructed). To skip this construction, c pass skind = 0 to RBpattern. c----------------------------------------------------------------------- subroutine RBheader (title, key, mtype, nrow, ncol, nnz, $ ptrfmt, indfmt, valfmt, mkind, cmplex, skind, nelnz, info) integer $ nrow, ncol, nnz, totcrd, ptrcrd, nelnz, $ indcrd, valcrd, mkind, skind, cmplex, info character title*72, key*8, mtype*3, ptrfmt*16, indfmt*16, $ valfmt*20, rhstyp*3 logical fem c ---------------------------------------------------------------- c read header lines 1-4 c ---------------------------------------------------------------- read (7, 10, err = 91, end = 91) $ title, key, $ totcrd, ptrcrd, indcrd, valcrd, $ mtype, nrow, ncol, nnz, nelnz, $ ptrfmt, indfmt, valfmt 10 format (a72, a8 / 4i14 / a3, 11x, 4i14 / 2a16, a20) if (nrow .lt. 0 .or. ncol .lt. 0 .or. nnz .lt. 0) then c error: invalid matrix dimensions info = -6 return endif c ---------------------------------------------------------------- c skip the Harwell/Boeing header line 5, if present c ---------------------------------------------------------------- read (7, 20, err = 91, end = 91) rhstyp 20 format (a3) if ((rhstyp (1:1) .eq. 'F' .or. rhstyp (1:1) .eq. 'f' .or. $ rhstyp (1:1) .eq. 'M' .or. rhstyp (1:1) .eq. 'm')) then c This is the 5th line Harwell/Boeing format. Ignore it. call mexErrMsgTxt ('Harwell/Boeing RHS ignored') else c Backspace one record, since we just read in one row of c the column pointers. backspace (unit = 7) endif c ---------------------------------------------------------------- c determine if real, pattern, integer, or complex c ---------------------------------------------------------------- if (mtype (1:1) .eq. 'R' .or. mtype (1:1) .eq. 'r') then c real mkind = 0 cmplex = 0 elseif (mtype (1:1) .eq. 'P' .or. mtype (1:1) .eq. 'p') then c pattern mkind = 1 cmplex = 0 elseif (mtype (1:1) .eq. 'C' .or. mtype (1:1) .eq. 'c') then c complex mkind = 2 cmplex = 1 elseif (mtype (1:1) .eq. 'I' .or. mtype (1:1) .eq. 'i') then c integer mkind = 3 cmplex = 0 else c error: invalid matrix type info = -5 return endif c ---------------------------------------------------------------- c determine if the upper part must be constructed c ---------------------------------------------------------------- if (mtype (2:2) .eq. 'R' .or. mtype (2:2) .eq. 'r') then c rectangular: RRA, PRA, IRA, and CRA matrices skind = -1 elseif (mtype (2:2) .eq. 'U' .or. mtype (2:2) .eq. 'u') then c unsymmetric: RUA, PUA, IUA, and CUA matrices skind = 0 elseif (mtype (2:2) .eq. 'S' .or. mtype (2:2) .eq. 's') then c symmetric: RSA, PSA, ISA, and CSA matrices skind = 1 elseif (mtype (2:2) .eq. 'H' .or. mtype (2:2) .eq. 'h') then c Hermitian: CHA (PHA, IHA, and RHA are valid, but atypical) skind = 2 elseif (mtype (2:2) .eq. 'Z' .or. mtype (2:2) .eq. 'z') then c skew symmetric: RZA, PZA, IZA, and CZA skind = 3 else c error: invalid matrix type info = -5 return endif c ---------------------------------------------------------------- c assembled matrices or elemental matrices (**A, **E) c ---------------------------------------------------------------- if (mtype (3:3) .eq. 'A' .or. mtype (3:3) .eq. 'a') then c assembled - ignore nelnz fem = .false. nelnz = 0 elseif (mtype (3:3) .eq. 'E' .or. mtype (3:3) .eq. 'e') then c finite-element fem = .true. continue else c error: invalid matrix type info = -5 return endif c ---------------------------------------------------------------- c assembled matrices must be square if skind is not R c ---------------------------------------------------------------- if (.not. fem .and. skind .ne. -1 .and. nrow .ne. ncol) then c error: invalid matrix dimensions info = -6 return endif c ---------------------------------------------------------------- c matrix is valid c ---------------------------------------------------------------- info = 0 return c ---------------------------------------------------------------- c error reading file c ---------------------------------------------------------------- 91 info = -91 return end c----------------------------------------------------------------------- c RBpattern: read the column pointers and row indices c----------------------------------------------------------------------- c w and cp are both of size ncol+1 (undefined on input). c c The matrix is contained in Ap, Ai, and Ax on output (undefined on c input). It has nzeros explicit zero entries. cp (1..ncol+1) are c the column pointers for the matrix Z that will contain all the c explicit zero entries. Ax is not read in (see RBrread and c RBcread). c c info is returned as: c 0 ok c -1 invalid column pointers c -2 row index out of range c -3 duplicate entry c -4 entries in upper triangular part of symmetric matrix c -5 invalid matrix type c -6 invalid dimensions c -7 matrix contains unsorted columns c -91 error reading file (header) c -92 error reading file (column pointers) c -93 error reading file (row indices) c -94 error reading file (numerical values: A, or sparse b) c----------------------------------------------------------------------- subroutine RBpattern (ptrfmt, indfmt, nrow, ncol, nnz, skind, $ Ap, Ai, w, cp, info, nw) integer $ nrow, ncol, nnz, skind, info, Ap (ncol+1), Ai (nnz), $ nw, w (nw), cp (ncol+1) character ptrfmt*16, indfmt*16 integer $ j, i, p, ilast c ---------------------------------------------------------------- c read the pointers and check them c ---------------------------------------------------------------- call RBiread (ptrfmt, ncol+1, Ap, info) if (info .lt. 0) then return endif if (Ap (1) .ne. 1 .or. Ap (ncol+1) - 1 .ne. nnz) then c error: invalid matrix (col pointers) info = -1 return endif do 10 j = 2, ncol+1 if (Ap (j) .lt. Ap (j-1)) then c error: invalid matrix (col pointers) info = -1 return endif 10 continue c ---------------------------------------------------------------- c read the row indices and check them c ---------------------------------------------------------------- call RBiread (indfmt, nnz, Ai, info) if (info .lt. 0) then info = -93 return endif do 20 i = 1, nrow w (i) = -1 20 continue do 40 j = 1, ncol ilast = 0 do 30 p = Ap (j), Ap (j+1) - 1 i = Ai (p) if (i .lt. 1 .or. i .gt. nrow) then c error: row index out of range c print *, 'column j, rows!', j, i, nrow info = -2 return endif if (w (i) .eq. j) then c error: duplicate entry in matrix print *, 'column j, duplicate!', j, i info = -3 return endif w (i) = j if (i .lt. ilast) then c error: matrix contains unsorted columns print *, 'column j, unsorted!', j, i, ilast info = -7 return endif ilast = i 30 continue 40 continue c ---------------------------------------------------------------- c construct new column pointers for symmetric matrices c ---------------------------------------------------------------- if (skind .gt. 0) then c ------------------------------------------------------------ c compute the column counts for the whole matrix c ------------------------------------------------------------ do 50 j = 1, ncol+1 w (j) = 0 50 continue do 70 j = 1, ncol do 60 p = Ap (j), Ap (j+1)-1 i = Ai (p) if (i .eq. j) then c diagonal entry, only appears as A(j,j) w (j) = w (j) + 1 elseif (i .gt. j) then c entry in lower triangular part, A(i,j) will be c duplicated as A(j,i), so count it in both cols w (i) = w (i) + 1 w (j) = w (j) + 1 else c error: entry in upper triangular part info = -4 c print *, 'column j, entries in upper!',j return endif 60 continue 70 continue c ------------------------------------------------------------ c compute the new column pointers c ------------------------------------------------------------ cp (1) = 1 do 80 j = 2, ncol+1 cp (j) = cp (j-1) + w (j-1) 80 continue endif c ---------------------------------------------------------------- c matrix is valid c ---------------------------------------------------------------- info = 0 return end c----------------------------------------------------------------------- c RBmangle: convert 1-based matrix into 0-based c----------------------------------------------------------------------- subroutine RBmangle (ncol, Ap, Ai, nnz) integer $ ncol, nnz, p, j, Ap (ncol+1), Ai (*) nnz = Ap (ncol + 1) - 1 do 10 j = 1, ncol+1 Ap (j) = Ap (j) - 1 10 continue do 20 p = 1, nnz Ai (p) = Ai (p) - 1 20 continue return end c----------------------------------------------------------------------- subroutine RBiread (ifmt, n, I, info) integer $ n, I (n), info, p character ifmt*16 info = 0 read (7, ifmt, err = 92, end = 92) (I (p), p = 1, n) return 92 info = -92 return end c----------------------------------------------------------------------- subroutine RBxread (xfmt, n, X, info) integer $ mkind, n, info, p double precision X (n) character xfmt*20 info = 0 read (7, xfmt, err = 94, end = 94) (X (p), p = 1, n) return 94 info = -94 return end c----------------------------------------------------------------------- c RBerr: report an error to MATLAB c----------------------------------------------------------------------- c c info = 0 is OK, info < 0 is a fatal error, info > 0 is a warning subroutine RBerr (info) integer $ info if (info .eq. -7) then call mexErrMsgTxt ('matrix contains unsorted columns') elseif (info .eq. -1) then call mexErrMsgTxt ('invalid matrix (col pointers)') elseif (info .eq. -2) then call mexErrMsgTxt ('row index out of range)') elseif (info .eq. -3) then call mexErrMsgTxt ('duplicate entry in matrix') elseif (info .eq. -4) then call mexErrMsgTxt ('invalid symmetric matrix') elseif (info .eq. -5) then call mexErrMsgTxt ('invalid matrix type') elseif (info .eq. -6) then call mexErrMsgTxt ('invalid matrix dimensions') elseif (info .eq. -911) then call mexErrMsgTxt ('finite-element form not supported') elseif (info .eq. -91) then call mexErrMsgTxt ('error reading file (header)') elseif (info .eq. -92) then call mexErrMsgTxt ('error reading file (column pointers)') elseif (info .eq. -93) then call mexErrMsgTxt ('error reading file (row indices)') elseif (info .eq. -94) then call mexErrMsgTxt ('error reading file (numerical values)') elseif (info .eq. -95) then call mexErrMsgTxt ('error reading file (right-hand-side)') elseif (info .lt. 0) then print *, info call mexErrMsgTxt ('error (unspecified)') elseif (info .gt. 0) then print *, info call mexErrMsgTxt ('warning (unspecified)') endif return end