glphbm.c 19 KB

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