Rev 3695 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === Check/cholmod_read =================================================== *//* ========================================================================== *//* -----------------------------------------------------------------------------* CHOLMOD/Check Module. Copyright (C) 2005-2006, 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 or dense form. A triplet matrix can be* returned as compressed-column sparse matrix. The file format is compatible* with all variations of the Matrix Market "coordinate" and "array" format* (http://www.nist.gov/MatrixMarket). The format supported by these routines* also allow other formats, where the Matrix Market header is optional.** Although the Matrix Market header is optional, I recommend that users stick* with the strict Matrix Market format. The optional format appears here to* support the reading of symmetric matrices stored with just their upper* triangular parts present, for testing and development of the A->stype > 0* format in CHOLMOD. That format is not included in the Matrix Market format.** 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 <fmt> <type> <storage>** <fmt> is one of: coordinate or array. The former is a sparse matrix in* triplet form. The latter is a dense matrix in column-major form.** <type> is one of: real, complex, pattern, or integer.* The functions here convert the "integer" and "pattern" types to real.** <storage> is one of: general, hermitian, symmetric, or skew-symmetric** The strings are case-insensitive. Only the first character is* significant (or the first two for skew-symmetric).** <type> is ignored for all matrices; the actual type (real, complex,* or pattern) is inferred from the number of tokens in each line of the* file. For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for* a dense "array" matrix: 1: real, 2: 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 always returned with both upper and lower* triangular parts present, with an stype of zero, since CHOLMOD does not* have a method for representing skew-symmetric and complex symmetric* matrices. Real symmetric and complex Hermitian matrices may optionally* be returned with both parts present.** Any other lines starting with "%" are treated as comments, and are ignored.* Blank lines are ignored. The Matrix Market header is optional in this* routine (it is not optional in the Matrix Market format).** Note that complex matrices are always returned in CHOLMOD_COMPLEX format,* not CHOLMOD_ZOMPLEX.** -----------------------------------------------------------------------------* Triplet matrices:* -----------------------------------------------------------------------------** The first data line of a triplet matrix 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.** The stype is first derived from the Matrix Market header. If the stype* appears as the fourth integer in the first data line, it is determined from* that line.** 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 real symmetric or complex 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* "real symmetric" and "complex Hermitian").* stype = 1 denotes a real symmetric or complex 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 present* in the Matrix Market format.** If stype is not present (no Matrix Market header and not in the first data* line) it is inferred from the rest of the data. 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.** After the first data line (with nrow, ncol, nnz, and optionally stype),* 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 (all matrices in the Matrix Market are one-based), 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).** If Common->prefer_binary is set to its default value of FALSE, then* 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-diagonal entries 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* Matrix Market format (A = mmread ('file') returns a binary pattern for A for* symmetric pattern-only matrices). If Common->prefer_binary is TRUE, then* this function returns a binary matrix (just like mmread('file')).** -----------------------------------------------------------------------------* Dense matrices:* -----------------------------------------------------------------------------** A dense matrix is specified by the Matrix Market "array" format. The* Matrix Market header is optional; if not present, the matrix is assumed to* be in the Matrix Market "general" format. The first data line contains just* two integers:** nrow ncol** The <type> can be real, integer, or complex (not pattern). These functions* convert an integer type to real. The entries in the matrix are stored in* column-major format, with one line per entry. Two entries are present in* each line for complex matrices, one for real and integer matrices. In* rectangular and unsymmetric matrices, all entries are present. For real* symmetric or complex Hermitian matrices, only entries in the lower triangular* part appear. For skew-symmetric matrices, only entries in the strictly* lower triangular part appear.** Since CHOLMOD does not have a data structure for presenting dense symmetric/* Hermitian matrices, these functions always return a dense matrix in its* general form, with both upper and lower parts present.*/#ifndef NCHECK#include "cholmod_internal.h"#include "cholmod_check.h"#include <string.h>#include <ctype.h>/* The MatrixMarket format specificies a maximum line length of 1024 */#define MAXLINE 1030/* ========================================================================== *//* === get_line ============================================================= *//* ========================================================================== *//* Read one line of the file, return TRUE if successful, FALSE if EOF. */static int get_line (FILE *f, char *buf){buf [0] = '\0' ;buf [1] = '\0' ;buf [MAXLINE] = '\0' ;return (fgets (buf, MAXLINE, f) != NULL) ;}/* ========================================================================== *//* === fix_inf ============================================================== *//* ========================================================================== *//* Replace huge values with +/- Inf's, since scanf and printf don't deal* with Inf's properly.*/static double fix_inf (double x){if ((x >= HUGE_DOUBLE) || (x <= -HUGE_DOUBLE)){/* treat this as +/- Inf (assume 2*x leads to overflow) */x = 2*x ;}return (x) ;}/* ========================================================================== *//* === is_blank_line ======================================================== *//* ========================================================================== *//* TRUE if s is a blank line or comment, FALSE otherwise */static int is_blank_line(char *s){int c, k ;if (s [0] == '%'){/* a comment line */return (TRUE) ;}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) ;}/* ========================================================================== *//* === read_header ========================================================== *//* ========================================================================== *//* Read the header. This consists of zero or more comment lines (blank, or* starting with a "%" in the first column), followed by a single data line* containing up to four numerical values.** The first line may optionally be a Matrix Market header line, of the form** %%MatrixMarket matrix <fmt> <type> <storage>** The first data line of a sparse matrix in triplet form consists of 3 or 4* numerical values:** nrow ncol nnz stype** where stype is optional (it does not appear in the Matrix Market file* format). The first line of a dense matrix in column-major form consists of* two numerical values:** nrow ncol** The stype of the matrix is determine either from the Matrix Market header,* or (optionally) from the first data line. stypes of 0 to -3 directly* correlate with the Matrix Market format; stype = 1 is an extension to that* format.** 999: unknown (will be inferred from the data)* 1: real symmetric or complex Hermitian with upper part stored* (not in the Matrix Market format)* 0: unsymmetric (same as 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 (lower part stored, can only be* specified by Matrix Market header)* -3: complex symmetric (lower part stored)* specified by Matrix Market header)** The Matrix Market header is optional. If stype appears in the first data* line, it is determine by that data line. Otherwise, if the Matrix Market* header appears, stype is determined from that header. If stype does not* appear, it is set to "unknown" (999).*/#define STYPE_UNKNOWN 999#define STYPE_SYMMETRIC_UPPER 1#define STYPE_UNSYMMETRIC 0#define STYPE_SYMMETRIC_LOWER -1#define STYPE_SKEW_SYMMETRIC -2#define STYPE_COMPLEX_SYMMETRIC_LOWER -3static int read_header /* returns TRUE if successful, FALSE on error */(/* ---- input ---- */FILE *f, /* file to read from *//* ---- output --- */char *buf, /* a character array of size MAXLINE+1 */int *mtype, /* CHOLMOD_TRIPLET or CHOLMOD_DENSE */size_t *nrow, /* number of rows in the matrix */size_t *ncol, /* number of columns in the matrix */size_t *nnz, /* number of entries in a triplet matrix (0 for dense)*/int *stype /* stype (see above) */){char *p ;int first = TRUE, got_mm_header = FALSE, c, c2, is_complex, nitems ;double l1, l2, l3, l4 ;*mtype = CHOLMOD_TRIPLET ;*nrow = 0 ;*ncol = 0 ;*nnz = 0 ;*stype = STYPE_UNKNOWN ;for ( ; ; ){/* ------------------------------------------------------------------ *//* get the next line *//* ------------------------------------------------------------------ */if (!get_line (f, buf)){/* premature end of file */return (FALSE) ;}if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0)){/* -------------------------------------------------------------- *//* read a Matrix Market header *//* -------------------------------------------------------------- */got_mm_header = TRUE ;p = buf ;/* -------------------------------------------------------------- *//* get "matrix" token *//* -------------------------------------------------------------- */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;if (c != 'm'){/* bad format */return (FALSE) ;}/* -------------------------------------------------------------- *//* get the fmt token ("coord" or "array") *//* -------------------------------------------------------------- */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;if (c == 'c'){*mtype = CHOLMOD_TRIPLET ;}else if (c == 'a'){*mtype = CHOLMOD_DENSE ;}else{/* bad format, neither "coordinate" nor "array" */return (FALSE) ;}/* -------------------------------------------------------------- *//* 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 (FALSE) ;}is_complex = (c == 'c') ;/* -------------------------------------------------------------- *//* get storage token (general, hermitian, symmetric, skew) *//* -------------------------------------------------------------- */while (*p && !isspace (*p)) p++ ;while (*p && isspace (*p)) p++ ;c = tolower (*p) ;c2 = tolower (*(p+1)) ;if (c == 'g'){/* "general" storage (unsymmetric matrix), both parts present */*stype = STYPE_UNSYMMETRIC ;}else if (c == 's' && c2 == 'y'){/* "symmetric" */if (is_complex){/* complex symmetric, lower triangular part present */*stype = STYPE_COMPLEX_SYMMETRIC_LOWER ;}else{/* real symmetric, lower triangular part present */*stype = STYPE_SYMMETRIC_LOWER ;}}else if (c == 'h'){/* "hermitian" matrix, lower triangular part present */*stype = STYPE_SYMMETRIC_LOWER ;}else if (c == 's' && c2 == 'k'){/* "skew-symmetric" (real or complex), lower part present */*stype = STYPE_SKEW_SYMMETRIC ;}else{/* bad format */return (FALSE) ;}}else if (is_blank_line (buf)){/* -------------------------------------------------------------- *//* blank line or comment line *//* -------------------------------------------------------------- */continue ;}else{/* -------------------------------------------------------------- *//* read the first data line and return *//* -------------------------------------------------------------- *//* format: nrow ncol nnz stype */l1 = EMPTY ;l2 = EMPTY ;l3 = 0 ;l4 = 0 ;nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ;if (nitems < 2 || nitems > 4 || l1 > Int_max || l2 > Int_max){/* invalid matrix */return (FALSE) ;}*nrow = l1 ;*ncol = l2 ;if (nitems == 2){/* a dense matrix */if (!got_mm_header){*mtype = CHOLMOD_DENSE ;*stype = STYPE_UNSYMMETRIC ;}}if (nitems == 3 || nitems == 4){/* a sparse triplet matrix */*nnz = l3 ;if (!got_mm_header){*mtype = CHOLMOD_TRIPLET ;}}if (nitems == 4){/* an stype specified here can only be 1, 0, or -1 */if (l4 < 0){*stype = STYPE_SYMMETRIC_LOWER ;}else if (l4 > 0){*stype = STYPE_SYMMETRIC_UPPER ;}else{*stype = STYPE_UNSYMMETRIC ;}}if (*nrow != *ncol){/* a rectangular matrix must be unsymmetric */*stype = STYPE_UNSYMMETRIC ;}return (TRUE) ;}first = FALSE ;}}/* ========================================================================== *//* === read_triplet ========================================================= *//* ========================================================================== *//* Header has already been read in, including first line (nrow ncol nnz stype).* Read the triplets. */static cholmod_triplet *read_triplet(/* ---- input ---- */FILE *f, /* file to read from, must already be open */size_t nrow, /* number of rows */size_t ncol, /* number of columns */size_t nnz, /* number of triplets in file to read */int stype, /* stype from header, or "unknown" */int prefer_unsym, /* if TRUE, always return T->stype of zero *//* ---- workspace */char *buf, /* of size MAXLINE+1 *//* --------------- */cholmod_common *Common){double x, z ;double *Tx ;Int *Ti, *Tj, *Rdeg, *Cdeg ;cholmod_triplet *T ;double l1, l2 ;Int nitems, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j,imax, jmax, skew_symmetric, p, complex_symmetric ;size_t s, nnz2, extra ;int ok = TRUE ;/* ---------------------------------------------------------------------- *//* quick return for empty matrix *//* ---------------------------------------------------------------------- */if (nrow == 0 || ncol == 0 || nnz == 0){/* return an empty matrix */return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL,Common)) ;}/* ---------------------------------------------------------------------- *//* special stype cases: unknown, skew symmetric, and complex symmetric *//* ---------------------------------------------------------------------- */unknown = (stype == STYPE_UNKNOWN) ;skew_symmetric = (stype == STYPE_SKEW_SYMMETRIC) ;complex_symmetric = (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) ;extra = 0 ;if (stype < STYPE_SYMMETRIC_LOWER|| (prefer_unsym && stype != STYPE_UNSYMMETRIC)){/* 999: unknown might be converted to unsymmetric *//* 1: symmetric upper converted to unsym. if prefer_unsym is TRUE *//* -1: symmetric lower converted to unsym. if prefer_unsym is TRUE *//* -2: real or complex skew symmetric converted to unsymmetric *//* -3: complex symmetric converted to unsymmetric */stype = STYPE_UNSYMMETRIC ;extra = nnz ;}nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ;/* ---------------------------------------------------------------------- *//* allocate workspace *//* ---------------------------------------------------------------------- *//* s = nrow + ncol */s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ;if (!ok || nrow > Int_max || ncol > Int_max || nnz > Int_max){ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;return (NULL) ;}CHOLMOD(allocate_work) (0, s, 0, Common) ;Rdeg = Common->Iwork ; /* size nrow */Cdeg = Rdeg + nrow ; /* size ncol *//* ---------------------------------------------------------------------- *//* read the triplets *//* ---------------------------------------------------------------------- */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 < (Int) nnz ; k++){/* ------------------------------------------------------------------ *//* get the next triplet, skipping blank lines and comment lines *//* ------------------------------------------------------------------ */l1 = EMPTY ;l2 = EMPTY ;x = 0 ;z = 0 ;for ( ; ; ){if (!get_line (f, buf)){/* premature end of file - not enough triplets read in */ERROR (CHOLMOD_INVALID, "premature EOF") ;return (NULL) ;}if (is_blank_line (buf)){/* blank line or comment */continue ;}nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ;x = fix_inf (x) ;z = fix_inf (z) ;break ;}nitems = (nitems == EOF) ? 0 : nitems ;i = l1 ;j = l2 ;/* ------------------------------------------------------------------ *//* for first triplet: 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 ;/* allocate triplet matrix */T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, 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 < (Int) nnz ; k++){Ti [k]-- ;Tj [k]-- ;}}if (one_based ?(imax > (Int) nrow || jmax > (Int) ncol) :(imax >= (Int) nrow || jmax >= (Int) ncol)){/* indices out of range */CHOLMOD(free_triplet) (&T, Common) ;ERROR (CHOLMOD_INVALID, "indices out of range") ;return (NULL) ;}/* ---------------------------------------------------------------------- *//* determine the stype, if not yet known *//* ---------------------------------------------------------------------- */if (unknown){if (is_lower && is_upper){/* diagonal matrix, symmetric with upper part present */stype = STYPE_SYMMETRIC_UPPER ;}else if (is_lower && !is_upper){/* symmetric, lower triangular part present */stype = STYPE_SYMMETRIC_LOWER ;}else if (!is_lower && is_upper){/* symmetric, upper triangular part present */stype = STYPE_SYMMETRIC_UPPER ;}else{/* unsymmetric */stype = STYPE_UNSYMMETRIC ;extra = 0 ;}}/* ---------------------------------------------------------------------- *//* add the remainder of symmetric, skew-symmetric or Hermitian matrices *//* ---------------------------------------------------------------------- *//* note that this step is not done for real symmetric or complex Hermitian* matrices, unless prefer_unsym is TRUE */if (extra > 0){p = nnz ;for (k = 0 ; k < (Int) nnz ; k++){i = Ti [k] ;j = Tj [k] ;if (i != j){Ti [p] = j ;Tj [p] = i ;if (xtype == CHOLMOD_REAL){if (skew_symmetric){Tx [p] = -Tx [k] ;}else{Tx [p] = Tx [k] ;}}else if (xtype == CHOLMOD_COMPLEX){if (skew_symmetric){Tx [2*p ] = -Tx [2*k ] ;Tx [2*p+1] = -Tx [2*k+1] ;}else if (complex_symmetric){Tx [2*p ] = Tx [2*k ] ;Tx [2*p+1] = Tx [2*k+1] ;}else /* Hermitian */{Tx [2*p ] = Tx [2*k ] ;Tx [2*p+1] = -Tx [2*k+1] ;}}p++ ;}}T->nnz = p ;nnz = p ;}T->stype = stype ;/* ---------------------------------------------------------------------- *//* create values for a pattern-only matrix *//* ---------------------------------------------------------------------- */if (xtype == CHOLMOD_PATTERN){if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary){/* unsymmetric case, or binary case */for (k = 0 ; k < (Int) nnz ; k++){Tx [k] = 1 ;}}else{/* compute the row and columm degrees (excluding the diagonal) */for (i = 0 ; i < (Int) nrow ; i++){Rdeg [i] = 0 ;}for (j = 0 ; j < (Int) ncol ; j++){Cdeg [j] = 0 ;}for (k = 0 ; k < (Int) 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 < (Int) nnz ; k++){i = Ti [k] ;j = Tj [k] ;Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ;}}}/* ---------------------------------------------------------------------- *//* return the new triplet matrix *//* ---------------------------------------------------------------------- */return (T) ;}/* ========================================================================== *//* === read_dense =========================================================== *//* ========================================================================== *//* Header has already been read in, including first line (nrow ncol).* Read a dense matrix. */static cholmod_dense *read_dense(/* ---- input ---- */FILE *f, /* file to read from, must already be open */size_t nrow, /* number of rows */size_t ncol, /* number of columns */int stype, /* stype from header *//* ---- workspace */char *buf, /* of size MAXLINE+1 *//* --------------- */cholmod_common *Common){double x, z ;double *Xx = NULL ;cholmod_dense *X ;Int nitems, xtype = -1, nshould = 0, i, j, k, kup, first ;/* ---------------------------------------------------------------------- *//* quick return for empty matrix *//* ---------------------------------------------------------------------- */if (nrow == 0 || ncol == 0){/* return an empty dense matrix */return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL, Common)) ;}/* ---------------------------------------------------------------------- *//* read the entries *//* ---------------------------------------------------------------------- */first = TRUE ;for (j = 0 ; j < (Int) ncol ; j++){/* ------------------------------------------------------------------ *//* get the row index of the first entry in the file for column j *//* ------------------------------------------------------------------ */if (stype == STYPE_UNSYMMETRIC){i = 0 ;}else if (stype == STYPE_SKEW_SYMMETRIC){i = j+1 ;}else /* real symmetric or complex Hermitian lower */{i = j ;}/* ------------------------------------------------------------------ *//* get column j *//* ------------------------------------------------------------------ */for ( ; i < (Int) nrow ; i++){/* -------------------------------------------------------------- *//* get the next entry, skipping blank lines and comment lines *//* -------------------------------------------------------------- */x = 0 ;z = 0 ;for ( ; ; ){if (!get_line (f, buf)){/* premature end of file - not enough entries read in */ERROR (CHOLMOD_INVALID, "premature EOF") ;return (NULL) ;}if (is_blank_line (buf)){/* blank line or comment */continue ;}nitems = sscanf (buf, "%lg %lg\n", &x, &z) ;x = fix_inf (x) ;z = fix_inf (z) ;break ;}nitems = (nitems == EOF) ? 0 : nitems ;/* -------------------------------------------------------------- *//* for first entry: determine type and allocate dense matrix *//* -------------------------------------------------------------- */if (first){first = FALSE ;if (nitems < 1 || nitems > 2){/* invalid matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}else if (nitems == 1){/* a real matrix */xtype = CHOLMOD_REAL ;}else if (nitems == 2){/* a complex matrix */xtype = CHOLMOD_COMPLEX ;}/* the rest of the lines should have same number of entries */nshould = nitems ;/* allocate the result */X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ;if (Common->status < CHOLMOD_OK){/* out of memory */return (NULL) ;}Xx = X->x ;}/* -------------------------------------------------------------- *//* save the entry in the dense matrix *//* -------------------------------------------------------------- */if (nitems != nshould){/* wrong format or premature end-of-file */CHOLMOD(free_dense) (&X, Common) ;ERROR (CHOLMOD_INVALID, "invalid matrix file") ;return (NULL) ;}k = i + j*nrow ;kup = j + i*nrow ;if (xtype == CHOLMOD_REAL){/* real matrix */Xx [k] = x ;if (k != kup){if (stype == STYPE_SYMMETRIC_LOWER){/* real symmetric matrix */Xx [kup] = x ;}else if (stype == STYPE_SKEW_SYMMETRIC){/* real skew symmetric matrix */Xx [kup] = -x ;}}}else if (xtype == CHOLMOD_COMPLEX){Xx [2*k ] = x ; /* real part */Xx [2*k+1] = z ; /* imaginary part */if (k != kup){if (stype == STYPE_SYMMETRIC_LOWER){/* complex Hermitian */Xx [2*kup ] = x ; /* real part */Xx [2*kup+1] = -z ; /* imaginary part */}else if (stype == STYPE_SKEW_SYMMETRIC){/* complex skew symmetric */Xx [2*kup ] = -x ; /* real part */Xx [2*kup+1] = -z ; /* imaginary part */}if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER){/* complex symmetric */Xx [2*kup ] = x ; /* real part */Xx [2*kup+1] = z ; /* imaginary part */}}}}}/* ---------------------------------------------------------------------- *//* return the new dense matrix *//* ---------------------------------------------------------------------- */return (X) ;}/* ========================================================================== *//* === cholmod_read_triplet ================================================= *//* ========================================================================== *//* Read in a triplet matrix from a file. */cholmod_triplet *CHOLMOD(read_triplet)(/* ---- input ---- */FILE *f, /* file to read from, must already be open *//* --------------- */cholmod_common *Common){char buf [MAXLINE+1] ;size_t nrow, ncol, nnz ;int stype, mtype ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (NULL) ;RETURN_IF_NULL (f, NULL) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* read the header and first data line *//* ---------------------------------------------------------------------- */if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||mtype != CHOLMOD_TRIPLET){/* invalid matrix - this function can only read in a triplet matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}/* ---------------------------------------------------------------------- *//* read the triplet matrix *//* ---------------------------------------------------------------------- */return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, buf, Common)) ;}/* ========================================================================== *//* === 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, must 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) ;}/* ========================================================================== *//* === cholmod_read_dense =================================================== *//* ========================================================================== *//* Read a dense matrix from a file. */cholmod_dense *CHOLMOD(read_dense)(/* ---- input ---- */FILE *f, /* file to read from, must already be open *//* --------------- */cholmod_common *Common){char buf [MAXLINE+1] ;size_t nrow, ncol, nnz ;int stype, mtype ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (NULL) ;RETURN_IF_NULL (f, NULL) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* read the header and first data line *//* ---------------------------------------------------------------------- */if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||mtype != CHOLMOD_DENSE){/* invalid matrix - this function can only read in a dense matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}/* ---------------------------------------------------------------------- *//* read the dense matrix *//* ---------------------------------------------------------------------- */return (read_dense (f, nrow, ncol, stype, buf, Common)) ;}/* ========================================================================== *//* === cholmod_read_matrix ================================================== *//* ========================================================================== *//* Read a triplet matrix, sparse matrix or a dense matrix from a file. Returns* a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense* object. The type of object is passed back to the caller as the mtype* argument. */void *CHOLMOD(read_matrix)(/* ---- input ---- */FILE *f, /* file to read from, must already be open */int prefer, /* If 0, a sparse matrix is always return as a* cholmod_triplet form. It can have any stype* (symmetric-lower, unsymmetric, or* symmetric-upper).* If 1, a sparse matrix is returned as an unsymmetric* cholmod_sparse form (A->stype == 0), with both* upper and lower triangular parts present.* This is what the MATLAB mread mexFunction does,* since MATLAB does not have an stype.* If 2, a sparse matrix is returned with an stype of 0* or 1 (unsymmetric, or symmetric with upper part* stored).* This argument has no effect for dense matrices.*//* ---- output---- */int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE *//* --------------- */cholmod_common *Common){void *G = NULL ;cholmod_sparse *A, *A2 ;cholmod_triplet *T ;char buf [MAXLINE+1] ;size_t nrow, ncol, nnz ;int stype ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (NULL) ;RETURN_IF_NULL (f, NULL) ;RETURN_IF_NULL (mtype, NULL) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* read the header to determine the mtype *//* ---------------------------------------------------------------------- */if (!read_header (f, buf, mtype, &nrow, &ncol, &nnz, &stype)){/* invalid matrix */ERROR (CHOLMOD_INVALID, "invalid format") ;return (NULL) ;}/* ---------------------------------------------------------------------- *//* read a matrix *//* ---------------------------------------------------------------------- */if (*mtype == CHOLMOD_TRIPLET){/* read in the triplet matrix, converting to unsymmetric format if* prefer == 1 */T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, buf, Common) ;if (prefer == 0){/* return matrix in its original triplet form */G = T ;}else{/* return matrix in a compressed-column form */A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;CHOLMOD(free_triplet) (&T, Common) ;if (A != NULL && prefer == 2 && A->stype == -1){/* convert A from symmetric-lower to symmetric-upper */A2 = CHOLMOD(transpose) (A, 2, Common) ;CHOLMOD(free_sparse) (&A, Common) ;A = A2 ;}*mtype = CHOLMOD_SPARSE ;G = A ;}}else if (*mtype == CHOLMOD_DENSE){/* return a dense matrix */G = read_dense (f, nrow, ncol, stype, buf, Common) ;}return (G) ;}#endif