alpar@1
|
1 |
/* glphbm.c */
|
alpar@1
|
2 |
|
alpar@1
|
3 |
/***********************************************************************
|
alpar@1
|
4 |
* This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@1
|
5 |
*
|
alpar@1
|
6 |
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@1
|
7 |
* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
|
alpar@1
|
8 |
* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@1
|
9 |
* E-mail: <mao@gnu.org>.
|
alpar@1
|
10 |
*
|
alpar@1
|
11 |
* GLPK is free software: you can redistribute it and/or modify it
|
alpar@1
|
12 |
* under the terms of the GNU General Public License as published by
|
alpar@1
|
13 |
* the Free Software Foundation, either version 3 of the License, or
|
alpar@1
|
14 |
* (at your option) any later version.
|
alpar@1
|
15 |
*
|
alpar@1
|
16 |
* GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@1
|
17 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@1
|
18 |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@1
|
19 |
* License for more details.
|
alpar@1
|
20 |
*
|
alpar@1
|
21 |
* You should have received a copy of the GNU General Public License
|
alpar@1
|
22 |
* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@1
|
23 |
***********************************************************************/
|
alpar@1
|
24 |
|
alpar@1
|
25 |
#define _GLPSTD_ERRNO
|
alpar@1
|
26 |
#define _GLPSTD_STDIO
|
alpar@1
|
27 |
#include "glphbm.h"
|
alpar@1
|
28 |
#include "glpenv.h"
|
alpar@1
|
29 |
|
alpar@1
|
30 |
/***********************************************************************
|
alpar@1
|
31 |
* NAME
|
alpar@1
|
32 |
*
|
alpar@1
|
33 |
* hbm_read_mat - read sparse matrix in Harwell-Boeing format
|
alpar@1
|
34 |
*
|
alpar@1
|
35 |
* SYNOPSIS
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* #include "glphbm.h"
|
alpar@1
|
38 |
* HBM *hbm_read_mat(const char *fname);
|
alpar@1
|
39 |
*
|
alpar@1
|
40 |
* DESCRIPTION
|
alpar@1
|
41 |
*
|
alpar@1
|
42 |
* The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
|
alpar@1
|
43 |
* format from a text file whose name is the character string fname.
|
alpar@1
|
44 |
*
|
alpar@1
|
45 |
* Detailed description of the Harwell-Boeing format recognised by this
|
alpar@1
|
46 |
* routine is given in the following report:
|
alpar@1
|
47 |
*
|
alpar@1
|
48 |
* I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
|
alpar@1
|
49 |
* Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
|
alpar@1
|
50 |
*
|
alpar@1
|
51 |
* RETURNS
|
alpar@1
|
52 |
*
|
alpar@1
|
53 |
* If no error occured, the routine hbm_read_mat returns a pointer to
|
alpar@1
|
54 |
* a data structure containing the matrix. In case of error the routine
|
alpar@1
|
55 |
* prints an appropriate error message and returns NULL. */
|
alpar@1
|
56 |
|
alpar@1
|
57 |
struct dsa
|
alpar@1
|
58 |
{ /* working area used by routine hbm_read_mat */
|
alpar@1
|
59 |
const char *fname;
|
alpar@1
|
60 |
/* name of input text file */
|
alpar@1
|
61 |
FILE *fp;
|
alpar@1
|
62 |
/* stream assigned to input text file */
|
alpar@1
|
63 |
int seqn;
|
alpar@1
|
64 |
/* card sequential number */
|
alpar@1
|
65 |
char card[80+1];
|
alpar@1
|
66 |
/* card image buffer */
|
alpar@1
|
67 |
int fmt_p;
|
alpar@1
|
68 |
/* scale factor */
|
alpar@1
|
69 |
int fmt_k;
|
alpar@1
|
70 |
/* iterator */
|
alpar@1
|
71 |
int fmt_f;
|
alpar@1
|
72 |
/* format code */
|
alpar@1
|
73 |
int fmt_w;
|
alpar@1
|
74 |
/* field width */
|
alpar@1
|
75 |
int fmt_d;
|
alpar@1
|
76 |
/* number of decimal places after point */
|
alpar@1
|
77 |
};
|
alpar@1
|
78 |
|
alpar@1
|
79 |
/***********************************************************************
|
alpar@1
|
80 |
* read_card - read next data card
|
alpar@1
|
81 |
*
|
alpar@1
|
82 |
* This routine reads the next 80-column card from the input text file
|
alpar@1
|
83 |
* and stores its image into the character string card. If the card was
|
alpar@1
|
84 |
* read successfully, the routine returns zero, otherwise non-zero. */
|
alpar@1
|
85 |
|
alpar@1
|
86 |
static int read_card(struct dsa *dsa)
|
alpar@1
|
87 |
{ int k, c;
|
alpar@1
|
88 |
dsa->seqn++;
|
alpar@1
|
89 |
memset(dsa->card, ' ', 80), dsa->card[80] = '\0';
|
alpar@1
|
90 |
k = 0;
|
alpar@1
|
91 |
for (;;)
|
alpar@1
|
92 |
{ c = fgetc(dsa->fp);
|
alpar@1
|
93 |
if (ferror(dsa->fp))
|
alpar@1
|
94 |
{ xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn,
|
alpar@1
|
95 |
strerror(errno));
|
alpar@1
|
96 |
return 1;
|
alpar@1
|
97 |
}
|
alpar@1
|
98 |
if (feof(dsa->fp))
|
alpar@1
|
99 |
{ if (k == 0)
|
alpar@1
|
100 |
xprintf("%s:%d: unexpected EOF\n", dsa->fname,
|
alpar@1
|
101 |
dsa->seqn);
|
alpar@1
|
102 |
else
|
alpar@1
|
103 |
xprintf("%s:%d: missing final LF\n", dsa->fname,
|
alpar@1
|
104 |
dsa->seqn);
|
alpar@1
|
105 |
return 1;
|
alpar@1
|
106 |
}
|
alpar@1
|
107 |
if (c == '\r') continue;
|
alpar@1
|
108 |
if (c == '\n') break;
|
alpar@1
|
109 |
if (iscntrl(c))
|
alpar@1
|
110 |
{ xprintf("%s:%d: invalid control character 0x%02X\n",
|
alpar@1
|
111 |
dsa->fname, dsa->seqn, c);
|
alpar@1
|
112 |
return 1;
|
alpar@1
|
113 |
}
|
alpar@1
|
114 |
if (k == 80)
|
alpar@1
|
115 |
{ xprintf("%s:%d: card image too long\n", dsa->fname,
|
alpar@1
|
116 |
dsa->seqn);
|
alpar@1
|
117 |
return 1;
|
alpar@1
|
118 |
}
|
alpar@1
|
119 |
dsa->card[k++] = (char)c;
|
alpar@1
|
120 |
}
|
alpar@1
|
121 |
return 0;
|
alpar@1
|
122 |
}
|
alpar@1
|
123 |
|
alpar@1
|
124 |
/***********************************************************************
|
alpar@1
|
125 |
* scan_int - scan integer value from the current card
|
alpar@1
|
126 |
*
|
alpar@1
|
127 |
* This routine scans an integer value from the current card, where fld
|
alpar@1
|
128 |
* is the name of the field, pos is the position of the field, width is
|
alpar@1
|
129 |
* the width of the field, val points to a location to which the scanned
|
alpar@1
|
130 |
* value should be stored. If the value was scanned successfully, the
|
alpar@1
|
131 |
* routine returns zero, otherwise non-zero. */
|
alpar@1
|
132 |
|
alpar@1
|
133 |
static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
|
alpar@1
|
134 |
int *val)
|
alpar@1
|
135 |
{ char str[80+1];
|
alpar@1
|
136 |
xassert(1 <= width && width <= 80);
|
alpar@1
|
137 |
memcpy(str, dsa->card + pos, width), str[width] = '\0';
|
alpar@1
|
138 |
if (str2int(strspx(str), val))
|
alpar@1
|
139 |
{ xprintf("%s:%d: field `%s' contains invalid value `%s'\n",
|
alpar@1
|
140 |
dsa->fname, dsa->seqn, fld, str);
|
alpar@1
|
141 |
return 1;
|
alpar@1
|
142 |
}
|
alpar@1
|
143 |
return 0;
|
alpar@1
|
144 |
}
|
alpar@1
|
145 |
|
alpar@1
|
146 |
/***********************************************************************
|
alpar@1
|
147 |
* parse_fmt - parse Fortran format specification
|
alpar@1
|
148 |
*
|
alpar@1
|
149 |
* This routine parses the Fortran format specification represented as
|
alpar@1
|
150 |
* character string which fmt points to and stores format elements into
|
alpar@1
|
151 |
* appropriate static locations. Should note that not all valid Fortran
|
alpar@1
|
152 |
* format specifications may be recognised. If the format specification
|
alpar@1
|
153 |
* was recognised, the routine returns zero, otherwise non-zero. */
|
alpar@1
|
154 |
|
alpar@1
|
155 |
static int parse_fmt(struct dsa *dsa, char *fmt)
|
alpar@1
|
156 |
{ int k, s, val;
|
alpar@1
|
157 |
char str[80+1];
|
alpar@1
|
158 |
/* first character should be left parenthesis */
|
alpar@1
|
159 |
if (fmt[0] != '(')
|
alpar@1
|
160 |
fail: { xprintf("hbm_read_mat: format `%s' not recognised\n", fmt);
|
alpar@1
|
161 |
return 1;
|
alpar@1
|
162 |
}
|
alpar@1
|
163 |
k = 1;
|
alpar@1
|
164 |
/* optional scale factor */
|
alpar@1
|
165 |
dsa->fmt_p = 0;
|
alpar@1
|
166 |
if (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
167 |
{ s = 0;
|
alpar@1
|
168 |
while (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
169 |
{ if (s == 80) goto fail;
|
alpar@1
|
170 |
str[s++] = fmt[k++];
|
alpar@1
|
171 |
}
|
alpar@1
|
172 |
str[s] = '\0';
|
alpar@1
|
173 |
if (str2int(str, &val)) goto fail;
|
alpar@1
|
174 |
if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
|
alpar@1
|
175 |
dsa->fmt_p = val, k++;
|
alpar@1
|
176 |
if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
|
alpar@1
|
177 |
/* optional comma may follow scale factor */
|
alpar@1
|
178 |
if (fmt[k] == ',') k++;
|
alpar@1
|
179 |
}
|
alpar@1
|
180 |
/* optional iterator */
|
alpar@1
|
181 |
dsa->fmt_k = 1;
|
alpar@1
|
182 |
if (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
183 |
{ s = 0;
|
alpar@1
|
184 |
while (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
185 |
{ if (s == 80) goto fail;
|
alpar@1
|
186 |
str[s++] = fmt[k++];
|
alpar@1
|
187 |
}
|
alpar@1
|
188 |
str[s] = '\0';
|
alpar@1
|
189 |
if (str2int(str, &val)) goto fail;
|
alpar@1
|
190 |
iter: dsa->fmt_k = val;
|
alpar@1
|
191 |
if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
|
alpar@1
|
192 |
}
|
alpar@1
|
193 |
/* format code */
|
alpar@1
|
194 |
dsa->fmt_f = toupper((unsigned char)fmt[k++]);
|
alpar@1
|
195 |
if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
|
alpar@1
|
196 |
dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
|
alpar@1
|
197 |
dsa->fmt_f == 'I')) goto fail;
|
alpar@1
|
198 |
/* field width */
|
alpar@1
|
199 |
if (!isdigit((unsigned char)fmt[k])) goto fail;
|
alpar@1
|
200 |
s = 0;
|
alpar@1
|
201 |
while (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
202 |
{ if (s == 80) goto fail;
|
alpar@1
|
203 |
str[s++] = fmt[k++];
|
alpar@1
|
204 |
}
|
alpar@1
|
205 |
str[s] = '\0';
|
alpar@1
|
206 |
if (str2int(str, &dsa->fmt_w)) goto fail;
|
alpar@1
|
207 |
if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
|
alpar@1
|
208 |
/* optional number of decimal places after point */
|
alpar@1
|
209 |
dsa->fmt_d = 0;
|
alpar@1
|
210 |
if (fmt[k] == '.')
|
alpar@1
|
211 |
{ k++;
|
alpar@1
|
212 |
if (!isdigit((unsigned char)fmt[k])) goto fail;
|
alpar@1
|
213 |
s = 0;
|
alpar@1
|
214 |
while (isdigit((unsigned char)fmt[k]))
|
alpar@1
|
215 |
{ if (s == 80) goto fail;
|
alpar@1
|
216 |
str[s++] = fmt[k++];
|
alpar@1
|
217 |
}
|
alpar@1
|
218 |
str[s] = '\0';
|
alpar@1
|
219 |
if (str2int(str, &dsa->fmt_d)) goto fail;
|
alpar@1
|
220 |
if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
|
alpar@1
|
221 |
}
|
alpar@1
|
222 |
/* last character should be right parenthesis */
|
alpar@1
|
223 |
if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
|
alpar@1
|
224 |
return 0;
|
alpar@1
|
225 |
}
|
alpar@1
|
226 |
|
alpar@1
|
227 |
/***********************************************************************
|
alpar@1
|
228 |
* read_int_array - read array of integer type
|
alpar@1
|
229 |
*
|
alpar@1
|
230 |
* This routine reads an integer array from the input text file, where
|
alpar@1
|
231 |
* name is array name, fmt is Fortran format specification that controls
|
alpar@1
|
232 |
* reading, n is number of array elements, val is array of integer type.
|
alpar@1
|
233 |
* If the array was read successful, the routine returns zero, otherwise
|
alpar@1
|
234 |
* non-zero. */
|
alpar@1
|
235 |
|
alpar@1
|
236 |
static int read_int_array(struct dsa *dsa, char *name, char *fmt,
|
alpar@1
|
237 |
int n, int val[])
|
alpar@1
|
238 |
{ int k, pos;
|
alpar@1
|
239 |
char str[80+1];
|
alpar@1
|
240 |
if (parse_fmt(dsa, fmt)) return 1;
|
alpar@1
|
241 |
if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
|
alpar@1
|
242 |
dsa->fmt_k * dsa->fmt_w <= 80))
|
alpar@1
|
243 |
{ xprintf(
|
alpar@1
|
244 |
"%s:%d: can't read array `%s' - invalid format `%s'\n",
|
alpar@1
|
245 |
dsa->fname, dsa->seqn, name, fmt);
|
alpar@1
|
246 |
return 1;
|
alpar@1
|
247 |
}
|
alpar@1
|
248 |
for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
|
alpar@1
|
249 |
{ if (pos >= dsa->fmt_k)
|
alpar@1
|
250 |
{ if (read_card(dsa)) return 1;
|
alpar@1
|
251 |
pos = 0;
|
alpar@1
|
252 |
}
|
alpar@1
|
253 |
memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
|
alpar@1
|
254 |
str[dsa->fmt_w] = '\0';
|
alpar@1
|
255 |
strspx(str);
|
alpar@1
|
256 |
if (str2int(str, &val[k]))
|
alpar@1
|
257 |
{ xprintf(
|
alpar@1
|
258 |
"%s:%d: can't read array `%s' - invalid value `%s'\n",
|
alpar@1
|
259 |
dsa->fname, dsa->seqn, name, str);
|
alpar@1
|
260 |
return 1;
|
alpar@1
|
261 |
}
|
alpar@1
|
262 |
}
|
alpar@1
|
263 |
return 0;
|
alpar@1
|
264 |
}
|
alpar@1
|
265 |
|
alpar@1
|
266 |
/***********************************************************************
|
alpar@1
|
267 |
* read_real_array - read array of real type
|
alpar@1
|
268 |
*
|
alpar@1
|
269 |
* This routine reads a real array from the input text file, where name
|
alpar@1
|
270 |
* is array name, fmt is Fortran format specification that controls
|
alpar@1
|
271 |
* reading, n is number of array elements, val is array of real type.
|
alpar@1
|
272 |
* If the array was read successful, the routine returns zero, otherwise
|
alpar@1
|
273 |
* non-zero. */
|
alpar@1
|
274 |
|
alpar@1
|
275 |
static int read_real_array(struct dsa *dsa, char *name, char *fmt,
|
alpar@1
|
276 |
int n, double val[])
|
alpar@1
|
277 |
{ int k, pos;
|
alpar@1
|
278 |
char str[80+1], *ptr;
|
alpar@1
|
279 |
if (parse_fmt(dsa, fmt)) return 1;
|
alpar@1
|
280 |
if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
|
alpar@1
|
281 |
dsa->fmt_k * dsa->fmt_w <= 80))
|
alpar@1
|
282 |
{ xprintf(
|
alpar@1
|
283 |
"%s:%d: can't read array `%s' - invalid format `%s'\n",
|
alpar@1
|
284 |
dsa->fname, dsa->seqn, name, fmt);
|
alpar@1
|
285 |
return 1;
|
alpar@1
|
286 |
}
|
alpar@1
|
287 |
for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
|
alpar@1
|
288 |
{ if (pos >= dsa->fmt_k)
|
alpar@1
|
289 |
{ if (read_card(dsa)) return 1;
|
alpar@1
|
290 |
pos = 0;
|
alpar@1
|
291 |
}
|
alpar@1
|
292 |
memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
|
alpar@1
|
293 |
str[dsa->fmt_w] = '\0';
|
alpar@1
|
294 |
strspx(str);
|
alpar@1
|
295 |
if (strchr(str, '.') == NULL && strcmp(str, "0"))
|
alpar@1
|
296 |
{ xprintf("%s(%d): can't read array `%s' - value `%s' has no "
|
alpar@1
|
297 |
"decimal point\n", dsa->fname, dsa->seqn, name, str);
|
alpar@1
|
298 |
return 1;
|
alpar@1
|
299 |
}
|
alpar@1
|
300 |
/* sometimes lower case letters appear */
|
alpar@1
|
301 |
for (ptr = str; *ptr; ptr++)
|
alpar@1
|
302 |
*ptr = (char)toupper((unsigned char)*ptr);
|
alpar@1
|
303 |
ptr = strchr(str, 'D');
|
alpar@1
|
304 |
if (ptr != NULL) *ptr = 'E';
|
alpar@1
|
305 |
/* value may appear with decimal exponent but without letters
|
alpar@1
|
306 |
E or D (for example, -123.456-012), so missing letter should
|
alpar@1
|
307 |
be inserted */
|
alpar@1
|
308 |
ptr = strchr(str+1, '+');
|
alpar@1
|
309 |
if (ptr == NULL) ptr = strchr(str+1, '-');
|
alpar@1
|
310 |
if (ptr != NULL && *(ptr-1) != 'E')
|
alpar@1
|
311 |
{ xassert(strlen(str) < 80);
|
alpar@1
|
312 |
memmove(ptr+1, ptr, strlen(ptr)+1);
|
alpar@1
|
313 |
*ptr = 'E';
|
alpar@1
|
314 |
}
|
alpar@1
|
315 |
if (str2num(str, &val[k]))
|
alpar@1
|
316 |
{ xprintf(
|
alpar@1
|
317 |
"%s:%d: can't read array `%s' - invalid value `%s'\n",
|
alpar@1
|
318 |
dsa->fname, dsa->seqn, name, str);
|
alpar@1
|
319 |
return 1;
|
alpar@1
|
320 |
}
|
alpar@1
|
321 |
}
|
alpar@1
|
322 |
return 0;
|
alpar@1
|
323 |
}
|
alpar@1
|
324 |
|
alpar@1
|
325 |
HBM *hbm_read_mat(const char *fname)
|
alpar@1
|
326 |
{ struct dsa _dsa, *dsa = &_dsa;
|
alpar@1
|
327 |
HBM *hbm = NULL;
|
alpar@1
|
328 |
dsa->fname = fname;
|
alpar@1
|
329 |
xprintf("hbm_read_mat: reading matrix from `%s'...\n",
|
alpar@1
|
330 |
dsa->fname);
|
alpar@1
|
331 |
dsa->fp = fopen(dsa->fname, "r");
|
alpar@1
|
332 |
if (dsa->fp == NULL)
|
alpar@1
|
333 |
{ xprintf("hbm_read_mat: unable to open `%s' - %s\n",
|
alpar@1
|
334 |
dsa->fname, strerror(errno));
|
alpar@1
|
335 |
goto fail;
|
alpar@1
|
336 |
}
|
alpar@1
|
337 |
dsa->seqn = 0;
|
alpar@1
|
338 |
hbm = xmalloc(sizeof(HBM));
|
alpar@1
|
339 |
memset(hbm, 0, sizeof(HBM));
|
alpar@1
|
340 |
/* read the first heading card */
|
alpar@1
|
341 |
if (read_card(dsa)) goto fail;
|
alpar@1
|
342 |
memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
|
alpar@1
|
343 |
strtrim(hbm->title);
|
alpar@1
|
344 |
xprintf("%s\n", hbm->title);
|
alpar@1
|
345 |
memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
|
alpar@1
|
346 |
strspx(hbm->key);
|
alpar@1
|
347 |
xprintf("key = %s\n", hbm->key);
|
alpar@1
|
348 |
/* read the second heading card */
|
alpar@1
|
349 |
if (read_card(dsa)) goto fail;
|
alpar@1
|
350 |
if (scan_int(dsa, "totcrd", 0, 14, &hbm->totcrd)) goto fail;
|
alpar@1
|
351 |
if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
|
alpar@1
|
352 |
if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
|
alpar@1
|
353 |
if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
|
alpar@1
|
354 |
if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
|
alpar@1
|
355 |
xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
|
alpar@1
|
356 |
"rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
|
alpar@1
|
357 |
hbm->valcrd, hbm->rhscrd);
|
alpar@1
|
358 |
/* read the third heading card */
|
alpar@1
|
359 |
if (read_card(dsa)) goto fail;
|
alpar@1
|
360 |
memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
|
alpar@1
|
361 |
if (strchr("RCP", hbm->mxtype[0]) == NULL ||
|
alpar@1
|
362 |
strchr("SUHZR", hbm->mxtype[1]) == NULL ||
|
alpar@1
|
363 |
strchr("AE", hbm->mxtype[2]) == NULL)
|
alpar@1
|
364 |
{ xprintf("%s:%d: matrix type `%s' not recognised\n",
|
alpar@1
|
365 |
dsa->fname, dsa->seqn, hbm->mxtype);
|
alpar@1
|
366 |
goto fail;
|
alpar@1
|
367 |
}
|
alpar@1
|
368 |
if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
|
alpar@1
|
369 |
if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
|
alpar@1
|
370 |
if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
|
alpar@1
|
371 |
if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
|
alpar@1
|
372 |
xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
|
alpar@1
|
373 |
" %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
|
alpar@1
|
374 |
hbm->neltvl);
|
alpar@1
|
375 |
/* read the fourth heading card */
|
alpar@1
|
376 |
if (read_card(dsa)) goto fail;
|
alpar@1
|
377 |
memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
|
alpar@1
|
378 |
strspx(hbm->ptrfmt);
|
alpar@1
|
379 |
memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
|
alpar@1
|
380 |
strspx(hbm->indfmt);
|
alpar@1
|
381 |
memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
|
alpar@1
|
382 |
strspx(hbm->valfmt);
|
alpar@1
|
383 |
memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
|
alpar@1
|
384 |
strspx(hbm->rhsfmt);
|
alpar@1
|
385 |
xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
|
alpar@1
|
386 |
hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
|
alpar@1
|
387 |
/* read the fifth heading card (optional) */
|
alpar@1
|
388 |
if (hbm->rhscrd <= 0)
|
alpar@1
|
389 |
{ strcpy(hbm->rhstyp, "???");
|
alpar@1
|
390 |
hbm->nrhs = 0;
|
alpar@1
|
391 |
hbm->nrhsix = 0;
|
alpar@1
|
392 |
}
|
alpar@1
|
393 |
else
|
alpar@1
|
394 |
{ if (read_card(dsa)) goto fail;
|
alpar@1
|
395 |
memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
|
alpar@1
|
396 |
if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
|
alpar@1
|
397 |
if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
|
alpar@1
|
398 |
xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n",
|
alpar@1
|
399 |
hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
|
alpar@1
|
400 |
}
|
alpar@1
|
401 |
/* read matrix structure */
|
alpar@1
|
402 |
hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
|
alpar@1
|
403 |
if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
|
alpar@1
|
404 |
hbm->colptr)) goto fail;
|
alpar@1
|
405 |
hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
|
alpar@1
|
406 |
if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
|
alpar@1
|
407 |
hbm->rowind)) goto fail;
|
alpar@1
|
408 |
/* read matrix values */
|
alpar@1
|
409 |
if (hbm->valcrd <= 0) goto done;
|
alpar@1
|
410 |
if (hbm->mxtype[2] == 'A')
|
alpar@1
|
411 |
{ /* assembled matrix */
|
alpar@1
|
412 |
hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
|
alpar@1
|
413 |
if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
|
alpar@1
|
414 |
hbm->values)) goto fail;
|
alpar@1
|
415 |
}
|
alpar@1
|
416 |
else
|
alpar@1
|
417 |
{ /* elemental (unassembled) matrix */
|
alpar@1
|
418 |
hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
|
alpar@1
|
419 |
if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
|
alpar@1
|
420 |
hbm->values)) goto fail;
|
alpar@1
|
421 |
}
|
alpar@1
|
422 |
/* read right-hand sides */
|
alpar@1
|
423 |
if (hbm->nrhs <= 0) goto done;
|
alpar@1
|
424 |
if (hbm->rhstyp[0] == 'F')
|
alpar@1
|
425 |
{ /* dense format */
|
alpar@1
|
426 |
hbm->nrhsvl = hbm->nrow * hbm->nrhs;
|
alpar@1
|
427 |
hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
|
alpar@1
|
428 |
if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
|
alpar@1
|
429 |
hbm->rhsval)) goto fail;
|
alpar@1
|
430 |
}
|
alpar@1
|
431 |
else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
|
alpar@1
|
432 |
{ /* sparse format */
|
alpar@1
|
433 |
/* read pointers */
|
alpar@1
|
434 |
hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
|
alpar@1
|
435 |
if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
|
alpar@1
|
436 |
hbm->rhsptr)) goto fail;
|
alpar@1
|
437 |
/* read sparsity pattern */
|
alpar@1
|
438 |
hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
|
alpar@1
|
439 |
if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
|
alpar@1
|
440 |
hbm->rhsind)) goto fail;
|
alpar@1
|
441 |
/* read values */
|
alpar@1
|
442 |
hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
|
alpar@1
|
443 |
if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
|
alpar@1
|
444 |
hbm->rhsval)) goto fail;
|
alpar@1
|
445 |
}
|
alpar@1
|
446 |
else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
|
alpar@1
|
447 |
{ /* elemental format */
|
alpar@1
|
448 |
hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
|
alpar@1
|
449 |
if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
|
alpar@1
|
450 |
hbm->rhsval)) goto fail;
|
alpar@1
|
451 |
}
|
alpar@1
|
452 |
else
|
alpar@1
|
453 |
{ xprintf("%s:%d: right-hand side type `%c' not recognised\n",
|
alpar@1
|
454 |
dsa->fname, dsa->seqn, hbm->rhstyp[0]);
|
alpar@1
|
455 |
goto fail;
|
alpar@1
|
456 |
}
|
alpar@1
|
457 |
/* read starting guesses */
|
alpar@1
|
458 |
if (hbm->rhstyp[1] == 'G')
|
alpar@1
|
459 |
{ hbm->nguess = hbm->nrow * hbm->nrhs;
|
alpar@1
|
460 |
hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
|
alpar@1
|
461 |
if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
|
alpar@1
|
462 |
hbm->sguess)) goto fail;
|
alpar@1
|
463 |
}
|
alpar@1
|
464 |
/* read solution vectors */
|
alpar@1
|
465 |
if (hbm->rhstyp[2] == 'X')
|
alpar@1
|
466 |
{ hbm->nexact = hbm->nrow * hbm->nrhs;
|
alpar@1
|
467 |
hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
|
alpar@1
|
468 |
if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
|
alpar@1
|
469 |
hbm->xexact)) goto fail;
|
alpar@1
|
470 |
}
|
alpar@1
|
471 |
done: /* reading has been completed */
|
alpar@1
|
472 |
xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
|
alpar@1
|
473 |
fclose(dsa->fp);
|
alpar@1
|
474 |
return hbm;
|
alpar@1
|
475 |
fail: /* something wrong in Danish kingdom */
|
alpar@1
|
476 |
if (hbm != NULL)
|
alpar@1
|
477 |
{ if (hbm->colptr != NULL) xfree(hbm->colptr);
|
alpar@1
|
478 |
if (hbm->rowind != NULL) xfree(hbm->rowind);
|
alpar@1
|
479 |
if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
|
alpar@1
|
480 |
if (hbm->rhsind != NULL) xfree(hbm->rhsind);
|
alpar@1
|
481 |
if (hbm->values != NULL) xfree(hbm->values);
|
alpar@1
|
482 |
if (hbm->rhsval != NULL) xfree(hbm->rhsval);
|
alpar@1
|
483 |
if (hbm->sguess != NULL) xfree(hbm->sguess);
|
alpar@1
|
484 |
if (hbm->xexact != NULL) xfree(hbm->xexact);
|
alpar@1
|
485 |
xfree(hbm);
|
alpar@1
|
486 |
}
|
alpar@1
|
487 |
if (dsa->fp != NULL) fclose(dsa->fp);
|
alpar@1
|
488 |
return NULL;
|
alpar@1
|
489 |
}
|
alpar@1
|
490 |
|
alpar@1
|
491 |
/***********************************************************************
|
alpar@1
|
492 |
* NAME
|
alpar@1
|
493 |
*
|
alpar@1
|
494 |
* hbm_free_mat - free sparse matrix in Harwell-Boeing format
|
alpar@1
|
495 |
*
|
alpar@1
|
496 |
* SYNOPSIS
|
alpar@1
|
497 |
*
|
alpar@1
|
498 |
* #include "glphbm.h"
|
alpar@1
|
499 |
* void hbm_free_mat(HBM *hbm);
|
alpar@1
|
500 |
*
|
alpar@1
|
501 |
* DESCRIPTION
|
alpar@1
|
502 |
*
|
alpar@1
|
503 |
* The hbm_free_mat routine frees all the memory allocated to the data
|
alpar@1
|
504 |
* structure containing a sparse matrix in the Harwell-Boeing format. */
|
alpar@1
|
505 |
|
alpar@1
|
506 |
void hbm_free_mat(HBM *hbm)
|
alpar@1
|
507 |
{ if (hbm->colptr != NULL) xfree(hbm->colptr);
|
alpar@1
|
508 |
if (hbm->rowind != NULL) xfree(hbm->rowind);
|
alpar@1
|
509 |
if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
|
alpar@1
|
510 |
if (hbm->rhsind != NULL) xfree(hbm->rhsind);
|
alpar@1
|
511 |
if (hbm->values != NULL) xfree(hbm->values);
|
alpar@1
|
512 |
if (hbm->rhsval != NULL) xfree(hbm->rhsval);
|
alpar@1
|
513 |
if (hbm->sguess != NULL) xfree(hbm->sguess);
|
alpar@1
|
514 |
if (hbm->xexact != NULL) xfree(hbm->xexact);
|
alpar@1
|
515 |
xfree(hbm);
|
alpar@1
|
516 |
return;
|
alpar@1
|
517 |
}
|
alpar@1
|
518 |
|
alpar@1
|
519 |
/* eof */
|