Rev 1824 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === Check/cholmod_read =================================================== *//* ========================================================================== *//* -----------------------------------------------------------------------------* CHOLMOD/Check Module. Version 0.6. Copyright (C) 2005, Timothy A. Davis* The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU* Lesser General Public License. See lesser.txt for a text of the license.* CHOLMOD is also available under other licenses; contact authors for details.* http://www.cise.ufl.edu/research/sparse* -------------------------------------------------------------------------- *//* Read a sparse matrix in triplet form. Compatible with all variations of* the Matrix Market "coord" format (http://www.nist.gov/MatrixMarket).** If the first line of the file starts with %%MatrixMarket, then it is* interpretted as a file in Matrix Market format. This line must have* the following format:** %%MatrixMarket matrix coord type storage** "type" is one of: real, complex, pattern, or integer.* "storage" is one of: general, hermitian, symmetric, or skew-symmetric** The strings are case-insentive. Only the first character is* significant (or the first two for skew-symmetric).** "coord" can be replaced with "array" in the Matrix Market format, but* this format not supported. The "integer" type is converted to real.* "type" is ignored; the actual type (real, complex, or pattern) is* inferred from the number of tokens in each line of the file (2: pattern,* 3: real, 4: complex). This is compatible with the Matrix Market format,* since pattern matrices must have two tokens per line, real matrices* must have 3, and complex matrices must have 4. A storage of "general"* implies an stype of zero (see below). "symmetric" and "hermitian"* imply an stype of -1. Skew-symmetric and complex symmetric matrices* are returned with both upper and lower triangular parts present, with* an stype of zero.** Any other lines starting with "%" are treated as comments, and are ignored.* Blank lines are ignored.** The first non-comment line contains 3 or 4 integers:** nrow ncol nnz stype** where stype is optional (stype does not appear in the Matrix Market format).* The matrix is nrow-by-ncol. The following nnz lines (excluding comments* and blank lines) each contain a single entry. Duplicates are permitted,* and are summed in the output matrix.** If stype is present, it denotes the storage format for the matrix.* stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general").* stype = -1 denotes a symmetric or Hermitian matrix whose lower triangular* entries are stored. Entries may be present in the upper triangular* part, but these are ignored (same as Matrix Market "symmetric").* stype = 1 denotes a symmetric or Hermitian matrix whose upper triangular* entries are stored. Entries may be present in the lower triangular* part, but these are ignored. This option is not in the Matrix Market* format.** If stype is not present it is inferred from the rest of the data (stype does* not appear in a Matrix Market file). If the matrix is rectangular, or has* entries in both the upper and lower triangular parts, then it is assumed to* be unsymmetric (stype=0). If only entries in the lower triangular part are* present, the matrix is assumed to have stype = -1. If only entries in the* upper triangular part are present, the matrix is assumed to have stype = 1.** Each nonzero consists of one line with 2, 3, or 4 entries. All lines must* have the same number of entries. The first two entries are the row and* column indices of the nonzero. If 3 entries are present, the 3rd entry is* the numerical value, and the matrix is real. If 4 entries are present,* the 3rd and 4th entries in the line are the real and imaginary parts of* a complex value.** The matrix can be either 0-based or 1-based. It is first assumed to be* one-based (compatible with Matrix Market), with row indices in the range* 1 to ncol and column indices in the range 1 to nrow. If a row or column* index of zero is found, the matrix is assumed to be zero-based (with row* indices in the range 0 to ncol-1 and column indices in the range 0 to* nrow-1).** For symmetric pattern-only matrices, the kth diagonal (if present) is set to* one plus the degree of the row/column k, and the off-diagonals are set to -1.* A symmetric pattern-only matrix with a zero-free diagonal is thus converted* into a symmetric positive definite matrix. All entries are set to one for* an unsymmetric pattern-only matrix. This differs from the MatrixMarket* format (A = mmread ('file') returns a binary pattern for A for symmetric* pattern-only matrices).*/#ifndef NCHECK#include "cholmod_check.h"#include "cholmod_internal.h"#include <string.h>#include <ctype.h>#define MAXLINE 1024/* ========================================================================== *//* === is_blank_line ======================================================== *//* ========================================================================== */static int is_blank_line /* TRUE if s is a blank line, FALSE otherwise */(char *s){int c, k ;for (k = 0 ; k <= MAXLINE ; k++){c = s [k] ;if (c == '\0'){/* end of line */break ;}if (!isspace (c)){/* non-space character */return (FALSE) ;}}return (TRUE) ;}/* ========================================================================== *//* === get_line ============================================================= *//* ========================================================================== *//* Get the next input line, discarding comments. */static int get_line /* returns # of items read, or -1 if error */(FILE *f, /* file to read from */long *i, /* row index */long *j, /* column index */double *x, /* real part */double *z, /* imaginary part */Int *stype) /* stype, as determined from Matrix Market header,* but with additional options for the skew-symmetric* and complex symmetric cases:* 1: symmetric, with upper part stored (not in Matrix Market format* 0: unsymmetric (Matrix Market "general")* -1: real symmetric or complex Hermitian, with lower part stored* (Matrix Market "real symmetric" or "complex hermitian")* -2: real or complex skew symmetric* -3: complex symmetric*/{char *p, s [MAXLINE+1] ;int k, c, c2, nitems, is_complex ;*i = 0 ;*j = 0 ;*x = 0 ;*z = 0 ;for ( ; ; ){s [0] = '\0' ;s [1] = '\0' ;s [MAXLINE] = '\0' ;if (fgets (s, MAXLINE, f) == NULL){/* end of file */return (EMPTY) ;}if (s [0] == '%'){/* a comment line */if (strncmp (s, "%%MatrixMarket", 14) == 0){/* this is a Matrix Market header, with the format:* %%MatrixMarket matrix coord type storage */p = s ;/* get "matrix" token */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;if (c != 'm'){/* bad format */return (EMPTY) ;}/* get "coord" token */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;if (c != 'c'){/* bad format, only "coordinate" is supported;* "array" is not supported */return (EMPTY) ;}/* get type token (real, pattern, complex, integer) */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i')){/* bad format */return (EMPTY) ;}is_complex = (c == 'c') ;/* get storage token (general, hermitian, symmetric, or* skew-symmetric) */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;c2 = tolower (*(p+1)) ;if (c == 'g'){/* "general" storage (unsymmetric matrix) */*stype = 0 ;}else if (c == 's' && c2 == 'y'){/* "symmetric" */if (is_complex){/* complex symmetric, lower triangular part present */*stype = -3 ;}else{/* real symmetric, lower triangular part present */*stype = -1 ;}}else if (c == 'h'){/* "hermitian" matrix, lower triangular part present */*stype = -1 ;}else if (c == 's' && c2 == 'k'){/* "skew-symmetric" (real or complex) */*stype = -2 ;}else{/* bad format */return (EMPTY) ;}}}else{/* an entry, or a blank line */if (is_blank_line (s)){/* the line is blank, continue and get the next line */continue ;}/* this line contains an entry */return (sscanf (s, "%ld %ld %lg %lg\n", i, j, x, z)) ;}}}/* ========================================================================== *//* === cholmod_read_triplet ================================================= *//* ========================================================================== */cholmod_triplet *CHOLMOD(read_triplet)(/* ---- input ---- */FILE *f, /* file to read from, assumed to already be open *//* --------------- */cholmod_common *Common){double x, z ;double *Tx ;Int *Ti, *Tj, *Rdeg, *Cdeg ;cholmod_triplet *T ;long l1, l2 ;Int nitems, nrow, ncol, nnz, stype, xtype, unknown, k, nshould, is_lower,is_upper, one_based, i, j, imax, jmax, ignore, skew_symmetric,extra, p ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (NULL) ;RETURN_IF_NULL (f, NULL) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* read the header line *//* ---------------------------------------------------------------------- */stype = 999 ;nitems = get_line (f, &l1, &l2, &x, &z, &stype) ;nrow = l1 ;ncol = l2 ;nnz = x ;if (nrow != ncol){stype = 0 ;}else if (nitems == 4){/* first line contains: m n nnz stype */if (z < 0){stype = -1 ;}else if (z > 0){stype = 1 ;}else{stype = 0 ;}}unknown = (stype == 999) ;if (nnz < 0 || nrow < 0 || ncol < 0 || nitems < 3){/* invalid matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}if (nrow == 0 || ncol == 0 || nnz == 0){/* return an empty matrix */return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL,Common)) ;}skew_symmetric = (stype == -2) ;extra = 0 ;if (stype < -1){/* -2: real or complex skew symmetric converted to unsymmetric *//* -3: complex symmetric converted to unsymmetric */stype = 0 ;extra = nnz ;}/* ---------------------------------------------------------------------- *//* allocate workspace *//* ---------------------------------------------------------------------- */CHOLMOD(allocate_work) (0, nrow + ncol, 0, Common) ;Rdeg = Common->Iwork ; /* size nrow */Cdeg = Rdeg + nrow ; /* size ncol *//* ---------------------------------------------------------------------- *//* read the nonzero entries *//* ---------------------------------------------------------------------- */is_lower = TRUE ;is_upper = TRUE ;one_based = TRUE ;imax = 0 ;jmax = 0 ;Tx = NULL ;Ti = NULL ;Tj = NULL ;xtype = 999 ;nshould = 0 ;for (k = 0 ; k < nnz ; k++){nitems = get_line (f, &l1, &l2, &x, &z, &ignore) ;i = l1 ;j = l2 ;/* ------------------------------------------------------------------ *//* for first entry: determine type and allocate triplet matrix *//* ------------------------------------------------------------------ */if (k == 0){if (nitems < 2 || nitems > 4){/* invalid matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}else if (nitems == 2){/* this will be converted into a real matrix later */xtype = CHOLMOD_PATTERN ;}else if (nitems == 3){xtype = CHOLMOD_REAL ;}else if (nitems == 4){xtype = CHOLMOD_COMPLEX ;}/* the rest of the lines should have the same number of entries */nshould = nitems ;T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz+extra, stype,(xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ;if (Common->status < CHOLMOD_OK){/* out of memory */return (NULL) ;}Ti = T->i ;Tj = T->j ;Tx = T->x ;T->nnz = nnz ;}/* ------------------------------------------------------------------ *//* save the entry in the triplet matrix *//* ------------------------------------------------------------------ */if (nitems != nshould || i < 0 || j < 0){/* wrong format, premature end-of-file, or negative indices */CHOLMOD(free_triplet) (&T, Common) ;ERROR (CHOLMOD_INVALID, "invalid matrix file") ;return (NULL) ;}Ti [k] = i ;Tj [k] = j ;if (i < j){/* this entry is in the upper triangular part */is_lower = FALSE ;}if (i > j){/* this entry is in the lower triangular part */is_upper = FALSE ;}if (xtype == CHOLMOD_REAL){Tx [k] = x ;}else if (xtype == CHOLMOD_COMPLEX){Tx [2*k ] = x ; /* real part */Tx [2*k+1] = z ; /* imaginary part */}if (i == 0 || j == 0){one_based = FALSE ;}imax = MAX (i, imax) ;jmax = MAX (j, jmax) ;}/* ---------------------------------------------------------------------- *//* convert to zero-based *//* ---------------------------------------------------------------------- */if (one_based){/* input matrix is one-based; convert matrix to zero-based */for (k = 0 ; k < nnz ; k++){Ti [k]-- ;Tj [k]-- ;}}if (one_based ? (imax > nrow || jmax > ncol):(imax >= nrow || jmax >= ncol)){/* indices out of range */CHOLMOD(free_triplet) (&T, Common) ;ERROR (CHOLMOD_INVALID, "indices out of range") ;return (NULL) ;}/* ---------------------------------------------------------------------- *//* add the remainder of skew-symmetric or complex symmetric matrices *//* ---------------------------------------------------------------------- */if (extra > 0){p = nnz ;for (k = 0 ; k < nnz ; k++){i = Ti [k] ;j = Tj [k] ;if (i != j){Ti [p] = j ;Tj [p] = i ;if (xtype == CHOLMOD_REAL){Tx [p] = skew_symmetric ? (-Tx [k]) : (Tx [k]) ;}else if (xtype == CHOLMOD_COMPLEX){Tx [2*p ] = skew_symmetric ? (-Tx [2*k ]) : (Tx [2*k ]);Tx [2*p+1] = skew_symmetric ? (-Tx [2*k+1]) : (Tx [2*k+1]);}p++ ;}}T->nnz = p ;nnz = p ;}/* ---------------------------------------------------------------------- *//* determine the stype, if not yet known *//* ---------------------------------------------------------------------- */if (unknown){if (is_lower && is_upper){/* diagonal matrix, symmetric with upper part present */stype = 1 ;}else if (is_lower && !is_upper){/* symmetric, lower triangular part present */stype = -1 ;}else if (!is_lower && is_upper){/* symmetric, upper triangular part present */stype = 1 ;}else{/* unsymmetric */stype = 0 ;}}T->stype = stype ;/* ---------------------------------------------------------------------- *//* create values for a pattern-only matrix *//* ---------------------------------------------------------------------- */if (xtype == CHOLMOD_PATTERN){if (stype == 0){/* unsymmetric case */for (k = 0 ; k < nnz ; k++){Tx [k] = 1 ;}}else{/* compute the row and columm degrees (excluding the diagonal) */for (i = 0 ; i < nrow ; i++){Rdeg [i] = 0 ;}for (j = 0 ; j < ncol ; j++){Cdeg [j] = 0 ;}for (k = 0 ; k < nnz ; k++){i = Ti [k] ;j = Tj [k] ;if ((stype < 0 && i > j) || (stype > 0 && i < j)){/* both a(i,j) and a(j,i) appear in the matrix */Rdeg [i]++ ;Cdeg [j]++ ;Rdeg [j]++ ;Cdeg [i]++ ;}}/* assign the numerical values */for (k = 0 ; k < nnz ; k++){i = Ti [k] ;j = Tj [k] ;Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ;}}}return (T) ;}/* ========================================================================== *//* === cholmod_read_sparse ================================================== *//* ========================================================================== *//* Read a sparse matrix from a file. See cholmod_read_triplet for a discussion* of the file format.** If Common->prefer_upper is TRUE (the default case), a symmetric matrix is* returned stored in upper-triangular form (A->stype == 1).*/cholmod_sparse *CHOLMOD(read_sparse)(/* ---- input ---- */FILE *f, /* file to read from, assumed to already be open *//* --------------- */cholmod_common *Common){cholmod_sparse *A, *A2 ;cholmod_triplet *T ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (NULL) ;RETURN_IF_NULL (f, NULL) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* convert to a sparse matrix in compressed-column form *//* ---------------------------------------------------------------------- */T = CHOLMOD(read_triplet) (f, Common) ;A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;CHOLMOD(free_triplet) (&T, Common) ;if (Common->prefer_upper && A != NULL && A->stype == -1){/* A=A' */A2 = CHOLMOD(transpose) (A, 2, Common) ;CHOLMOD(free_sparse) (&A, Common) ;A = A2 ;}return (A) ;}#endif