1 //  (C) Copyright Jeremy Siek 2004
2 //  Distributed under the Boost Software License, Version 1.0. (See
3 //  accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5 
6 /*
7 Fri Aug 15 16:29:47 EDT 1997
8 
9                        Harwell-Boeing File I/O in C
10                                 V. 1.0
11 
12            National Institute of Standards and Technology, MD.
13                              K.A. Remington
14 
15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16                                 NOTICE
17 
18  Permission to use, copy, modify, and distribute this software and
19  its documentation for any purpose and without fee is hereby granted
20  provided that the above copyright notice appear in all copies and
21  that both the copyright notice and this permission notice appear in
22  supporting documentation.
23 
24  Neither the Author nor the Institution (National Institute of Standards
25  and Technology) make any representations about the suitability of this
26  software for any purpose. This software is provided "as is" without
27  expressed or implied warranty.
28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29 
30                          ---------------------
31                          INTERFACE DESCRIPTION
32                          ---------------------
33   ---------------
34   QUERY FUNCTIONS
35   ---------------
36 
37   FUNCTION:
38 
39   int readHB_info(const char *filename, int *M, int *N, int *nz,
40   char **Type, int *Nrhs)
41 
42   DESCRIPTION:
43 
44   The readHB_info function opens and reads the header information from
45   the specified Harwell-Boeing file, and reports back the number of rows
46   and columns in the stored matrix (M and N), the number of nonzeros in
47   the matrix (nz), the 3-character matrix type(Type), and the number of
48   right-hand-sides stored along with the matrix (Nrhs).  This function
49   is designed to retrieve basic size information which can be used to
50   allocate arrays.
51 
52   FUNCTION:
53 
54   int  readHB_header(FILE* in_file, char* Title, char* Key, char* Type,
55                     int* Nrow, int* Ncol, int* Nnzero, int* Nrhs,
56                     char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
57                     int* Ptrcrd, int* Indcrd, int* Valcrd, int* Rhscrd,
58                     char *Rhstype)
59 
60   DESCRIPTION:
61 
62   More detailed than the readHB_info function, readHB_header() reads from
63   the specified Harwell-Boeing file all of the header information.
64 
65 
66   ------------------------------
67   DOUBLE PRECISION I/O FUNCTIONS
68   ------------------------------
69   FUNCTION:
70 
71   int readHB_newmat_double(const char *filename, int *M, int *N, *int nz,
72   int **colptr, int **rowind,  double**val)
73 
74   int readHB_mat_double(const char *filename, int *colptr, int *rowind,
75   double*val)
76 
77 
78   DESCRIPTION:
79 
80   This function opens and reads the specified file, interpreting its
81   contents as a sparse matrix stored in the Harwell/Boeing standard
82   format.  (See readHB_aux_double to read auxillary vectors.)
83         -- Values are interpreted as double precision numbers. --
84 
85   The "mat" function uses _pre-allocated_ vectors to hold the index and
86   nonzero value information.
87 
88   The "newmat" function allocates vectors to hold the index and nonzero
89   value information, and returns pointers to these vectors along with
90   matrix dimension and number of nonzeros.
91 
92   FUNCTION:
93 
94   int readHB_aux_double(const char* filename, const char AuxType, double b[])
95 
96   int readHB_newaux_double(const char* filename, const char AuxType, double** b)
97 
98   DESCRIPTION:
99 
100   This function opens and reads from the specified file auxillary vector(s).
101   The char argument Auxtype determines which type of auxillary vector(s)
102   will be read (if present in the file).
103 
104                   AuxType = 'F'   right-hand-side
105                   AuxType = 'G'   initial estimate (Guess)
106                   AuxType = 'X'   eXact solution
107 
108   If Nrhs > 1, all of the Nrhs vectors of the given type are read and
109   stored in column-major order in the vector b.
110 
111   The "newaux" function allocates a vector to hold the values retrieved.
112   The "mat" function uses a _pre-allocated_ vector to hold the values.
113 
114   FUNCTION:
115 
116   int writeHB_mat_double(const char* filename, int M, int N,
117                         int nz, const int colptr[], const int rowind[],
118                         const double val[], int Nrhs, const double rhs[],
119                         const double guess[], const double exact[],
120                         const char* Title, const char* Key, const char* Type,
121                         char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
122                         const char* Rhstype)
123 
124   DESCRIPTION:
125 
126   The writeHB_mat_double function opens the named file and writes the specified
127   matrix and optional auxillary vector(s) to that file in Harwell-Boeing
128   format.  The format arguments (Ptrfmt,Indfmt,Valfmt, and Rhsfmt) are
129   character strings specifying "Fortran-style" output formats -- as they
130   would appear in a Harwell-Boeing file.  They are used to produce output
131   which is as close as possible to what would be produced by Fortran code,
132   but note that "D" and "P" edit descriptors are not supported.
133   If NULL, the following defaults will be used:
134                     Ptrfmt = Indfmt = "(8I10)"
135                     Valfmt = Rhsfmt = "(4E20.13)"
136 
137   -----------------------
138   CHARACTER I/O FUNCTIONS
139   -----------------------
140   FUNCTION:
141 
142   int readHB_mat_char(const char* filename, int colptr[], int rowind[],
143                                            char val[], char* Valfmt)
144   int readHB_newmat_char(const char* filename, int* M, int* N, int* nonzeros,
145                           int** colptr, int** rowind, char** val, char** Valfmt)
146 
147   DESCRIPTION:
148 
149   This function opens and reads the specified file, interpreting its
150   contents as a sparse matrix stored in the Harwell/Boeing standard
151   format.  (See readHB_aux_char to read auxillary vectors.)
152               -- Values are interpreted as char strings.     --
153   (Used to translate exact values from the file into a new storage format.)
154 
155   The "mat" function uses _pre-allocated_ arrays to hold the index and
156   nonzero value information.
157 
158   The "newmat" function allocates char arrays to hold the index
159   and nonzero value information, and returns pointers to these arrays
160   along with matrix dimension and number of nonzeros.
161 
162   FUNCTION:
163 
164   int readHB_aux_char(const char* filename, const char AuxType, char b[])
165   int readHB_newaux_char(const char* filename, const char AuxType, char** b,
166                          char** Rhsfmt)
167 
168   DESCRIPTION:
169 
170   This function opens and reads from the specified file auxillary vector(s).
171   The char argument Auxtype determines which type of auxillary vector(s)
172   will be read (if present in the file).
173 
174                   AuxType = 'F'   right-hand-side
175                   AuxType = 'G'   initial estimate (Guess)
176                   AuxType = 'X'   eXact solution
177 
178   If Nrhs > 1, all of the Nrhs vectors of the given type are read and
179   stored in column-major order in the vector b.
180 
181   The "newaux" function allocates a character array to hold the values
182                 retrieved.
183   The "mat" function uses a _pre-allocated_ array to hold the values.
184 
185   FUNCTION:
186 
187   int writeHB_mat_char(const char* filename, int M, int N,
188                         int nz, const int colptr[], const int rowind[],
189                         const char val[], int Nrhs, const char rhs[],
190                         const char guess[], const char exact[],
191                         const char* Title, const char* Key, const char* Type,
192                         char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
193                         const char* Rhstype)
194 
195   DESCRIPTION:
196 
197   The writeHB_mat_char function opens the named file and writes the specified
198   matrix and optional auxillary vector(s) to that file in Harwell-Boeing
199   format.  The format arguments (Ptrfmt,Indfmt,Valfmt, and Rhsfmt) are
200   character strings specifying "Fortran-style" output formats -- as they
201   would appear in a Harwell-Boeing file.  Valfmt and Rhsfmt must accurately
202   represent the character representation of the values stored in val[]
203   and rhs[].
204 
205   If NULL, the following defaults will be used for the integer vectors:
206                     Ptrfmt = Indfmt = "(8I10)"
207                     Valfmt = Rhsfmt = "(4E20.13)"
208 
209 
210 */
211 
212 /*---------------------------------------------------------------------*/
213 /* If zero-based indexing is desired, _SP_base should be set to 0      */
214 /* This will cause indices read from H-B files to be decremented by 1  */
215 /*             and indices written to H-B files to be incremented by 1 */
216 /*            <<<  Standard usage is _SP_base = 1  >>>                 */
217 #ifndef _SP_base
218 #define _SP_base 1
219 #endif
220 /*---------------------------------------------------------------------*/
221 
222 #include "iohb.h"
223 #include<stdio.h>
224 #include<stdlib.h>
225 #include<string.h>
226 #include<math.h>
227 
228 char* substr(const char* S, const int pos, const int len);
229 void upcase(char* S);
230 void IOHBTerminate(const char* message);
231 
readHB_info(const char * filename,int * M,int * N,int * nz,char ** Type,int * Nrhs)232 int readHB_info(const char* filename, int* M, int* N, int* nz, char** Type,
233                                                       int* Nrhs)
234 {
235 /****************************************************************************/
236 /*  The readHB_info function opens and reads the header information from    */
237 /*  the specified Harwell-Boeing file, and reports back the number of rows  */
238 /*  and columns in the stored matrix (M and N), the number of nonzeros in   */
239 /*  the matrix (nz), and the number of right-hand-sides stored along with   */
240 /*  the matrix (Nrhs).                                                      */
241 /*                                                                          */
242 /*  For a description of the Harwell Boeing standard, see:                  */
243 /*            Duff, et al.,  ACM TOMS Vol.15, No.1, March 1989              */
244 /*                                                                          */
245 /*    ----------                                                            */
246 /*    **CAVEAT**                                                            */
247 /*    ----------                                                            */
248 /*  **  If the input file does not adhere to the H/B format, the  **        */
249 /*  **             results will be unpredictable.                 **        */
250 /*                                                                          */
251 /****************************************************************************/
252     FILE *in_file;
253     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
254     int Nrow, Ncol, Nnzero;
255     char* mat_type;
256     char Title[73], Key[9], Rhstype[4];
257     char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
258 
259     mat_type = *Type;
260     if ( mat_type == NULL ) IOHBTerminate("Insufficient memory for mat_typen");
261 
262     if ( (in_file = fopen( filename, "r")) == NULL ) {
263        fprintf(stderr,"Error: Cannot open file: %s\n",filename);
264        return 0;
265     }
266 
267     readHB_header(in_file, Title, Key, mat_type, &Nrow, &Ncol, &Nnzero, Nrhs,
268                   Ptrfmt, Indfmt, Valfmt, Rhsfmt,
269                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
270     fclose(in_file);
271     *Type = mat_type;
272     *(*Type+3) = (char) NULL;
273     *M    = Nrow;
274     *N    = Ncol;
275     *nz   = Nnzero;
276     if (Rhscrd == 0) {*Nrhs = 0;}
277 
278 /*  In verbose mode, print some of the header information:   */
279 /*
280     if (verbose == 1)
281     {
282         printf("Reading from Harwell-Boeing file %s (verbose on)...\n",filename);
283         printf("  Title: %s\n",Title);
284         printf("  Key:   %s\n",Key);
285         printf("  The stored matrix is %i by %i with %i nonzeros.\n",
286                 *M, *N, *nz );
287         printf("  %i right-hand--side(s) stored.\n",*Nrhs);
288     }
289 */
290 
291     return 1;
292 
293 }
294 
295 
296 
readHB_header(FILE * in_file,char * Title,char * Key,char * Type,int * Nrow,int * Ncol,int * Nnzero,int * Nrhs,char * Ptrfmt,char * Indfmt,char * Valfmt,char * Rhsfmt,int * Ptrcrd,int * Indcrd,int * Valcrd,int * Rhscrd,char * Rhstype)297 int readHB_header(FILE* in_file, char* Title, char* Key, char* Type,
298                     int* Nrow, int* Ncol, int* Nnzero, int* Nrhs,
299                     char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
300                     int* Ptrcrd, int* Indcrd, int* Valcrd, int* Rhscrd,
301                     char *Rhstype)
302 {
303 /*************************************************************************/
304 /*  Read header information from the named H/B file...                   */
305 /*************************************************************************/
306     int Totcrd,Neltvl,Nrhsix;
307     char line[BUFSIZ];
308 
309 /*  First line:   */
310     fgets(line, BUFSIZ, in_file);
311     if ( sscanf(line,"%*s") < 0 )
312         IOHBTerminate("iohb.c: Null (or blank) first line of HB file.\n");
313     (void) sscanf(line, "%72c%8[^\n]", Title, Key);
314     *(Key+8) = (char) NULL;
315     *(Title+72) = (char) NULL;
316 
317 /*  Second line:  */
318     fgets(line, BUFSIZ, in_file);
319     if ( sscanf(line,"%*s") < 0 )
320         IOHBTerminate("iohb.c: Null (or blank) second line of HB file.\n");
321     if ( sscanf(line,"%i",&Totcrd) != 1) Totcrd = 0;
322     if ( sscanf(line,"%*i%i",Ptrcrd) != 1) *Ptrcrd = 0;
323     if ( sscanf(line,"%*i%*i%i",Indcrd) != 1) *Indcrd = 0;
324     if ( sscanf(line,"%*i%*i%*i%i",Valcrd) != 1) *Valcrd = 0;
325     if ( sscanf(line,"%*i%*i%*i%*i%i",Rhscrd) != 1) *Rhscrd = 0;
326 
327 /*  Third line:   */
328     fgets(line, BUFSIZ, in_file);
329     if ( sscanf(line,"%*s") < 0 )
330         IOHBTerminate("iohb.c: Null (or blank) third line of HB file.\n");
331     if ( sscanf(line, "%3c", Type) != 1)
332         IOHBTerminate("iohb.c: Invalid Type info, line 3 of Harwell-Boeing file.\n");
333     upcase(Type);
334     if ( sscanf(line,"%*3c%i",Nrow) != 1) *Nrow = 0 ;
335     if ( sscanf(line,"%*3c%*i%i",Ncol) != 1) *Ncol = 0 ;
336     if ( sscanf(line,"%*3c%*i%*i%i",Nnzero) != 1) *Nnzero = 0 ;
337     if ( sscanf(line,"%*3c%*i%*i%*i%i",&Neltvl) != 1) Neltvl = 0 ;
338 
339 /*  Fourth line:  */
340     fgets(line, BUFSIZ, in_file);
341     if ( sscanf(line,"%*s") < 0 )
342         IOHBTerminate("iohb.c: Null (or blank) fourth line of HB file.\n");
343     if ( sscanf(line, "%16c",Ptrfmt) != 1)
344         IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n");
345     if ( sscanf(line, "%*16c%16c",Indfmt) != 1)
346         IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n");
347     if ( sscanf(line, "%*16c%*16c%20c",Valfmt) != 1)
348         IOHBTerminate("iohb.c: Invalid format info, line 4 of Harwell-Boeing file.\n");
349     sscanf(line, "%*16c%*16c%*20c%20c",Rhsfmt);
350     *(Ptrfmt+16) = (char) NULL;
351     *(Indfmt+16) = (char) NULL;
352     *(Valfmt+20) = (char) NULL;
353     *(Rhsfmt+20) = (char) NULL;
354 
355 /*  (Optional) Fifth line: */
356     if (*Rhscrd != 0 )
357     {
358        fgets(line, BUFSIZ, in_file);
359        if ( sscanf(line,"%*s") < 0 )
360            IOHBTerminate("iohb.c: Null (or blank) fifth line of HB file.\n");
361        if ( sscanf(line, "%3c", Rhstype) != 1)
362          IOHBTerminate("iohb.c: Invalid RHS type information, line 5 of Harwell-Boeing file.\n");
363        if ( sscanf(line, "%*3c%i", Nrhs) != 1) *Nrhs = 0;
364        if ( sscanf(line, "%*3c%*i%i", &Nrhsix) != 1) Nrhsix = 0;
365     }
366     return 1;
367 }
368 
369 
readHB_mat_double(const char * filename,int colptr[],int rowind[],double val[])370 int readHB_mat_double(const char* filename, int colptr[], int rowind[],
371                                                                  double val[])
372 {
373 /****************************************************************************/
374 /*  This function opens and reads the specified file, interpreting its      */
375 /*  contents as a sparse matrix stored in the Harwell/Boeing standard       */
376 /*  format and creating compressed column storage scheme vectors to hold    */
377 /*  the index and nonzero value information.                                */
378 /*                                                                          */
379 /*    ----------                                                            */
380 /*    **CAVEAT**                                                            */
381 /*    ----------                                                            */
382 /*  Parsing real formats from Fortran is tricky, and this file reader       */
383 /*  does not claim to be foolproof.   It has been tested for cases when     */
384 /*  the real values are printed consistently and evenly spaced on each      */
385 /*  line, with Fixed (F), and Exponential (E or D) formats.                 */
386 /*                                                                          */
387 /*  **  If the input file does not adhere to the H/B format, the  **        */
388 /*  **             results will be unpredictable.                 **        */
389 /*                                                                          */
390 /****************************************************************************/
391     FILE *in_file;
392     int i,j,ind,col,offset,count,last,Nrhs;
393     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
394     int Nrow, Ncol, Nnzero, Nentries;
395     int Ptrperline, Ptrwidth, Indperline, Indwidth;
396     int Valperline, Valwidth, Valprec;
397     int Valflag;           /* Indicates 'E','D', or 'F' float format */
398     char* ThisElement;
399     char Title[73], Key[8], Type[4], Rhstype[4];
400     char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
401     char line[BUFSIZ];
402 
403     if ( (in_file = fopen( filename, "r")) == NULL ) {
404        fprintf(stderr,"Error: Cannot open file: %s\n",filename);
405        return 0;
406     }
407 
408     readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs,
409                   Ptrfmt, Indfmt, Valfmt, Rhsfmt,
410                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
411 
412 /*  Parse the array input formats from Line 3 of HB file  */
413     ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
414     ParseIfmt(Indfmt,&Indperline,&Indwidth);
415     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
416     ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
417     }
418 
419 /*  Read column pointer array:   */
420 
421     offset = 1-_SP_base;  /* if base 0 storage is declared (via macro definition), */
422                           /* then storage entries are offset by 1                  */
423 
424     ThisElement = (char *) malloc(Ptrwidth+1);
425     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
426     *(ThisElement+Ptrwidth) = (char) NULL;
427     count=0;
428     for (i=0;i<Ptrcrd;i++)
429     {
430        fgets(line, BUFSIZ, in_file);
431        if ( sscanf(line,"%*s") < 0 )
432          IOHBTerminate("iohb.c: Null (or blank) line in pointer data region of HB file.\n");
433        col =  0;
434        for (ind = 0;ind<Ptrperline;ind++)
435        {
436           if (count > Ncol) break;
437           strncpy(ThisElement,line+col,Ptrwidth);
438   /* ThisElement = substr(line,col,Ptrwidth); */
439           colptr[count] = atoi(ThisElement)-offset;
440           count++; col += Ptrwidth;
441        }
442     }
443     free(ThisElement);
444 
445 /*  Read row index array:  */
446 
447     ThisElement = (char *) malloc(Indwidth+1);
448     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
449     *(ThisElement+Indwidth) = (char) NULL;
450     count = 0;
451     for (i=0;i<Indcrd;i++)
452     {
453        fgets(line, BUFSIZ, in_file);
454        if ( sscanf(line,"%*s") < 0 )
455          IOHBTerminate("iohb.c: Null (or blank) line in index data region of HB file.\n");
456        col =  0;
457        for (ind = 0;ind<Indperline;ind++)
458        {
459           if (count == Nnzero) break;
460           strncpy(ThisElement,line+col,Indwidth);
461 /*        ThisElement = substr(line,col,Indwidth); */
462           rowind[count] = atoi(ThisElement)-offset;
463           count++; col += Indwidth;
464        }
465     }
466     free(ThisElement);
467 
468 /*  Read array of values:  */
469 
470     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
471 
472        if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
473            else Nentries = Nnzero;
474 
475     ThisElement = (char *) malloc(Valwidth+1);
476     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
477     *(ThisElement+Valwidth) = (char) NULL;
478     count = 0;
479     for (i=0;i<Valcrd;i++)
480     {
481        fgets(line, BUFSIZ, in_file);
482        if ( sscanf(line,"%*s") < 0 )
483          IOHBTerminate("iohb.c: Null (or blank) line in value data region of HB file.\n");
484        if (Valflag == 'D')  {
485           while( strchr(line,'D') ) *strchr(line,'D') = 'E';
486 /*           *strchr(Valfmt,'D') = 'E'; */
487        }
488        col =  0;
489        for (ind = 0;ind<Valperline;ind++)
490        {
491           if (count == Nentries) break;
492           strncpy(ThisElement,line+col,Valwidth);
493           /*ThisElement = substr(line,col,Valwidth);*/
494           if ( Valflag != 'F' && strchr(ThisElement,'E') == NULL ) {
495              /* insert a char prefix for exp */
496              last = strlen(ThisElement);
497              for (j=last+1;j>=0;j--) {
498                 ThisElement[j] = ThisElement[j-1];
499                 if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) {
500                    ThisElement[j-1] = Valflag;
501                    break;
502                 }
503              }
504           }
505           val[count] = atof(ThisElement);
506           count++; col += Valwidth;
507        }
508     }
509     free(ThisElement);
510     }
511 
512     fclose(in_file);
513     return 1;
514 }
515 
readHB_newmat_double(const char * filename,int * M,int * N,int * nonzeros,int ** colptr,int ** rowind,double ** val)516 int readHB_newmat_double(const char* filename, int* M, int* N, int* nonzeros,
517                          int** colptr, int** rowind, double** val)
518 {
519         int Nrhs;
520         char *Type;
521 
522         readHB_info(filename, M, N, nonzeros, &Type, &Nrhs);
523 
524         *colptr = (int *)malloc((*N+1)*sizeof(int));
525         if ( *colptr == NULL ) IOHBTerminate("Insufficient memory for colptr.\n");
526         *rowind = (int *)malloc(*nonzeros*sizeof(int));
527         if ( *rowind == NULL ) IOHBTerminate("Insufficient memory for rowind.\n");
528         if ( Type[0] == 'C' ) {
529 /*
530    fprintf(stderr, "Warning: Reading complex data from HB file %s.\n",filename);
531    fprintf(stderr, "         Real and imaginary parts will be interlaced in val[].\n");
532 */
533            /* Malloc enough space for real AND imaginary parts of val[] */
534            *val = (double *)malloc(*nonzeros*sizeof(double)*2);
535            if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n");
536         } else {
537            if ( Type[0] != 'P' ) {
538              /* Malloc enough space for real array val[] */
539              *val = (double *)malloc(*nonzeros*sizeof(double));
540              if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n");
541            }
542         }  /* No val[] space needed if pattern only */
543         return readHB_mat_double(filename, *colptr, *rowind, *val);
544 
545 }
546 
readHB_aux_double(const char * filename,const char AuxType,double b[])547 int readHB_aux_double(const char* filename, const char AuxType, double b[])
548 {
549 /****************************************************************************/
550 /*  This function opens and reads the specified file, placing auxillary     */
551 /*  vector(s) of the given type (if available) in b.                        */
552 /*  Return value is the number of vectors successfully read.                */
553 /*                                                                          */
554 /*                AuxType = 'F'   full right-hand-side vector(s)            */
555 /*                AuxType = 'G'   initial Guess vector(s)                   */
556 /*                AuxType = 'X'   eXact solution vector(s)                  */
557 /*                                                                          */
558 /*    ----------                                                            */
559 /*    **CAVEAT**                                                            */
560 /*    ----------                                                            */
561 /*  Parsing real formats from Fortran is tricky, and this file reader       */
562 /*  does not claim to be foolproof.   It has been tested for cases when     */
563 /*  the real values are printed consistently and evenly spaced on each      */
564 /*  line, with Fixed (F), and Exponential (E or D) formats.                 */
565 /*                                                                          */
566 /*  **  If the input file does not adhere to the H/B format, the  **        */
567 /*  **             results will be unpredictable.                 **        */
568 /*                                                                          */
569 /****************************************************************************/
570     FILE *in_file;
571     int i,j,n,maxcol,start,stride,col,last,linel;
572     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
573     int Nrow, Ncol, Nnzero, Nentries;
574     int Nrhs, nvecs, rhsi;
575     int Rhsperline, Rhswidth, Rhsprec;
576     int Rhsflag;
577     char *ThisElement;
578     char Title[73], Key[9], Type[4], Rhstype[4];
579     char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
580     char line[BUFSIZ];
581 
582     if ((in_file = fopen( filename, "r")) == NULL) {
583       fprintf(stderr,"Error: Cannot open file: %s\n",filename);
584       return 0;
585      }
586 
587     readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs,
588                   Ptrfmt, Indfmt, Valfmt, Rhsfmt,
589                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
590 
591     if (Nrhs <= 0)
592     {
593       fprintf(stderr, "Warn: Attempt to read auxillary vector(s) when none are present.\n");
594       return 0;
595     }
596     if (Rhstype[0] != 'F' )
597     {
598       fprintf(stderr,"Warn: Attempt to read auxillary vector(s) which are not stored in Full form.\n");
599       fprintf(stderr,"       Rhs must be specified as full. \n");
600       return 0;
601     }
602 
603 /* If reading complex data, allow for interleaved real and imaginary values. */
604     if ( Type[0] == 'C' ) {
605        Nentries = 2*Nrow;
606      } else {
607        Nentries = Nrow;
608     }
609 
610     nvecs = 1;
611 
612     if ( Rhstype[1] == 'G' ) nvecs++;
613     if ( Rhstype[2] == 'X' ) nvecs++;
614 
615     if ( AuxType == 'G' && Rhstype[1] != 'G' ) {
616       fprintf(stderr, "Warn: Attempt to read auxillary Guess vector(s) when none are present.\n");
617       return 0;
618     }
619     if ( AuxType == 'X' && Rhstype[2] != 'X' ) {
620       fprintf(stderr, "Warn: Attempt to read auxillary eXact solution vector(s) when none are present.\n");
621       return 0;
622     }
623 
624     ParseRfmt(Rhsfmt, &Rhsperline, &Rhswidth, &Rhsprec,&Rhsflag);
625     maxcol = Rhsperline*Rhswidth;
626 
627 /*  Lines to skip before starting to read RHS values... */
628     n = Ptrcrd + Indcrd + Valcrd;
629 
630     for (i = 0; i < n; i++)
631       fgets(line, BUFSIZ, in_file);
632 
633 /*  start  - number of initial aux vector entries to skip   */
634 /*           to reach first  vector requested               */
635 /*  stride - number of aux vector entries to skip between   */
636 /*           requested vectors                              */
637     if ( AuxType == 'F' ) start = 0;
638     else if ( AuxType == 'G' ) start = Nentries;
639     else start = (nvecs-1)*Nentries;
640     stride = (nvecs-1)*Nentries;
641 
642     fgets(line, BUFSIZ, in_file);
643     linel= strchr(line,'\n')-line;
644     col = 0;
645 /*  Skip to initial offset */
646 
647     for (i=0;i<start;i++) {
648        if ( col >=  ( maxcol<linel?maxcol:linel ) ) {
649            fgets(line, BUFSIZ, in_file);
650            linel= strchr(line,'\n')-line;
651            col = 0;
652        }
653        col += Rhswidth;
654     }
655     if (Rhsflag == 'D')  {
656        while( strchr(line,'D') ) *strchr(line,'D') = 'E';
657     }
658 
659 /*  Read a vector of desired type, then skip to next */
660 /*  repeating to fill Nrhs vectors                   */
661 
662   ThisElement = (char *) malloc(Rhswidth+1);
663   if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
664   *(ThisElement+Rhswidth) = (char) NULL;
665   for (rhsi=0;rhsi<Nrhs;rhsi++) {
666 
667     for (i=0;i<Nentries;i++) {
668        if ( col >= ( maxcol<linel?maxcol:linel ) ) {
669            fgets(line, BUFSIZ, in_file);
670            linel= strchr(line,'\n')-line;
671            if (Rhsflag == 'D')  {
672               while( strchr(line,'D') ) *strchr(line,'D') = 'E';
673            }
674            col = 0;
675        }
676        strncpy(ThisElement,line+col,Rhswidth);
677        /*ThisElement = substr(line, col, Rhswidth);*/
678           if ( Rhsflag != 'F' && strchr(ThisElement,'E') == NULL ) {
679              /* insert a char prefix for exp */
680              last = strlen(ThisElement);
681              for (j=last+1;j>=0;j--) {
682                 ThisElement[j] = ThisElement[j-1];
683                 if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) {
684                    ThisElement[j-1] = Rhsflag;
685                    break;
686                 }
687              }
688           }
689        b[i] = atof(ThisElement);
690        col += Rhswidth;
691     }
692 
693 /*  Skip any interleaved Guess/eXact vectors */
694 
695     for (i=0;i<stride;i++) {
696        if ( col >= ( maxcol<linel?maxcol:linel ) ) {
697            fgets(line, BUFSIZ, in_file);
698            linel= strchr(line,'\n')-line;
699            col = 0;
700        }
701        col += Rhswidth;
702     }
703 
704   }
705   free(ThisElement);
706 
707 
708     fclose(in_file);
709     return Nrhs;
710 }
711 
readHB_newaux_double(const char * filename,const char AuxType,double ** b)712 int readHB_newaux_double(const char* filename, const char AuxType, double** b)
713 {
714         int Nrhs,M,N,nonzeros;
715         char *Type;
716 
717         readHB_info(filename, &M, &N, &nonzeros, &Type, &Nrhs);
718         if ( Nrhs <= 0 ) {
719           fprintf(stderr,"Warn: Requested read of aux vector(s) when none are present.\n");
720           return 0;
721         } else {
722           if ( Type[0] == 'C' ) {
723             fprintf(stderr, "Warning: Reading complex aux vector(s) from HB file %s.",filename);
724             fprintf(stderr, "         Real and imaginary parts will be interlaced in b[].");
725             *b = (double *)malloc(M*Nrhs*sizeof(double)*2);
726             if ( *b == NULL ) IOHBTerminate("Insufficient memory for rhs.\n");
727             return readHB_aux_double(filename, AuxType, *b);
728           } else {
729             *b = (double *)malloc(M*Nrhs*sizeof(double));
730             if ( *b == NULL ) IOHBTerminate("Insufficient memory for rhs.\n");
731             return readHB_aux_double(filename, AuxType, *b);
732           }
733         }
734 }
735 
writeHB_mat_double(const char * filename,int M,int N,int nz,const int colptr[],const int rowind[],const double val[],int Nrhs,const double rhs[],const double guess[],const double exact[],const char * Title,const char * Key,const char * Type,char * Ptrfmt,char * Indfmt,char * Valfmt,char * Rhsfmt,const char * Rhstype)736 int writeHB_mat_double(const char* filename, int M, int N,
737                         int nz, const int colptr[], const int rowind[],
738                         const double val[], int Nrhs, const double rhs[],
739                         const double guess[], const double exact[],
740                         const char* Title, const char* Key, const char* Type,
741                         char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
742                         const char* Rhstype)
743 {
744 /****************************************************************************/
745 /*  The writeHB function opens the named file and writes the specified      */
746 /*  matrix and optional right-hand-side(s) to that file in Harwell-Boeing   */
747 /*  format.                                                                 */
748 /*                                                                          */
749 /*  For a description of the Harwell Boeing standard, see:                  */
750 /*            Duff, et al.,  ACM TOMS Vol.15, No.1, March 1989              */
751 /*                                                                          */
752 /****************************************************************************/
753     FILE *out_file;
754     int i,j,entry,offset,acount,linemod;
755     int totcrd, ptrcrd, indcrd, valcrd, rhscrd;
756     int nvalentries, nrhsentries;
757     int Ptrperline, Ptrwidth, Indperline, Indwidth;
758     int Rhsperline, Rhswidth, Rhsprec;
759     int Rhsflag;
760     int Valperline, Valwidth, Valprec;
761     int Valflag;           /* Indicates 'E','D', or 'F' float format */
762     char pformat[16],iformat[16],vformat[19],rformat[19];
763 
764     if ( Type[0] == 'C' ) {
765          nvalentries = 2*nz;
766          nrhsentries = 2*M;
767     } else {
768          nvalentries = nz;
769          nrhsentries = M;
770     }
771 
772     if ( filename != NULL ) {
773        if ( (out_file = fopen( filename, "w")) == NULL ) {
774          fprintf(stderr,"Error: Cannot open file: %s\n",filename);
775          return 0;
776        }
777     } else out_file = stdout;
778 
779     if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
780     ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
781     sprintf(pformat,"%%%dd",Ptrwidth);
782     ptrcrd = (N+1)/Ptrperline;
783     if ( (N+1)%Ptrperline != 0) ptrcrd++;
784 
785     if ( Indfmt == NULL ) Indfmt =  Ptrfmt;
786     ParseIfmt(Indfmt,&Indperline,&Indwidth);
787     sprintf(iformat,"%%%dd",Indwidth);
788     indcrd = nz/Indperline;
789     if ( nz%Indperline != 0) indcrd++;
790 
791     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
792       if ( Valfmt == NULL ) Valfmt = "(4E20.13)";
793       ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
794       if (Valflag == 'D') *strchr(Valfmt,'D') = 'E';
795       if (Valflag == 'F')
796          sprintf(vformat,"%% %d.%df",Valwidth,Valprec);
797       else
798          sprintf(vformat,"%% %d.%dE",Valwidth,Valprec);
799       valcrd = nvalentries/Valperline;
800       if ( nvalentries%Valperline != 0) valcrd++;
801     } else valcrd = 0;
802 
803     if ( Nrhs > 0 ) {
804        if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
805        ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
806        if (Rhsflag == 'F')
807           sprintf(rformat,"%% %d.%df",Rhswidth,Rhsprec);
808        else
809           sprintf(rformat,"%% %d.%dE",Rhswidth,Rhsprec);
810        if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E';
811        rhscrd = nrhsentries/Rhsperline;
812        if ( nrhsentries%Rhsperline != 0) rhscrd++;
813        if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
814        if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
815        rhscrd*=Nrhs;
816     } else rhscrd = 0;
817 
818     totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
819 
820 
821 /*  Print header information:  */
822 
823     fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
824             ptrcrd, indcrd, valcrd, rhscrd);
825     fprintf(out_file,"%3s%11s%14d%14d%14d\n",Type,"          ", M, N, nz);
826     fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt);
827     if ( Nrhs != 0 ) {
828 /*     Print Rhsfmt on fourth line and                                    */
829 /*           optional fifth header line for auxillary vector information: */
830        fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs);
831     } else fprintf(out_file,"\n");
832 
833     offset = 1-_SP_base;  /* if base 0 storage is declared (via macro definition), */
834                           /* then storage entries are offset by 1                  */
835 
836 /*  Print column pointers:   */
837     for (i=0;i<N+1;i++)
838     {
839        entry = colptr[i]+offset;
840        fprintf(out_file,pformat,entry);
841        if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
842     }
843 
844    if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
845 
846 /*  Print row indices:       */
847     for (i=0;i<nz;i++)
848     {
849        entry = rowind[i]+offset;
850        fprintf(out_file,iformat,entry);
851        if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
852     }
853 
854    if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
855 
856 /*  Print values:            */
857 
858     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
859 
860     for (i=0;i<nvalentries;i++)
861     {
862        fprintf(out_file,vformat,val[i]);
863        if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
864     }
865 
866     if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
867 
868 /*  If available,  print right hand sides,
869            guess vectors and exact solution vectors:  */
870     acount = 1;
871     linemod = 0;
872     if ( Nrhs > 0 ) {
873        for (i=0;i<Nrhs;i++)
874        {
875           for ( j=0;j<nrhsentries;j++ ) {
876             fprintf(out_file,rformat,rhs[j]);
877             if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
878           }
879           if ( acount%Rhsperline != linemod ) {
880             fprintf(out_file,"\n");
881             linemod = (acount-1)%Rhsperline;
882           }
883           rhs += nrhsentries;
884           if ( Rhstype[1] == 'G' ) {
885             for ( j=0;j<nrhsentries;j++ ) {
886               fprintf(out_file,rformat,guess[j]);
887               if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
888             }
889             if ( acount%Rhsperline != linemod ) {
890               fprintf(out_file,"\n");
891               linemod = (acount-1)%Rhsperline;
892             }
893             guess += nrhsentries;
894           }
895           if ( Rhstype[2] == 'X' ) {
896             for ( j=0;j<nrhsentries;j++ ) {
897               fprintf(out_file,rformat,exact[j]);
898               if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
899             }
900             if ( acount%Rhsperline != linemod ) {
901               fprintf(out_file,"\n");
902               linemod = (acount-1)%Rhsperline;
903             }
904             exact += nrhsentries;
905           }
906        }
907     }
908 
909     }
910 
911     if ( fclose(out_file) != 0){
912       fprintf(stderr,"Error closing file in writeHB_mat_double().\n");
913       return 0;
914     } else return 1;
915 
916 }
917 
readHB_mat_char(const char * filename,int colptr[],int rowind[],char val[],char * Valfmt)918 int readHB_mat_char(const char* filename, int colptr[], int rowind[],
919                                            char val[], char* Valfmt)
920 {
921 /****************************************************************************/
922 /*  This function opens and reads the specified file, interpreting its      */
923 /*  contents as a sparse matrix stored in the Harwell/Boeing standard       */
924 /*  format and creating compressed column storage scheme vectors to hold    */
925 /*  the index and nonzero value information.                                */
926 /*                                                                          */
927 /*    ----------                                                            */
928 /*    **CAVEAT**                                                            */
929 /*    ----------                                                            */
930 /*  Parsing real formats from Fortran is tricky, and this file reader       */
931 /*  does not claim to be foolproof.   It has been tested for cases when     */
932 /*  the real values are printed consistently and evenly spaced on each      */
933 /*  line, with Fixed (F), and Exponential (E or D) formats.                 */
934 /*                                                                          */
935 /*  **  If the input file does not adhere to the H/B format, the  **        */
936 /*  **             results will be unpredictable.                 **        */
937 /*                                                                          */
938 /****************************************************************************/
939     FILE *in_file;
940     int i,j,ind,col,offset,count,last;
941     int Nrow,Ncol,Nnzero,Nentries,Nrhs;
942     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
943     int Ptrperline, Ptrwidth, Indperline, Indwidth;
944     int Valperline, Valwidth, Valprec;
945     int Valflag;           /* Indicates 'E','D', or 'F' float format */
946     char* ThisElement;
947     char line[BUFSIZ];
948     char Title[73], Key[8], Type[4], Rhstype[4];
949     char Ptrfmt[17], Indfmt[17], Rhsfmt[21];
950 
951     if ( (in_file = fopen( filename, "r")) == NULL ) {
952        fprintf(stderr,"Error: Cannot open file: %s\n",filename);
953        return 0;
954     }
955 
956     readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs,
957                   Ptrfmt, Indfmt, Valfmt, Rhsfmt,
958                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
959 
960 /*  Parse the array input formats from Line 3 of HB file  */
961     ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
962     ParseIfmt(Indfmt,&Indperline,&Indwidth);
963     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
964        ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
965        if (Valflag == 'D') {
966           *strchr(Valfmt,'D') = 'E';
967        }
968     }
969 
970 /*  Read column pointer array:   */
971 
972     offset = 1-_SP_base;  /* if base 0 storage is declared (via macro definition), */
973                           /* then storage entries are offset by 1                  */
974 
975     ThisElement = (char *) malloc(Ptrwidth+1);
976     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
977     *(ThisElement+Ptrwidth) = (char) NULL;
978     count=0;
979     for (i=0;i<Ptrcrd;i++)
980     {
981        fgets(line, BUFSIZ, in_file);
982        if ( sscanf(line,"%*s") < 0 )
983          IOHBTerminate("iohb.c: Null (or blank) line in pointer data region of HB file.\n");
984        col =  0;
985        for (ind = 0;ind<Ptrperline;ind++)
986        {
987           if (count > Ncol) break;
988           strncpy(ThisElement,line+col,Ptrwidth);
989           /*ThisElement = substr(line,col,Ptrwidth);*/
990           colptr[count] = atoi(ThisElement)-offset;
991           count++; col += Ptrwidth;
992        }
993     }
994     free(ThisElement);
995 
996 /*  Read row index array:  */
997 
998     ThisElement = (char *) malloc(Indwidth+1);
999     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
1000     *(ThisElement+Indwidth) = (char) NULL;
1001     count = 0;
1002     for (i=0;i<Indcrd;i++)
1003     {
1004        fgets(line, BUFSIZ, in_file);
1005        if ( sscanf(line,"%*s") < 0 )
1006          IOHBTerminate("iohb.c: Null (or blank) line in index data region of HB file.\n");
1007        col =  0;
1008        for (ind = 0;ind<Indperline;ind++)
1009        {
1010           if (count == Nnzero) break;
1011           strncpy(ThisElement,line+col,Indwidth);
1012           /*ThisElement = substr(line,col,Indwidth);*/
1013           rowind[count] = atoi(ThisElement)-offset;
1014           count++; col += Indwidth;
1015        }
1016     }
1017     free(ThisElement);
1018 
1019 /*  Read array of values:  AS CHARACTERS*/
1020 
1021     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
1022 
1023        if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
1024            else Nentries = Nnzero;
1025 
1026     ThisElement = (char *) malloc(Valwidth+1);
1027     if ( ThisElement == NULL ) IOHBTerminate("Insufficient memory for ThisElement.");
1028     *(ThisElement+Valwidth) = (char) NULL;
1029     count = 0;
1030     for (i=0;i<Valcrd;i++)
1031     {
1032        fgets(line, BUFSIZ, in_file);
1033        if ( sscanf(line,"%*s") < 0 )
1034          IOHBTerminate("iohb.c: Null (or blank) line in value data region of HB file.\n");
1035        if (Valflag == 'D') {
1036           while( strchr(line,'D') ) *strchr(line,'D') = 'E';
1037        }
1038        col =  0;
1039        for (ind = 0;ind<Valperline;ind++)
1040        {
1041           if (count == Nentries) break;
1042           ThisElement = &val[count*Valwidth];
1043           strncpy(ThisElement,line+col,Valwidth);
1044           /*strncpy(ThisElement,substr(line,col,Valwidth),Valwidth);*/
1045           if ( Valflag != 'F' && strchr(ThisElement,'E') == NULL ) {
1046              /* insert a char prefix for exp */
1047              last = strlen(ThisElement);
1048              for (j=last+1;j>=0;j--) {
1049                 ThisElement[j] = ThisElement[j-1];
1050                 if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) {
1051                    ThisElement[j-1] = Valflag;
1052                    break;
1053                 }
1054              }
1055           }
1056           count++; col += Valwidth;
1057        }
1058     }
1059     }
1060 
1061     return 1;
1062 }
1063 
readHB_newmat_char(const char * filename,int * M,int * N,int * nonzeros,int ** colptr,int ** rowind,char ** val,char ** Valfmt)1064 int readHB_newmat_char(const char* filename, int* M, int* N, int* nonzeros, int** colptr,
1065                           int** rowind, char** val, char** Valfmt)
1066 {
1067     FILE *in_file;
1068     int Nrhs;
1069     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
1070     int Valperline, Valwidth, Valprec;
1071     int Valflag;           /* Indicates 'E','D', or 'F' float format */
1072     char Title[73], Key[9], Type[4], Rhstype[4];
1073     char Ptrfmt[17], Indfmt[17], Rhsfmt[21];
1074 
1075     if ((in_file = fopen( filename, "r")) == NULL) {
1076       fprintf(stderr,"Error: Cannot open file: %s\n",filename);
1077       return 0;
1078      }
1079 
1080     *Valfmt = (char *)malloc(21*sizeof(char));
1081     if ( *Valfmt == NULL ) IOHBTerminate("Insufficient memory for Valfmt.");
1082     readHB_header(in_file, Title, Key, Type, M, N, nonzeros, &Nrhs,
1083                   Ptrfmt, Indfmt, (*Valfmt), Rhsfmt,
1084                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
1085     fclose(in_file);
1086     ParseRfmt(*Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
1087 
1088         *colptr = (int *)malloc((*N+1)*sizeof(int));
1089         if ( *colptr == NULL ) IOHBTerminate("Insufficient memory for colptr.\n");
1090         *rowind = (int *)malloc(*nonzeros*sizeof(int));
1091         if ( *rowind == NULL ) IOHBTerminate("Insufficient memory for rowind.\n");
1092         if ( Type[0] == 'C' ) {
1093 /*
1094    fprintf(stderr, "Warning: Reading complex data from HB file %s.\n",filename);
1095    fprintf(stderr, "         Real and imaginary parts will be interlaced in val[].\n");
1096 */
1097            /* Malloc enough space for real AND imaginary parts of val[] */
1098            *val = (char *)malloc(*nonzeros*Valwidth*sizeof(char)*2);
1099            if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n");
1100         } else {
1101            if ( Type[0] != 'P' ) {
1102              /* Malloc enough space for real array val[] */
1103              *val = (char *)malloc(*nonzeros*Valwidth*sizeof(char));
1104              if ( *val == NULL ) IOHBTerminate("Insufficient memory for val.\n");
1105            }
1106         }  /* No val[] space needed if pattern only */
1107         return readHB_mat_char(filename, *colptr, *rowind, *val, *Valfmt);
1108 
1109 }
1110 
readHB_aux_char(const char * filename,const char AuxType,char b[])1111 int readHB_aux_char(const char* filename, const char AuxType, char b[])
1112 {
1113 /****************************************************************************/
1114 /*  This function opens and reads the specified file, placing auxilary      */
1115 /*  vector(s) of the given type (if available) in b :                       */
1116 /*  Return value is the number of vectors successfully read.                */
1117 /*                                                                          */
1118 /*                AuxType = 'F'   full right-hand-side vector(s)            */
1119 /*                AuxType = 'G'   initial Guess vector(s)                   */
1120 /*                AuxType = 'X'   eXact solution vector(s)                  */
1121 /*                                                                          */
1122 /*    ----------                                                            */
1123 /*    **CAVEAT**                                                            */
1124 /*    ----------                                                            */
1125 /*  Parsing real formats from Fortran is tricky, and this file reader       */
1126 /*  does not claim to be foolproof.   It has been tested for cases when     */
1127 /*  the real values are printed consistently and evenly spaced on each      */
1128 /*  line, with Fixed (F), and Exponential (E or D) formats.                 */
1129 /*                                                                          */
1130 /*  **  If the input file does not adhere to the H/B format, the  **        */
1131 /*  **             results will be unpredictable.                 **        */
1132 /*                                                                          */
1133 /****************************************************************************/
1134     FILE *in_file;
1135     int i,j,n,maxcol,start,stride,col,last,linel,nvecs,rhsi;
1136     int Nrow, Ncol, Nnzero, Nentries,Nrhs;
1137     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
1138     int Rhsperline, Rhswidth, Rhsprec;
1139     int Rhsflag;
1140     char Title[73], Key[9], Type[4], Rhstype[4];
1141     char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
1142     char line[BUFSIZ];
1143     char *ThisElement;
1144 
1145     if ((in_file = fopen( filename, "r")) == NULL) {
1146       fprintf(stderr,"Error: Cannot open file: %s\n",filename);
1147       return 0;
1148      }
1149 
1150     readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs,
1151                   Ptrfmt, Indfmt, Valfmt, Rhsfmt,
1152                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
1153 
1154     if (Nrhs <= 0)
1155     {
1156       fprintf(stderr, "Warn: Attempt to read auxillary vector(s) when none are present.\n");
1157       return 0;
1158     }
1159     if (Rhstype[0] != 'F' )
1160     {
1161       fprintf(stderr,"Warn: Attempt to read auxillary vector(s) which are not stored in Full form.\n");
1162       fprintf(stderr,"       Rhs must be specified as full. \n");
1163       return 0;
1164     }
1165 
1166 /* If reading complex data, allow for interleaved real and imaginary values. */
1167     if ( Type[0] == 'C' ) {
1168        Nentries = 2*Nrow;
1169      } else {
1170        Nentries = Nrow;
1171     }
1172 
1173     nvecs = 1;
1174 
1175     if ( Rhstype[1] == 'G' ) nvecs++;
1176     if ( Rhstype[2] == 'X' ) nvecs++;
1177 
1178     if ( AuxType == 'G' && Rhstype[1] != 'G' ) {
1179       fprintf(stderr, "Warn: Attempt to read auxillary Guess vector(s) when none are present.\n");
1180       return 0;
1181     }
1182     if ( AuxType == 'X' && Rhstype[2] != 'X' ) {
1183       fprintf(stderr, "Warn: Attempt to read auxillary eXact solution vector(s) when none are present.\n");
1184       return 0;
1185     }
1186 
1187     ParseRfmt(Rhsfmt, &Rhsperline, &Rhswidth, &Rhsprec,&Rhsflag);
1188     maxcol = Rhsperline*Rhswidth;
1189 
1190 /*  Lines to skip before starting to read RHS values... */
1191     n = Ptrcrd + Indcrd + Valcrd;
1192 
1193     for (i = 0; i < n; i++)
1194       fgets(line, BUFSIZ, in_file);
1195 
1196 /*  start  - number of initial aux vector entries to skip   */
1197 /*           to reach first  vector requested               */
1198 /*  stride - number of aux vector entries to skip between   */
1199 /*           requested vectors                              */
1200     if ( AuxType == 'F' ) start = 0;
1201     else if ( AuxType == 'G' ) start = Nentries;
1202     else start = (nvecs-1)*Nentries;
1203     stride = (nvecs-1)*Nentries;
1204 
1205     fgets(line, BUFSIZ, in_file);
1206     linel= strchr(line,'\n')-line;
1207     if ( sscanf(line,"%*s") < 0 )
1208        IOHBTerminate("iohb.c: Null (or blank) line in auxillary vector data region of HB file.\n");
1209     col = 0;
1210 /*  Skip to initial offset */
1211 
1212     for (i=0;i<start;i++) {
1213        col += Rhswidth;
1214        if ( col >= ( maxcol<linel?maxcol:linel ) ) {
1215            fgets(line, BUFSIZ, in_file);
1216            linel= strchr(line,'\n')-line;
1217        if ( sscanf(line,"%*s") < 0 )
1218        IOHBTerminate("iohb.c: Null (or blank) line in auxillary vector data region of HB file.\n");
1219            col = 0;
1220        }
1221     }
1222 
1223     if (Rhsflag == 'D')  {
1224       while( strchr(line,'D') ) *strchr(line,'D') = 'E';
1225     }
1226 /*  Read a vector of desired type, then skip to next */
1227 /*  repeating to fill Nrhs vectors                   */
1228 
1229   for (rhsi=0;rhsi<Nrhs;rhsi++) {
1230 
1231     for (i=0;i<Nentries;i++) {
1232        if ( col >= ( maxcol<linel?maxcol:linel ) ) {
1233            fgets(line, BUFSIZ, in_file);
1234            linel= strchr(line,'\n')-line;
1235        if ( sscanf(line,"%*s") < 0 )
1236        IOHBTerminate("iohb.c: Null (or blank) line in auxillary vector data region of HB file.\n");
1237            if (Rhsflag == 'D')  {
1238               while( strchr(line,'D') ) *strchr(line,'D') = 'E';
1239            }
1240            col = 0;
1241        }
1242        ThisElement = &b[i*Rhswidth];
1243        strncpy(ThisElement,line+col,Rhswidth);
1244           if ( Rhsflag != 'F' && strchr(ThisElement,'E') == NULL ) {
1245              /* insert a char prefix for exp */
1246              last = strlen(ThisElement);
1247              for (j=last+1;j>=0;j--) {
1248                 ThisElement[j] = ThisElement[j-1];
1249                 if ( ThisElement[j] == '+' || ThisElement[j] == '-' ) {
1250                    ThisElement[j-1] = Rhsflag;
1251                    break;
1252                 }
1253              }
1254           }
1255        col += Rhswidth;
1256     }
1257     b+=Nentries*Rhswidth;
1258 
1259 /*  Skip any interleaved Guess/eXact vectors */
1260 
1261     for (i=0;i<stride;i++) {
1262        col += Rhswidth;
1263        if ( col >= ( maxcol<linel?maxcol:linel ) ) {
1264            fgets(line, BUFSIZ, in_file);
1265            linel= strchr(line,'\n')-line;
1266        if ( sscanf(line,"%*s") < 0 )
1267        IOHBTerminate("iohb.c: Null (or blank) line in auxillary vector data region of HB file.\n");
1268            col = 0;
1269        }
1270     }
1271 
1272   }
1273 
1274 
1275     fclose(in_file);
1276     return Nrhs;
1277 }
1278 
readHB_newaux_char(const char * filename,const char AuxType,char ** b,char ** Rhsfmt)1279 int readHB_newaux_char(const char* filename, const char AuxType, char** b, char** Rhsfmt)
1280 {
1281     FILE *in_file;
1282     int Ptrcrd, Indcrd, Valcrd, Rhscrd;
1283     int Nrow,Ncol,Nnzero,Nrhs;
1284     int Rhsperline, Rhswidth, Rhsprec;
1285     int Rhsflag;
1286     char Title[73], Key[9], Type[4], Rhstype[4];
1287     char Ptrfmt[17], Indfmt[17], Valfmt[21];
1288 
1289     if ((in_file = fopen( filename, "r")) == NULL) {
1290       fprintf(stderr,"Error: Cannot open file: %s\n",filename);
1291       return 0;
1292      }
1293 
1294     *Rhsfmt = (char *)malloc(21*sizeof(char));
1295     if ( *Rhsfmt == NULL ) IOHBTerminate("Insufficient memory for Rhsfmt.");
1296     readHB_header(in_file, Title, Key, Type, &Nrow, &Ncol, &Nnzero, &Nrhs,
1297                   Ptrfmt, Indfmt, Valfmt, (*Rhsfmt),
1298                   &Ptrcrd, &Indcrd, &Valcrd, &Rhscrd, Rhstype);
1299      fclose(in_file);
1300         if ( Nrhs == 0 ) {
1301           fprintf(stderr,"Warn: Requested read of aux vector(s) when none are present.\n");
1302           return 0;
1303         } else {
1304           ParseRfmt(*Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec,&Rhsflag);
1305           if ( Type[0] == 'C' ) {
1306             fprintf(stderr, "Warning: Reading complex aux vector(s) from HB file %s.",filename);
1307             fprintf(stderr, "         Real and imaginary parts will be interlaced in b[].");
1308             *b = (char *)malloc(Nrow*Nrhs*Rhswidth*sizeof(char)*2);
1309             if ( *b == NULL ) IOHBTerminate("Insufficient memory for rhs.\n");
1310             return readHB_aux_char(filename, AuxType, *b);
1311           } else {
1312             *b = (char *)malloc(Nrow*Nrhs*Rhswidth*sizeof(char));
1313             if ( *b == NULL ) IOHBTerminate("Insufficient memory for rhs.\n");
1314             return readHB_aux_char(filename, AuxType, *b);
1315           }
1316         }
1317 }
1318 
writeHB_mat_char(const char * filename,int M,int N,int nz,const int colptr[],const int rowind[],const char val[],int Nrhs,const char rhs[],const char guess[],const char exact[],const char * Title,const char * Key,const char * Type,char * Ptrfmt,char * Indfmt,char * Valfmt,char * Rhsfmt,const char * Rhstype)1319 int writeHB_mat_char(const char* filename, int M, int N,
1320                         int nz, const int colptr[], const int rowind[],
1321                         const char val[], int Nrhs, const char rhs[],
1322                         const char guess[], const char exact[],
1323                         const char* Title, const char* Key, const char* Type,
1324                         char* Ptrfmt, char* Indfmt, char* Valfmt, char* Rhsfmt,
1325                         const char* Rhstype)
1326 {
1327 /****************************************************************************/
1328 /*  The writeHB function opens the named file and writes the specified      */
1329 /*  matrix and optional right-hand-side(s) to that file in Harwell-Boeing   */
1330 /*  format.                                                                 */
1331 /*                                                                          */
1332 /*  For a description of the Harwell Boeing standard, see:                  */
1333 /*            Duff, et al.,  ACM TOMS Vol.15, No.1, March 1989              */
1334 /*                                                                          */
1335 /****************************************************************************/
1336     FILE *out_file;
1337     int i,j,acount,linemod,entry,offset;
1338     int totcrd, ptrcrd, indcrd, valcrd, rhscrd;
1339     int nvalentries, nrhsentries;
1340     int Ptrperline, Ptrwidth, Indperline, Indwidth;
1341     int Rhsperline, Rhswidth, Rhsprec;
1342     int Rhsflag;
1343     int Valperline = 1, Valwidth, Valprec;
1344     int Valflag;           /* Indicates 'E','D', or 'F' float format */
1345     char pformat[16],iformat[16],vformat[19],rformat[19];
1346 
1347     if ( Type[0] == 'C' ) {
1348          nvalentries = 2*nz;
1349          nrhsentries = 2*M;
1350     } else {
1351          nvalentries = nz;
1352          nrhsentries = M;
1353     }
1354 
1355     if ( filename != NULL ) {
1356        if ( (out_file = fopen( filename, "w")) == NULL ) {
1357          fprintf(stderr,"Error: Cannot open file: %s\n",filename);
1358          return 0;
1359        }
1360     } else out_file = stdout;
1361 
1362     if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
1363     ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
1364     sprintf(pformat,"%%%dd",Ptrwidth);
1365 
1366     if ( Indfmt == NULL ) Indfmt =  Ptrfmt;
1367     ParseIfmt(Indfmt,&Indperline,&Indwidth);
1368     sprintf(iformat,"%%%dd",Indwidth);
1369 
1370     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
1371       if ( Valfmt == NULL ) Valfmt = "(4E20.13)";
1372       ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
1373       sprintf(vformat,"%%%ds",Valwidth);
1374     }
1375 
1376     ptrcrd = (N+1)/Ptrperline;
1377     if ( (N+1)%Ptrperline != 0) ptrcrd++;
1378 
1379     indcrd = nz/Indperline;
1380     if ( nz%Indperline != 0) indcrd++;
1381 
1382     valcrd = nvalentries/Valperline;
1383     if ( nvalentries%Valperline != 0) valcrd++;
1384 
1385     if ( Nrhs > 0 ) {
1386        if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
1387        ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
1388        sprintf(rformat,"%%%ds",Rhswidth);
1389        rhscrd = nrhsentries/Rhsperline;
1390        if ( nrhsentries%Rhsperline != 0) rhscrd++;
1391        if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
1392        if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
1393        rhscrd*=Nrhs;
1394     } else rhscrd = 0;
1395 
1396     totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
1397 
1398 
1399 /*  Print header information:  */
1400 
1401     fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
1402             ptrcrd, indcrd, valcrd, rhscrd);
1403     fprintf(out_file,"%3s%11s%14d%14d%14d\n",Type,"          ", M, N, nz);
1404     fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt);
1405     if ( Nrhs != 0 ) {
1406 /*     Print Rhsfmt on fourth line and                                    */
1407 /*           optional fifth header line for auxillary vector information: */
1408        fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs);
1409     } else fprintf(out_file,"\n");
1410 
1411     offset = 1-_SP_base;  /* if base 0 storage is declared (via macro definition), */
1412                           /* then storage entries are offset by 1                  */
1413 
1414 /*  Print column pointers:   */
1415     for (i=0;i<N+1;i++)
1416     {
1417        entry = colptr[i]+offset;
1418        fprintf(out_file,pformat,entry);
1419        if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
1420     }
1421 
1422    if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
1423 
1424 /*  Print row indices:       */
1425     for (i=0;i<nz;i++)
1426     {
1427        entry = rowind[i]+offset;
1428        fprintf(out_file,iformat,entry);
1429        if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
1430     }
1431 
1432    if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
1433 
1434 /*  Print values:            */
1435 
1436     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
1437     for (i=0;i<nvalentries;i++)
1438     {
1439        fprintf(out_file,vformat,val+i*Valwidth);
1440        if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
1441     }
1442 
1443     if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
1444 
1445 /*  Print right hand sides:  */
1446     acount = 1;
1447     linemod=0;
1448     if ( Nrhs > 0 ) {
1449       for (j=0;j<Nrhs;j++) {
1450        for (i=0;i<nrhsentries;i++)
1451        {
1452           fprintf(out_file,rformat,rhs+i*Rhswidth);
1453           if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
1454        }
1455        if ( acount%Rhsperline != linemod ) {
1456           fprintf(out_file,"\n");
1457           linemod = (acount-1)%Rhsperline;
1458        }
1459        if ( Rhstype[1] == 'G' ) {
1460          for (i=0;i<nrhsentries;i++)
1461          {
1462            fprintf(out_file,rformat,guess+i*Rhswidth);
1463            if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
1464          }
1465          if ( acount%Rhsperline != linemod ) {
1466             fprintf(out_file,"\n");
1467             linemod = (acount-1)%Rhsperline;
1468          }
1469        }
1470        if ( Rhstype[2] == 'X' ) {
1471          for (i=0;i<nrhsentries;i++)
1472          {
1473            fprintf(out_file,rformat,exact+i*Rhswidth);
1474            if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
1475          }
1476          if ( acount%Rhsperline != linemod ) {
1477             fprintf(out_file,"\n");
1478             linemod = (acount-1)%Rhsperline;
1479          }
1480        }
1481       }
1482     }
1483 
1484     }
1485 
1486     if ( fclose(out_file) != 0){
1487       fprintf(stderr,"Error closing file in writeHB_mat_char().\n");
1488       return 0;
1489     } else return 1;
1490 
1491 }
1492 
ParseIfmt(char * fmt,int * perline,int * width)1493 int ParseIfmt(char* fmt, int* perline, int* width)
1494 {
1495 /*************************************************/
1496 /*  Parse an *integer* format field to determine */
1497 /*  width and number of elements per line.       */
1498 /*************************************************/
1499     char *tmp;
1500     if (fmt == NULL ) {
1501       *perline = 0; *width = 0; return 0;
1502     }
1503     upcase(fmt);
1504     tmp = strchr(fmt,'(');
1505     tmp = substr(fmt,tmp - fmt + 1, strchr(fmt,'I') - tmp - 1);
1506     *perline = atoi(tmp);
1507     tmp = strchr(fmt,'I');
1508     tmp = substr(fmt,tmp - fmt + 1, strchr(fmt,')') - tmp - 1);
1509     return *width = atoi(tmp);
1510 }
1511 
ParseRfmt(char * fmt,int * perline,int * width,int * prec,int * flag)1512 int ParseRfmt(char* fmt, int* perline, int* width, int* prec, int* flag)
1513 {
1514 /*************************************************/
1515 /*  Parse a *real* format field to determine     */
1516 /*  width and number of elements per line.       */
1517 /*  Also sets flag indicating 'E' 'F' 'P' or 'D' */
1518 /*  format.                                      */
1519 /*************************************************/
1520     char* tmp;
1521     char* tmp2;
1522     char* tmp3;
1523     int len;
1524 
1525     if (fmt == NULL ) {
1526       *perline = 0;
1527       *width = 0;
1528       flag = NULL;
1529       return 0;
1530     }
1531 
1532     upcase(fmt);
1533     if (strchr(fmt,'(') != NULL)  fmt = strchr(fmt,'(');
1534     if (strchr(fmt,')') != NULL)  {
1535        tmp2 = strchr(fmt,')');
1536        while ( strchr(tmp2+1,')') != NULL ) {
1537           tmp2 = strchr(tmp2+1,')');
1538        }
1539        *(tmp2+1) = (int) NULL;
1540     }
1541     if (strchr(fmt,'P') != NULL)  /* Remove any scaling factor, which */
1542     {                             /* affects output only, not input */
1543       if (strchr(fmt,'(') != NULL) {
1544         tmp = strchr(fmt,'P');
1545         if ( *(++tmp) == ',' ) tmp++;
1546         tmp3 = strchr(fmt,'(')+1;
1547         len = tmp-tmp3;
1548         tmp2 = tmp3;
1549         while ( *(tmp2+len) != (int) NULL ) {
1550            *tmp2=*(tmp2+len);
1551            tmp2++;
1552         }
1553         *(strchr(fmt,')')+1) = (int) NULL;
1554       }
1555     }
1556     if (strchr(fmt,'E') != NULL) {
1557        *flag = 'E';
1558     } else if (strchr(fmt,'D') != NULL) {
1559        *flag = 'D';
1560     } else if (strchr(fmt,'F') != NULL) {
1561        *flag = 'F';
1562     } else {
1563       fprintf(stderr,"Real format %s in H/B file not supported.\n",fmt);
1564       return 0;
1565     }
1566     tmp = strchr(fmt,'(');
1567     tmp = substr(fmt,tmp - fmt + 1, strchr(fmt,*flag) - tmp - 1);
1568     *perline = atoi(tmp);
1569     tmp = strchr(fmt,*flag);
1570     if ( strchr(fmt,'.') ) {
1571       *prec = atoi( substr( fmt, strchr(fmt,'.') - fmt + 1, strchr(fmt,')') - strchr(fmt,'.')-1) );
1572       tmp = substr(fmt,tmp - fmt + 1, strchr(fmt,'.') - tmp - 1);
1573     } else {
1574       tmp = substr(fmt,tmp - fmt + 1, strchr(fmt,')') - tmp - 1);
1575     }
1576     return *width = atoi(tmp);
1577 }
1578 
substr(const char * S,const int pos,const int len)1579 char* substr(const char* S, const int pos, const int len)
1580 {
1581     int i;
1582     char *SubS;
1583     if ( pos+len <= strlen(S)) {
1584     SubS = (char *)malloc(len+1);
1585     if ( SubS == NULL ) IOHBTerminate("Insufficient memory for SubS.");
1586     for (i=0;i<len;i++) SubS[i] = S[pos+i];
1587     SubS[len] = (char) NULL;
1588     } else {
1589       SubS = NULL;
1590     }
1591     return SubS;
1592 }
1593 
1594 #include<ctype.h>
upcase(char * S)1595 void upcase(char* S)
1596 {
1597 /*  Convert S to uppercase     */
1598     int i,len;
1599     if ( S == NULL ) return;
1600     len = strlen(S);
1601     for (i=0;i< len;i++)
1602        S[i] = toupper(S[i]);
1603 }
1604 
IOHBTerminate(const char * message)1605 void IOHBTerminate(const char* message)
1606 {
1607    fprintf(stderr,"%s",message);
1608    exit(1);
1609 }
1610 
1611