You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1161 lines
40 KiB

  1. /* -*- c++ -*- (enables emacs c++ mode) */
  2. /*===========================================================================
  3. Copyright (C) 2003-2012 Yves Renard, Julien Pommier
  4. This file is a part of GETFEM++
  5. Getfem++ is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU Lesser General Public License as published
  7. by the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version along with the GCC Runtime Library
  9. Exception either version 3.1 or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  13. License and GCC Runtime Library Exception for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with this program; if not, write to the Free Software Foundation,
  16. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  17. As a special exception, you may use this file as it is a part of a free
  18. software library without restriction. Specifically, if other files
  19. instantiate templates or use macros or inline functions from this file,
  20. or you compile this file and link it with other files to produce an
  21. executable, this file does not by itself cause the resulting executable
  22. to be covered by the GNU Lesser General Public License. This exception
  23. does not however invalidate any other reasons why the executable file
  24. might be covered by the GNU Lesser General Public License.
  25. ===========================================================================*/
  26. /**@file gmm_inoutput.h
  27. @author Yves Renard <Yves.Renard@insa-lyon.fr>
  28. @author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
  29. @date July 8, 2003.
  30. @brief Input/output on sparse matrices
  31. Support Harwell-Boeing and Matrix-Market formats.
  32. */
  33. #ifndef GMM_INOUTPUT_H
  34. #define GMM_INOUTPUT_H
  35. #include <stdio.h>
  36. #include "gmm_kernel.h"
  37. namespace gmm {
  38. /*************************************************************************/
  39. /* */
  40. /* Functions to read and write Harwell Boeing format. */
  41. /* */
  42. /*************************************************************************/
  43. // Fri Aug 15 16:29:47 EDT 1997
  44. //
  45. // Harwell-Boeing File I/O in C
  46. // V. 1.0
  47. //
  48. // National Institute of Standards and Technology, MD.
  49. // K.A. Remington
  50. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  51. // NOTICE
  52. //
  53. // Permission to use, copy, modify, and distribute this software and
  54. // its documentation for any purpose and without fee is hereby granted
  55. // provided that the above copyright notice appear in all copies and
  56. // that both the copyright notice and this permission notice appear in
  57. // supporting documentation.
  58. //
  59. // Neither the Author nor the Institution (National Institute of Standards
  60. // and Technology) make any representations about the suitability of this
  61. // software for any purpose. This software is provided "as is" without
  62. // expressed or implied warranty.
  63. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  64. inline void IOHBTerminate(const char *a) { GMM_ASSERT1(false, a);}
  65. inline bool is_complex_double__(std::complex<double>) { return true; }
  66. inline bool is_complex_double__(double) { return false; }
  67. inline int ParseIfmt(const char *fmt, int* perline, int* width) {
  68. if (SECURE_NONCHAR_SSCANF(fmt, " (%dI%d)", perline, width) != 2) {
  69. *perline = 1;
  70. int s = SECURE_NONCHAR_SSCANF(fmt, " (I%d)", width);
  71. GMM_ASSERT1(s == 1, "invalid HB I-format: " << fmt);
  72. }
  73. return *width;
  74. }
  75. inline int ParseRfmt(const char *fmt, int* perline, int* width,
  76. int* prec, int* flag) {
  77. char p;
  78. *perline = *width = *flag = *prec = 0;
  79. #ifdef GMM_SECURE_CRT
  80. if (sscanf_s(fmt, " (%d%c%d.%d)", perline, &p, sizeof(char), width, prec)
  81. < 3 || !strchr("PEDF", p))
  82. #else
  83. if (sscanf(fmt, " (%d%c%d.%d)", perline, &p, width, prec) < 3
  84. || !strchr("PEDF", p))
  85. #endif
  86. {
  87. *perline = 1;
  88. #ifdef GMM_SECURE_CRT
  89. int s = sscanf_s(fmt, " (%c%d.%d)", &p, sizeof(char), width, prec);
  90. #else
  91. int s = sscanf(fmt, " (%c%d.%d)", &p, width, prec);
  92. #endif
  93. GMM_ASSERT1(s>=2 && strchr("PEDF",p), "invalid HB REAL format: " << fmt);
  94. }
  95. *flag = p;
  96. return *width;
  97. }
  98. /** matrix input/output for Harwell-Boeing format */
  99. struct HarwellBoeing_IO {
  100. int nrows() const { return Nrow; }
  101. int ncols() const { return Ncol; }
  102. int nnz() const { return Nnzero; }
  103. int is_complex() const { return Type[0] == 'C'; }
  104. int is_symmetric() const { return Type[1] == 'S'; }
  105. int is_hermitian() const { return Type[1] == 'H'; }
  106. HarwellBoeing_IO() { clear(); }
  107. HarwellBoeing_IO(const char *filename) { clear(); open(filename); }
  108. ~HarwellBoeing_IO() { close(); }
  109. /** open filename and reads header */
  110. void open(const char *filename);
  111. /** read the opened file */
  112. template <typename T, int shift> void read(csc_matrix<T, shift>& A);
  113. template <typename MAT> void read(MAT &M) IS_DEPRECATED;
  114. template <typename T, int shift>
  115. static void write(const char *filename, const csc_matrix<T, shift>& A);
  116. template <typename T, int shift>
  117. static void write(const char *filename, const csc_matrix<T, shift>& A,
  118. const std::vector<T> &rhs);
  119. template <typename T, typename INDI, typename INDJ, int shift>
  120. static void write(const char *filename,
  121. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
  122. template <typename T, typename INDI, typename INDJ, int shift>
  123. static void write(const char *filename,
  124. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
  125. const std::vector<T> &rhs);
  126. /** static method for saving the matrix */
  127. template <typename MAT> static void write(const char *filename,
  128. const MAT& A) IS_DEPRECATED;
  129. private:
  130. FILE *f;
  131. char Title[73], Key[9], Rhstype[4], Type[4];
  132. int Nrow, Ncol, Nnzero, Nrhs;
  133. char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
  134. int Ptrcrd, Indcrd, Valcrd, Rhscrd;
  135. int lcount;
  136. void close() { if (f) fclose(f); clear(); }
  137. void clear() {
  138. Nrow = Ncol = Nnzero = Nrhs = 0; f = 0; lcount = 0;
  139. memset(Type, 0, sizeof Type);
  140. memset(Key, 0, sizeof Key);
  141. memset(Title, 0, sizeof Title);
  142. }
  143. char *getline(char *buf) {
  144. char *p = fgets(buf, BUFSIZ, f); ++lcount;
  145. int s = SECURE_NONCHAR_SSCANF(buf,"%*s");
  146. GMM_ASSERT1(s >= 0 && p != 0,
  147. "blank line in HB file at line " << lcount);
  148. return buf;
  149. }
  150. int substrtoi(const char *p, size_type len) {
  151. char s[100]; len = std::min(len, sizeof s - 1);
  152. SECURE_STRNCPY(s, 100, p, len); s[len] = 0; return atoi(s);
  153. }
  154. double substrtod(const char *p, size_type len, int Valflag) {
  155. char s[100]; len = std::min(len, sizeof s - 1);
  156. SECURE_STRNCPY(s, 100, p, len); s[len] = 0;
  157. if ( Valflag != 'F' && !strchr(s,'E')) {
  158. /* insert a char prefix for exp */
  159. int last = int(strlen(s));
  160. for (int j=last+1;j>=0;j--) {
  161. s[j] = s[j-1];
  162. if ( s[j] == '+' || s[j] == '-' ) {
  163. s[j-1] = char(Valflag);
  164. break;
  165. }
  166. }
  167. }
  168. return atof(s);
  169. }
  170. template <typename IND_TYPE>
  171. int readHB_data(IND_TYPE colptr[], IND_TYPE rowind[],
  172. double val[]) {
  173. /***********************************************************************/
  174. /* This function opens and reads the specified file, interpreting its */
  175. /* contents as a sparse matrix stored in the Harwell/Boeing standard */
  176. /* format and creating compressed column storage scheme vectors to */
  177. /* hold the index and nonzero value information. */
  178. /* */
  179. /* ---------- */
  180. /* **CAVEAT** */
  181. /* ---------- */
  182. /* Parsing real formats from Fortran is tricky, and this file reader */
  183. /* does not claim to be foolproof. It has been tested for cases */
  184. /* when the real values are printed consistently and evenly spaced on */
  185. /* each line, with Fixed (F), and Exponential (E or D) formats. */
  186. /* */
  187. /* ** If the input file does not adhere to the H/B format, the ** */
  188. /* ** results will be unpredictable. ** */
  189. /* */
  190. /***********************************************************************/
  191. int i,ind,col,offset,count;
  192. int Ptrperline, Ptrwidth, Indperline, Indwidth;
  193. int Valperline, Valwidth, Valprec, Nentries;
  194. int Valflag = 'D'; /* Indicates 'E','D', or 'F' float format */
  195. char line[BUFSIZ];
  196. gmm::standard_locale sl;
  197. /* Parse the array input formats from Line 3 of HB file */
  198. ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
  199. ParseIfmt(Indfmt,&Indperline,&Indwidth);
  200. if ( Type[0] != 'P' ) { /* Skip if pattern only */
  201. ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
  202. }
  203. /* Read column pointer array: */
  204. offset = 0; /* if base 0 storage is declared (via macro def), */
  205. /* then storage entries are offset by 1 */
  206. for (count = 0, i=0;i<Ptrcrd;i++) {
  207. getline(line);
  208. for (col = 0, ind = 0;ind<Ptrperline;ind++) {
  209. if (count > Ncol) break;
  210. colptr[count] = substrtoi(line+col,Ptrwidth)-offset;
  211. count++; col += Ptrwidth;
  212. }
  213. }
  214. /* Read row index array: */
  215. for (count = 0, i=0;i<Indcrd;i++) {
  216. getline(line);
  217. for (col = 0, ind = 0;ind<Indperline;ind++) {
  218. if (count == Nnzero) break;
  219. rowind[count] = substrtoi(line+col,Indwidth)-offset;
  220. count++; col += Indwidth;
  221. }
  222. }
  223. /* Read array of values: */
  224. if ( Type[0] != 'P' ) { /* Skip if pattern only */
  225. if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
  226. else Nentries = Nnzero;
  227. count = 0;
  228. for (i=0;i<Valcrd;i++) {
  229. getline(line);
  230. if (Valflag == 'D') {
  231. // const_cast Due to aCC excentricity
  232. char *p;
  233. while( (p = const_cast<char *>(strchr(line,'D')) )) *p = 'E';
  234. }
  235. for (col = 0, ind = 0;ind<Valperline;ind++) {
  236. if (count == Nentries) break;
  237. val[count] = substrtod(line+col, Valwidth, Valflag);
  238. count++; col += Valwidth;
  239. }
  240. }
  241. }
  242. return 1;
  243. }
  244. };
  245. inline void HarwellBoeing_IO::open(const char *filename) {
  246. int Totcrd,Neltvl,Nrhsix;
  247. char line[BUFSIZ];
  248. close();
  249. SECURE_FOPEN(&f, filename, "r");
  250. GMM_ASSERT1(f, "could not open " << filename);
  251. /* First line: */
  252. #ifdef GMM_SECURE_CRT
  253. sscanf_s(getline(line), "%c%s", Title, 72, Key, 8);
  254. #else
  255. sscanf(getline(line), "%72c%8s", Title, Key);
  256. #endif
  257. Key[8] = Title[72] = 0;
  258. /* Second line: */
  259. Totcrd = Ptrcrd = Indcrd = Valcrd = Rhscrd = 0;
  260. SECURE_NONCHAR_SSCANF(getline(line), "%d%d%d%d%d", &Totcrd, &Ptrcrd,
  261. &Indcrd, &Valcrd, &Rhscrd);
  262. /* Third line: */
  263. Nrow = Ncol = Nnzero = Neltvl = 0;
  264. #ifdef GMM_SECURE_CRT
  265. if (sscanf_s(getline(line), "%c%d%d%d%d", Type, 3, &Nrow, &Ncol, &Nnzero,
  266. &Neltvl) < 1)
  267. #else
  268. if (sscanf(getline(line), "%3c%d%d%d%d", Type, &Nrow, &Ncol, &Nnzero,
  269. &Neltvl) < 1)
  270. #endif
  271. IOHBTerminate("Invalid Type info, line 3 of Harwell-Boeing file.\n");
  272. for (size_type i = 0; i < 3; ++i) Type[i] = char(toupper(Type[i]));
  273. /* Fourth line: */
  274. #ifdef GMM_SECURE_CRT
  275. if ( sscanf_s(getline(line), "%c%c%c%c",Ptrfmt, 16,Indfmt, 16,Valfmt,
  276. 20,Rhsfmt, 20) < 3)
  277. #else
  278. if ( sscanf(getline(line), "%16c%16c%20c%20c",Ptrfmt,Indfmt,Valfmt,
  279. Rhsfmt) < 3)
  280. #endif
  281. IOHBTerminate("Invalid format info, line 4 of Harwell-Boeing file.\n");
  282. Ptrfmt[16] = Indfmt[16] = Valfmt[20] = Rhsfmt[20] = 0;
  283. /* (Optional) Fifth line: */
  284. if (Rhscrd != 0 ) {
  285. Nrhs = Nrhsix = 0;
  286. #ifdef GMM_SECURE_CRT
  287. if ( sscanf_s(getline(line), "%c%d%d", Rhstype, 3, &Nrhs, &Nrhsix) != 1)
  288. #else
  289. if ( sscanf(getline(line), "%3c%d%d", Rhstype, &Nrhs, &Nrhsix) != 1)
  290. #endif
  291. IOHBTerminate("Invalid RHS type information, line 5 of"
  292. " Harwell-Boeing file.\n");
  293. }
  294. }
  295. /* only valid for double and complex<double> csc matrices */
  296. template <typename T, int shift> void
  297. HarwellBoeing_IO::read(csc_matrix<T, shift>& A) {
  298. typedef typename csc_matrix<T, shift>::IND_TYPE IND_TYPE;
  299. GMM_ASSERT1(f, "no file opened!");
  300. GMM_ASSERT1(Type[0] != 'P',
  301. "Bad HB matrix format (pattern matrices not supported)");
  302. GMM_ASSERT1(!is_complex_double__(T()) || Type[0] != 'R',
  303. "Bad HB matrix format (file contains a REAL matrix)");
  304. GMM_ASSERT1(is_complex_double__(T()) || Type[0] != 'C',
  305. "Bad HB matrix format (file contains a COMPLEX matrix)");
  306. A.nc = ncols(); A.nr = nrows();
  307. A.jc.resize(ncols()+1);
  308. A.ir.resize(nnz());
  309. A.pr.resize(nnz());
  310. readHB_data(&A.jc[0], &A.ir[0], (double*)&A.pr[0]);
  311. for (int i = 0; i <= ncols(); ++i) { A.jc[i] += shift; A.jc[i] -= 1; }
  312. for (int i = 0; i < nnz(); ++i) { A.ir[i] += shift; A.ir[i] -= 1; }
  313. }
  314. template <typename MAT> void
  315. HarwellBoeing_IO::read(MAT &M) {
  316. csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
  317. read(csc);
  318. resize(M, mat_nrows(csc), mat_ncols(csc));
  319. copy(csc, M);
  320. }
  321. template <typename IND_TYPE>
  322. inline int writeHB_mat_double(const char* filename, int M, int N, int nz,
  323. const IND_TYPE colptr[],
  324. const IND_TYPE rowind[],
  325. const double val[], int Nrhs,
  326. const double rhs[], const double guess[],
  327. const double exact[], const char* Title,
  328. const char* Key, const char* Type,
  329. const char* Ptrfmt, const char* Indfmt,
  330. const char* Valfmt, const char* Rhsfmt,
  331. const char* Rhstype, int shift) {
  332. /************************************************************************/
  333. /* The writeHB function opens the named file and writes the specified */
  334. /* matrix and optional right-hand-side(s) to that file in */
  335. /* Harwell-Boeing format. */
  336. /* */
  337. /* For a description of the Harwell Boeing standard, see: */
  338. /* Duff, et al., ACM TOMS Vol.15, No.1, March 1989 */
  339. /* */
  340. /************************************************************************/
  341. FILE *out_file;
  342. int i, entry, offset, j, acount, linemod;
  343. int totcrd, ptrcrd, indcrd, valcrd, rhscrd;
  344. int nvalentries, nrhsentries;
  345. int Ptrperline, Ptrwidth, Indperline, Indwidth;
  346. int Rhsperline, Rhswidth, Rhsprec, Rhsflag;
  347. int Valperline, Valwidth, Valprec;
  348. int Valflag; /* Indicates 'E','D', or 'F' float format */
  349. char pformat[16],iformat[16],vformat[19],rformat[19];
  350. // char *pValflag, *pRhsflag;
  351. gmm::standard_locale sl;
  352. if ( Type[0] == 'C' )
  353. { nvalentries = 2*nz; nrhsentries = 2*M; }
  354. else
  355. { nvalentries = nz; nrhsentries = M; }
  356. if ( filename != NULL ) {
  357. SECURE_FOPEN(&out_file, filename, "w");
  358. GMM_ASSERT1(out_file != NULL, "Error: Cannot open file: " << filename);
  359. } else out_file = stdout;
  360. if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
  361. ParseIfmt(Ptrfmt, &Ptrperline, &Ptrwidth);
  362. SECURE_SPRINTF1(pformat,sizeof(pformat),"%%%dd",Ptrwidth);
  363. ptrcrd = (N+1)/Ptrperline;
  364. if ( (N+1)%Ptrperline != 0) ptrcrd++;
  365. if ( Indfmt == NULL ) Indfmt = Ptrfmt;
  366. ParseIfmt(Indfmt, &Indperline, &Indwidth);
  367. SECURE_SPRINTF1(iformat,sizeof(iformat), "%%%dd",Indwidth);
  368. indcrd = nz/Indperline;
  369. if ( nz%Indperline != 0) indcrd++;
  370. if ( Type[0] != 'P' ) { /* Skip if pattern only */
  371. if ( Valfmt == NULL ) Valfmt = "(4E21.13)";
  372. ParseRfmt(Valfmt, &Valperline, &Valwidth, &Valprec, &Valflag);
  373. // if (Valflag == 'D') {
  374. // pValflag = (char *) strchr(Valfmt,'D');
  375. // *pValflag = 'E';
  376. // }
  377. if (Valflag == 'F')
  378. SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%df", Valwidth,
  379. Valprec);
  380. else
  381. SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%dE", Valwidth,
  382. Valprec);
  383. valcrd = nvalentries/Valperline;
  384. if ( nvalentries%Valperline != 0) valcrd++;
  385. } else valcrd = 0;
  386. if ( Nrhs > 0 ) {
  387. if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
  388. ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
  389. if (Rhsflag == 'F')
  390. SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%df",Rhswidth,Rhsprec);
  391. else
  392. SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%dE",Rhswidth,Rhsprec);
  393. // if (Valflag == 'D') {
  394. // pRhsflag = (char *) strchr(Rhsfmt,'D');
  395. // *pRhsflag = 'E';
  396. // }
  397. rhscrd = nrhsentries/Rhsperline;
  398. if ( nrhsentries%Rhsperline != 0) rhscrd++;
  399. if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
  400. if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
  401. rhscrd*=Nrhs;
  402. } else rhscrd = 0;
  403. totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
  404. /* Print header information: */
  405. fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
  406. ptrcrd, indcrd, valcrd, rhscrd);
  407. fprintf(out_file,"%3s%11s%14d%14d%14d%14d\n",Type," ", M, N, nz, 0);
  408. fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt);
  409. if ( Nrhs != 0 ) {
  410. /* Print Rhsfmt on fourth line and */
  411. /* optional fifth header line for auxillary vector information:*/
  412. fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs);
  413. }
  414. else
  415. fprintf(out_file,"\n");
  416. offset = 1 - shift; /* if base 0 storage is declared (via macro def), */
  417. /* then storage entries are offset by 1 */
  418. /* Print column pointers: */
  419. for (i = 0; i < N+1; i++) {
  420. entry = colptr[i]+offset;
  421. fprintf(out_file,pformat,entry);
  422. if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
  423. }
  424. if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
  425. /* Print row indices: */
  426. for (i=0;i<nz;i++) {
  427. entry = rowind[i]+offset;
  428. fprintf(out_file,iformat,entry);
  429. if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
  430. }
  431. if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
  432. /* Print values: */
  433. if ( Type[0] != 'P' ) { /* Skip if pattern only */
  434. for (i=0;i<nvalentries;i++) {
  435. fprintf(out_file,vformat,val[i]);
  436. if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
  437. }
  438. if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
  439. /* Print right hand sides: */
  440. acount = 1;
  441. linemod=0;
  442. if ( Nrhs > 0 ) {
  443. for (j=0;j<Nrhs;j++) {
  444. for (i=0;i<nrhsentries;i++) {
  445. fprintf(out_file,rformat,rhs[i] /* *Rhswidth */);
  446. if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
  447. }
  448. if ( acount%Rhsperline != linemod ) {
  449. fprintf(out_file,"\n");
  450. linemod = (acount-1)%Rhsperline;
  451. }
  452. if ( Rhstype[1] == 'G' ) {
  453. for (i=0;i<nrhsentries;i++) {
  454. fprintf(out_file,rformat,guess[i] /* *Rhswidth */);
  455. if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
  456. }
  457. if ( acount%Rhsperline != linemod ) {
  458. fprintf(out_file,"\n");
  459. linemod = (acount-1)%Rhsperline;
  460. }
  461. }
  462. if ( Rhstype[2] == 'X' ) {
  463. for (i=0;i<nrhsentries;i++) {
  464. fprintf(out_file,rformat,exact[i] /* *Rhswidth */);
  465. if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
  466. }
  467. if ( acount%Rhsperline != linemod ) {
  468. fprintf(out_file,"\n");
  469. linemod = (acount-1)%Rhsperline;
  470. }
  471. }
  472. }
  473. }
  474. }
  475. int s = fclose(out_file);
  476. GMM_ASSERT1(s == 0, "Error closing file in writeHB_mat_double().");
  477. return 1;
  478. }
  479. template <typename T, int shift> void
  480. HarwellBoeing_IO::write(const char *filename,
  481. const csc_matrix<T, shift>& A) {
  482. write(filename, csc_matrix_ref<const T*, const unsigned*,
  483. const unsigned *, shift>
  484. (&A.pr[0], &A.ir[0], &A.jc[0], A.nr, A.nc));
  485. }
  486. template <typename T, int shift> void
  487. HarwellBoeing_IO::write(const char *filename,
  488. const csc_matrix<T, shift>& A,
  489. const std::vector<T> &rhs) {
  490. write(filename, csc_matrix_ref<const T*, const unsigned*,
  491. const unsigned *, shift>
  492. (&A.pr[0], &A.ir[0], &A.jc[0], A.nr, A.nc), rhs);
  493. }
  494. template <typename T, typename INDI, typename INDJ, int shift> void
  495. HarwellBoeing_IO::write(const char *filename,
  496. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
  497. const char *t = 0;
  498. if (is_complex_double__(T()))
  499. if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
  500. else
  501. if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
  502. writeHB_mat_double(filename, int(mat_nrows(A)), int(mat_ncols(A)),
  503. A.jc[mat_ncols(A)], A.jc, A.ir,
  504. (const double *)A.pr,
  505. 0, 0, 0, 0, "GETFEM++ CSC MATRIX", "CSCMAT",
  506. t, 0, 0, 0, 0, "F", shift);
  507. }
  508. template <typename T, typename INDI, typename INDJ, int shift> void
  509. HarwellBoeing_IO::write(const char *filename,
  510. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
  511. const std::vector<T> &rhs) {
  512. const char *t = 0;
  513. if (is_complex_double__(T()))
  514. if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
  515. else
  516. if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
  517. int Nrhs = gmm::vect_size(rhs) / mat_nrows(A);
  518. writeHB_mat_double(filename, int(mat_nrows(A)), int(mat_ncols(A)),
  519. A.jc[mat_ncols(A)], A.jc, A.ir,
  520. (const double *)A.pr,
  521. Nrhs, (const double *)(&rhs[0]), 0, 0,
  522. "GETFEM++ CSC MATRIX", "CSCMAT",
  523. t, 0, 0, 0, 0, "F ", shift);
  524. }
  525. template <typename MAT> void
  526. HarwellBoeing_IO::write(const char *filename, const MAT& A) {
  527. gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
  528. tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
  529. gmm::copy(A,tmp);
  530. HarwellBoeing_IO::write(filename, tmp);
  531. }
  532. /** save a "double" or "std::complex<double>" csc matrix into a
  533. HarwellBoeing file
  534. */
  535. template <typename T, int shift> inline void
  536. Harwell_Boeing_save(const std::string &filename,
  537. const csc_matrix<T, shift>& A)
  538. { HarwellBoeing_IO::write(filename.c_str(), A); }
  539. /** save a reference on "double" or "std::complex<double>" csc matrix
  540. into a HarwellBoeing file
  541. */
  542. template <typename T, typename INDI, typename INDJ, int shift> inline void
  543. Harwell_Boeing_save(const std::string &filename,
  544. const csc_matrix_ref<T, INDI, INDJ, shift>& A)
  545. { HarwellBoeing_IO::write(filename.c_str(), A); }
  546. /** save a "double" or "std::complex<double>" generic matrix
  547. into a HarwellBoeing file making a copy in a csc matrix
  548. */
  549. template <typename MAT> inline void
  550. Harwell_Boeing_save(const std::string &filename, const MAT& A) {
  551. gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
  552. tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
  553. gmm::copy(A, tmp);
  554. HarwellBoeing_IO::write(filename.c_str(), tmp);
  555. }
  556. template <typename MAT, typename VECT> inline void
  557. Harwell_Boeing_save(const std::string &filename, const MAT& A,
  558. const VECT &RHS) {
  559. typedef typename gmm::linalg_traits<MAT>::value_type T;
  560. gmm::csc_matrix<T> tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
  561. gmm::copy(A, tmp);
  562. std::vector<T> tmprhs(gmm::vect_size(RHS));
  563. gmm::copy(RHS, tmprhs);
  564. HarwellBoeing_IO::write(filename.c_str(), tmp, tmprhs);
  565. }
  566. /** load a "double" or "std::complex<double>" csc matrix from a
  567. HarwellBoeing file
  568. */
  569. template <typename T, int shift> void
  570. Harwell_Boeing_load(const std::string &filename, csc_matrix<T, shift>& A) {
  571. HarwellBoeing_IO h(filename.c_str()); h.read(A);
  572. }
  573. /** load a "double" or "std::complex<double>" generic matrix from a
  574. HarwellBoeing file
  575. */
  576. template <typename MAT> void
  577. Harwell_Boeing_load(const std::string &filename, MAT& A) {
  578. csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
  579. Harwell_Boeing_load(filename, csc);
  580. resize(A, mat_nrows(csc), mat_ncols(csc));
  581. copy(csc, A);
  582. }
  583. /*************************************************************************/
  584. /* */
  585. /* Functions to read and write MatrixMarket format. */
  586. /* */
  587. /*************************************************************************/
  588. /*
  589. * Matrix Market I/O library for ANSI C
  590. *
  591. * See http://math.nist.gov/MatrixMarket for details.
  592. *
  593. *
  594. */
  595. #define MM_MAX_LINE_LENGTH 1025
  596. #define MatrixMarketBanner "%%MatrixMarket"
  597. #define MM_MAX_TOKEN_LENGTH 64
  598. typedef char MM_typecode[4];
  599. /******************* MM_typecode query functions *************************/
  600. #define mm_is_matrix(typecode) ((typecode)[0]=='M')
  601. #define mm_is_sparse(typecode) ((typecode)[1]=='C')
  602. #define mm_is_coordinate(typecode) ((typecode)[1]=='C')
  603. #define mm_is_dense(typecode) ((typecode)[1]=='A')
  604. #define mm_is_array(typecode) ((typecode)[1]=='A')
  605. #define mm_is_complex(typecode) ((typecode)[2]=='C')
  606. #define mm_is_real(typecode) ((typecode)[2]=='R')
  607. #define mm_is_pattern(typecode) ((typecode)[2]=='P')
  608. #define mm_is_integer(typecode) ((typecode)[2]=='I')
  609. #define mm_is_symmetric(typecode) ((typecode)[3]=='S')
  610. #define mm_is_general(typecode) ((typecode)[3]=='G')
  611. #define mm_is_skew(typecode) ((typecode)[3]=='K')
  612. #define mm_is_hermitian(typecode) ((typecode)[3]=='H')
  613. /******************* MM_typecode modify fucntions ************************/
  614. #define mm_set_matrix(typecode) ((*typecode)[0]='M')
  615. #define mm_set_coordinate(typecode) ((*typecode)[1]='C')
  616. #define mm_set_array(typecode) ((*typecode)[1]='A')
  617. #define mm_set_dense(typecode) mm_set_array(typecode)
  618. #define mm_set_sparse(typecode) mm_set_coordinate(typecode)
  619. #define mm_set_complex(typecode) ((*typecode)[2]='C')
  620. #define mm_set_real(typecode) ((*typecode)[2]='R')
  621. #define mm_set_pattern(typecode) ((*typecode)[2]='P')
  622. #define mm_set_integer(typecode) ((*typecode)[2]='I')
  623. #define mm_set_symmetric(typecode) ((*typecode)[3]='S')
  624. #define mm_set_general(typecode) ((*typecode)[3]='G')
  625. #define mm_set_skew(typecode) ((*typecode)[3]='K')
  626. #define mm_set_hermitian(typecode) ((*typecode)[3]='H')
  627. #define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
  628. (*typecode)[2]=' ',(*typecode)[3]='G')
  629. #define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
  630. /******************* Matrix Market error codes ***************************/
  631. #define MM_COULD_NOT_READ_FILE 11
  632. #define MM_PREMATURE_EOF 12
  633. #define MM_NOT_MTX 13
  634. #define MM_NO_HEADER 14
  635. #define MM_UNSUPPORTED_TYPE 15
  636. #define MM_LINE_TOO_LONG 16
  637. #define MM_COULD_NOT_WRITE_FILE 17
  638. /******************** Matrix Market internal definitions *****************
  639. MM_matrix_typecode: 4-character sequence
  640. object sparse/ data storage
  641. dense type scheme
  642. string position: [0] [1] [2] [3]
  643. Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
  644. A(array) C(omplex) H(ermitian)
  645. P(attern) S(ymmetric)
  646. I(nteger) K(kew)
  647. ***********************************************************************/
  648. #define MM_MTX_STR "matrix"
  649. #define MM_ARRAY_STR "array"
  650. #define MM_DENSE_STR "array"
  651. #define MM_COORDINATE_STR "coordinate"
  652. #define MM_SPARSE_STR "coordinate"
  653. #define MM_COMPLEX_STR "complex"
  654. #define MM_REAL_STR "real"
  655. #define MM_INT_STR "integer"
  656. #define MM_GENERAL_STR "general"
  657. #define MM_SYMM_STR "symmetric"
  658. #define MM_HERM_STR "hermitian"
  659. #define MM_SKEW_STR "skew-symmetric"
  660. #define MM_PATTERN_STR "pattern"
  661. inline char *mm_typecode_to_str(MM_typecode matcode) {
  662. char buffer[MM_MAX_LINE_LENGTH];
  663. const char *types[4] = {0,0,0,0};
  664. /* int error =0; */
  665. /* int i; */
  666. /* check for MTX type */
  667. if (mm_is_matrix(matcode))
  668. types[0] = MM_MTX_STR;
  669. /*
  670. else
  671. error=1;
  672. */
  673. /* check for CRD or ARR matrix */
  674. if (mm_is_sparse(matcode))
  675. types[1] = MM_SPARSE_STR;
  676. else
  677. if (mm_is_dense(matcode))
  678. types[1] = MM_DENSE_STR;
  679. else
  680. return NULL;
  681. /* check for element data type */
  682. if (mm_is_real(matcode))
  683. types[2] = MM_REAL_STR;
  684. else
  685. if (mm_is_complex(matcode))
  686. types[2] = MM_COMPLEX_STR;
  687. else
  688. if (mm_is_pattern(matcode))
  689. types[2] = MM_PATTERN_STR;
  690. else
  691. if (mm_is_integer(matcode))
  692. types[2] = MM_INT_STR;
  693. else
  694. return NULL;
  695. /* check for symmetry type */
  696. if (mm_is_general(matcode))
  697. types[3] = MM_GENERAL_STR;
  698. else if (mm_is_symmetric(matcode))
  699. types[3] = MM_SYMM_STR;
  700. else if (mm_is_hermitian(matcode))
  701. types[3] = MM_HERM_STR;
  702. else if (mm_is_skew(matcode))
  703. types[3] = MM_SKEW_STR;
  704. else
  705. return NULL;
  706. SECURE_SPRINTF4(buffer, sizeof(buffer), "%s %s %s %s", types[0], types[1],
  707. types[2], types[3]);
  708. return SECURE_STRDUP(buffer);
  709. }
  710. inline int mm_read_banner(FILE *f, MM_typecode *matcode) {
  711. char line[MM_MAX_LINE_LENGTH];
  712. char banner[MM_MAX_TOKEN_LENGTH];
  713. char mtx[MM_MAX_TOKEN_LENGTH];
  714. char crd[MM_MAX_TOKEN_LENGTH];
  715. char data_type[MM_MAX_TOKEN_LENGTH];
  716. char storage_scheme[MM_MAX_TOKEN_LENGTH];
  717. char *p;
  718. gmm::standard_locale sl;
  719. /* int ret_code; */
  720. mm_clear_typecode(matcode);
  721. if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
  722. return MM_PREMATURE_EOF;
  723. #ifdef GMM_SECURE_CRT
  724. if (sscanf_s(line, "%s %s %s %s %s", banner, sizeof(banner),
  725. mtx, sizeof(mtx), crd, sizeof(crd), data_type,
  726. sizeof(data_type), storage_scheme,
  727. sizeof(storage_scheme)) != 5)
  728. #else
  729. if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd,
  730. data_type, storage_scheme) != 5)
  731. #endif
  732. return MM_PREMATURE_EOF;
  733. for (p=mtx; *p!='\0'; *p=char(tolower(*p)),p++) {}; /* convert to lower case */
  734. for (p=crd; *p!='\0'; *p=char(tolower(*p)),p++) {};
  735. for (p=data_type; *p!='\0'; *p=char(tolower(*p)),p++) {};
  736. for (p=storage_scheme; *p!='\0'; *p=char(tolower(*p)),p++) {};
  737. /* check for banner */
  738. if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
  739. return MM_NO_HEADER;
  740. /* first field should be "mtx" */
  741. if (strcmp(mtx, MM_MTX_STR) != 0)
  742. return MM_UNSUPPORTED_TYPE;
  743. mm_set_matrix(matcode);
  744. /* second field describes whether this is a sparse matrix (in coordinate
  745. storgae) or a dense array */
  746. if (strcmp(crd, MM_SPARSE_STR) == 0)
  747. mm_set_sparse(matcode);
  748. else
  749. if (strcmp(crd, MM_DENSE_STR) == 0)
  750. mm_set_dense(matcode);
  751. else
  752. return MM_UNSUPPORTED_TYPE;
  753. /* third field */
  754. if (strcmp(data_type, MM_REAL_STR) == 0)
  755. mm_set_real(matcode);
  756. else
  757. if (strcmp(data_type, MM_COMPLEX_STR) == 0)
  758. mm_set_complex(matcode);
  759. else
  760. if (strcmp(data_type, MM_PATTERN_STR) == 0)
  761. mm_set_pattern(matcode);
  762. else
  763. if (strcmp(data_type, MM_INT_STR) == 0)
  764. mm_set_integer(matcode);
  765. else
  766. return MM_UNSUPPORTED_TYPE;
  767. /* fourth field */
  768. if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
  769. mm_set_general(matcode);
  770. else
  771. if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
  772. mm_set_symmetric(matcode);
  773. else
  774. if (strcmp(storage_scheme, MM_HERM_STR) == 0)
  775. mm_set_hermitian(matcode);
  776. else
  777. if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
  778. mm_set_skew(matcode);
  779. else
  780. return MM_UNSUPPORTED_TYPE;
  781. return 0;
  782. }
  783. inline int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz ) {
  784. char line[MM_MAX_LINE_LENGTH];
  785. /* int ret_code;*/
  786. int num_items_read;
  787. /* set return null parameter values, in case we exit with errors */
  788. *M = *N = *nz = 0;
  789. /* now continue scanning until you reach the end-of-comments */
  790. do {
  791. if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
  792. return MM_PREMATURE_EOF;
  793. } while (line[0] == '%');
  794. /* line[] is either blank or has M,N, nz */
  795. if (SECURE_NONCHAR_SSCANF(line, "%d %d %d", M, N, nz) == 3) return 0;
  796. else
  797. do {
  798. num_items_read = SECURE_NONCHAR_FSCANF(f, "%d %d %d", M, N, nz);
  799. if (num_items_read == EOF) return MM_PREMATURE_EOF;
  800. }
  801. while (num_items_read != 3);
  802. return 0;
  803. }
  804. inline int mm_read_mtx_crd_data(FILE *f, int, int, int nz, int I[],
  805. int J[], double val[], MM_typecode matcode) {
  806. int i;
  807. if (mm_is_complex(matcode)) {
  808. for (i=0; i<nz; i++)
  809. if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg %lg", &I[i], &J[i],
  810. &val[2*i], &val[2*i+1])
  811. != 4) return MM_PREMATURE_EOF;
  812. }
  813. else if (mm_is_real(matcode)) {
  814. for (i=0; i<nz; i++) {
  815. if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
  816. != 3) return MM_PREMATURE_EOF;
  817. }
  818. }
  819. else if (mm_is_pattern(matcode)) {
  820. for (i=0; i<nz; i++)
  821. if (SECURE_NONCHAR_FSCANF(f, "%d %d", &I[i], &J[i])
  822. != 2) return MM_PREMATURE_EOF;
  823. }
  824. else return MM_UNSUPPORTED_TYPE;
  825. return 0;
  826. }
  827. inline int mm_write_mtx_crd(const char *fname, int M, int N, int nz,
  828. int I[], int J[], const double val[],
  829. MM_typecode matcode) {
  830. FILE *f;
  831. int i;
  832. if (strcmp(fname, "stdout") == 0)
  833. f = stdout;
  834. else {
  835. SECURE_FOPEN(&f, fname, "w");
  836. if (f == NULL)
  837. return MM_COULD_NOT_WRITE_FILE;
  838. }
  839. /* print banner followed by typecode */
  840. fprintf(f, "%s ", MatrixMarketBanner);
  841. char *str = mm_typecode_to_str(matcode);
  842. fprintf(f, "%s\n", str);
  843. free(str);
  844. /* print matrix sizes and nonzeros */
  845. fprintf(f, "%d %d %d\n", M, N, nz);
  846. /* print values */
  847. if (mm_is_pattern(matcode))
  848. for (i=0; i<nz; i++)
  849. fprintf(f, "%d %d\n", I[i], J[i]);
  850. else
  851. if (mm_is_real(matcode))
  852. for (i=0; i<nz; i++)
  853. fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
  854. else
  855. if (mm_is_complex(matcode))
  856. for (i=0; i<nz; i++)
  857. fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
  858. val[2*i+1]);
  859. else {
  860. if (f != stdout) fclose(f);
  861. return MM_UNSUPPORTED_TYPE;
  862. }
  863. if (f !=stdout) fclose(f);
  864. return 0;
  865. }
  866. /** matrix input/output for MatrixMarket storage */
  867. class MatrixMarket_IO {
  868. FILE *f;
  869. bool isComplex, isSymmetric, isHermitian;
  870. int row, col, nz;
  871. MM_typecode matcode;
  872. public:
  873. MatrixMarket_IO() : f(0) {}
  874. MatrixMarket_IO(const char *filename) : f(0) { open(filename); }
  875. ~MatrixMarket_IO() { if (f) fclose(f); f = 0; }
  876. int nrows() const { return row; }
  877. int ncols() const { return col; }
  878. int nnz() const { return nz; }
  879. int is_complex() const { return isComplex; }
  880. int is_symmetric() const { return isSymmetric; }
  881. int is_hermitian() const { return isHermitian; }
  882. /* open filename and reads header */
  883. void open(const char *filename);
  884. /* read opened file */
  885. template <typename Matrix> void read(Matrix &A);
  886. /* write a matrix */
  887. template <typename T, int shift> static void
  888. write(const char *filename, const csc_matrix<T, shift>& A);
  889. template <typename T, typename INDI, typename INDJ, int shift> static void
  890. write(const char *filename,
  891. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
  892. template <typename MAT> static void
  893. write(const char *filename, const MAT& A);
  894. };
  895. /** load a matrix-market file */
  896. template <typename Matrix> inline void
  897. MatrixMarket_load(const char *filename, Matrix& A) {
  898. MatrixMarket_IO mm; mm.open(filename);
  899. mm.read(A);
  900. }
  901. /** write a matrix-market file */
  902. template <typename T, int shift> void
  903. MatrixMarket_save(const char *filename, const csc_matrix<T, shift>& A) {
  904. MatrixMarket_IO mm; mm.write(filename, A);
  905. }
  906. template <typename T, typename INDI, typename INDJ, int shift> inline void
  907. MatrixMarket_save(const char *filename,
  908. const csc_matrix_ref<T, INDI, INDJ, shift>& A) {
  909. MatrixMarket_IO mm; mm.write(filename, A);
  910. }
  911. inline void MatrixMarket_IO::open(const char *filename) {
  912. gmm::standard_locale sl;
  913. if (f) { fclose(f); }
  914. SECURE_FOPEN(&f, filename, "r");
  915. GMM_ASSERT1(f, "Sorry, cannot open file " << filename);
  916. int s1 = mm_read_banner(f, &matcode);
  917. GMM_ASSERT1(s1 == 0, "Sorry, cannnot find the matrix market banner in "
  918. << filename);
  919. int s2 = mm_is_coordinate(matcode), s3 = mm_is_matrix(matcode);
  920. GMM_ASSERT1(s2 > 0 && s3 > 0,
  921. "file is not coordinate storage or is not a matrix");
  922. int s4 = mm_is_pattern(matcode);
  923. GMM_ASSERT1(s4 == 0,
  924. "the file does only contain the pattern of a sparse matrix");
  925. int s5 = mm_is_skew(matcode);
  926. GMM_ASSERT1(s5 == 0, "not currently supporting skew symmetric");
  927. isSymmetric = mm_is_symmetric(matcode) || mm_is_hermitian(matcode);
  928. isHermitian = mm_is_hermitian(matcode);
  929. isComplex = mm_is_complex(matcode);
  930. mm_read_mtx_crd_size(f, &row, &col, &nz);
  931. }
  932. template <typename Matrix> void MatrixMarket_IO::read(Matrix &A) {
  933. gmm::standard_locale sl;
  934. typedef typename linalg_traits<Matrix>::value_type T;
  935. GMM_ASSERT1(f, "no file opened!");
  936. GMM_ASSERT1(!is_complex_double__(T()) || isComplex,
  937. "Bad MM matrix format (complex matrix expected)");
  938. GMM_ASSERT1(is_complex_double__(T()) || !isComplex,
  939. "Bad MM matrix format (real matrix expected)");
  940. A = Matrix(row, col);
  941. gmm::clear(A);
  942. std::vector<int> I(nz), J(nz);
  943. std::vector<typename Matrix::value_type> PR(nz);
  944. mm_read_mtx_crd_data(f, row, col, nz, &I[0], &J[0],
  945. (double*)&PR[0], matcode);
  946. for (size_type i = 0; i < size_type(nz); ++i) {
  947. A(I[i]-1, J[i]-1) = PR[i];
  948. // FIXED MM Format
  949. if (mm_is_hermitian(matcode) && (I[i] != J[i]) ) {
  950. A(J[i]-1, I[i]-1) = gmm::conj(PR[i]);
  951. }
  952. if (mm_is_symmetric(matcode) && (I[i] != J[i]) ) {
  953. A(J[i]-1, I[i]-1) = PR[i];
  954. }
  955. if (mm_is_skew(matcode) && (I[i] != J[i]) ) {
  956. A(J[i]-1, I[i]-1) = -PR[i];
  957. }
  958. }
  959. }
  960. template <typename T, int shift> void
  961. MatrixMarket_IO::write(const char *filename, const csc_matrix<T, shift>& A) {
  962. write(filename, csc_matrix_ref<const T*, const unsigned*,
  963. const unsigned*,shift>
  964. (&A.pr[0], &A.ir[0], &A.jc[0], A.nr, A.nc));
  965. }
  966. template <typename T, typename INDI, typename INDJ, int shift> void
  967. MatrixMarket_IO::write(const char *filename,
  968. const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
  969. gmm::standard_locale sl;
  970. static MM_typecode t1 = {'M', 'C', 'R', 'G'};
  971. static MM_typecode t2 = {'M', 'C', 'C', 'G'};
  972. MM_typecode t;
  973. if (is_complex_double__(T())) std::copy(&(t2[0]), &(t2[0])+4, &(t[0]));
  974. else std::copy(&(t1[0]), &(t1[0])+4, &(t[0]));
  975. size_type nz = A.jc[mat_ncols(A)];
  976. std::vector<int> I(nz), J(nz);
  977. for (size_type j=0; j < mat_ncols(A); ++j) {
  978. for (size_type i = A.jc[j]; i < A.jc[j+1]; ++i) {
  979. I[i] = A.ir[i] + 1 - shift;
  980. J[i] = int(j + 1);
  981. }
  982. }
  983. mm_write_mtx_crd(filename, int(mat_nrows(A)), int(mat_ncols(A)),
  984. int(nz), &I[0], &J[0], (const double *)A.pr, t);
  985. }
  986. template <typename MAT> void
  987. MatrixMarket_IO::write(const char *filename, const MAT& A) {
  988. gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
  989. tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
  990. gmm::copy(A,tmp);
  991. MatrixMarket_IO::write(filename, tmp);
  992. }
  993. template<typename VEC> static void vecsave(std::string fname, const VEC& V) {
  994. std::ofstream f(fname.c_str()); f.precision(16); f.imbue(std::locale("C"));
  995. for (size_type i=0; i < gmm::vect_size(V); ++i) f << V[i] << "\n";
  996. }
  997. template<typename VEC> static void vecload(std::string fname,
  998. const VEC& V_) {
  999. VEC &V(const_cast<VEC&>(V_));
  1000. std::ifstream f(fname.c_str()); f.imbue(std::locale("C"));
  1001. for (size_type i=0; i < gmm::vect_size(V); ++i) f >> V[i];
  1002. }
  1003. }
  1004. #endif // GMM_INOUTPUT_H