matrix_sparse/IOMatrixMarket.cxx

00001 // Copyright (C) 2001-2009 Vivien Mallet
00002 //
00003 // This file is part of the linear-algebra library Seldon,
00004 // http://seldon.sourceforge.net/.
00005 //
00006 // Seldon is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the Free
00008 // Software Foundation; either version 2.1 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public License
00017 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00018 
00019 
00020 #ifndef SELDON_FILE_MATRIX_SPARSE_IOMATRIXMARKET_CXX
00021 
00022 
00023 #include "IOMatrixMarket.hxx"
00024 #include <iomanip>
00025 
00026 namespace Seldon
00027 {
00028 
00029 
00031 
00044   template <class Prop, class Allocator>
00045   void ReadHarwellBoeing(string filename,
00046                          Matrix<float, Prop, ColSparse, Allocator>& A)
00047   {
00048     ReadHarwellBoeing(filename, "real", "general", A);
00049   }
00050 
00051 
00053   template <class Prop, class Allocator>
00054   void ReadHarwellBoeing(string filename,
00055                          Matrix<double, Prop, ColSparse, Allocator>& A)
00056   {
00057     ReadHarwellBoeing(filename, "real", "general", A);
00058   }
00059 
00060 
00062 
00080   template <class T, class Prop, class Storage, class Allocator>
00081   void ReadHarwellBoeing(string filename,
00082                          string value_type, string matrix_type,
00083                          Matrix<T, Prop, Storage, Allocator> & A)
00084   {
00085     int i, j, k;
00086     string line, element;
00087 
00088     // Dimensions of the output matrix.
00089     int Nrow, Ncol;
00090     int Nnonzero;
00091 
00092     ifstream input_stream(filename.c_str());
00093 
00094 #ifdef SELDON_CHECK_IO
00095     // Checks if the stream is ready.
00096     if (!input_stream.good())
00097       throw IOError("ReadHarwellBoeing(string filename, "
00098                     "Matrix& A, string value_type, string matrix_type)",
00099                     "Unable to read file \"" + filename + "\".");
00100 #endif
00101 
00102     /*** Parsing headers ***/
00103 
00104     // First line.
00105     string title, name;
00106     getline(input_stream, line);
00107     title = line.substr(0, 72);
00108     name = line.substr(72, 8);
00109 
00110     // Second line.
00111     int Nline_ptr, Nline_ind, Nline_val, Nline_rhs;
00112     input_stream >> i >> Nline_ptr >> Nline_ind >> Nline_val >> Nline_rhs;
00113 
00114     // Third line.
00115     string type;
00116     int Nelemental;
00117     input_stream >> type >> Nrow >> Ncol >> Nnonzero >> Nelemental;
00118 
00119     if (type.size() != 3)
00120       throw WrongArgument("ReadHarwellBoeing(string filename, "
00121                           "Matrix& A, string value_type, string matrix_type)",
00122                           "File \"" + filename + "\" contains a matrix of "
00123                           "type \"" + type + "\", which is not a valid type. "
00124                           "The type must contain exactly three characters.");
00125 
00126     if (type.substr(0, 1) != "R" && type.substr(0, 1) != "C"
00127         && type.substr(0, 1) != "P")
00128       throw WrongArgument("ReadHarwellBoeing(string filename, "
00129                           "Matrix& A, string value_type, string matrix_type)",
00130                           "File \"" + filename + "\" contains a matrix of "
00131                           "type \"" + type + "\", which is not a valid type. "
00132                           "The first character of that type must be 'R', 'C' "
00133                           "(not supported anyway) or 'P'.");
00134 
00135     if (type.substr(0, 1) == "C")
00136       throw WrongArgument("ReadHarwellBoeing(string filename, "
00137                           "Matrix& A, string value_type, string matrix_type)",
00138                           "File \"" + filename + "\" contains a "
00139                           "complex-valued matrix, which is not supported.");
00140 
00141     if (type.substr(0, 1) == "R" && value_type != "real")
00142       throw WrongArgument("ReadHarwellBoeing(string filename, "
00143                           "Matrix& A, string value_type, string matrix_type)",
00144                           "File \"" + filename + "\" contains a real-valued "
00145                           "matrix, while the input matrix 'A' is not "
00146                           "declared as such.");
00147 
00148     if (type.substr(1, 1) == "H")
00149       throw WrongArgument("ReadHarwellBoeing(string filename, "
00150                           "Matrix& A, string value_type, string matrix_type)",
00151                           "File \"" + filename + "\" contains a Hermitian "
00152                           "matrix, which is not supported.");
00153 
00154     if (type.substr(1, 1) == "Z")
00155       throw WrongArgument("ReadHarwellBoeing(string filename, "
00156                           "Matrix& A, string value_type, string matrix_type)",
00157                           "File \"" + filename + "\" contains a skew "
00158                           "symmetric matrix, which is not supported.");
00159 
00160     if (type.substr(1, 1) == "S")
00161       throw WrongArgument("ReadHarwellBoeing(string filename, "
00162                           "Matrix& A, string value_type, string matrix_type)",
00163                           "File \"" + filename + "\" contains a "
00164                           "symmetric matrix, which is not supported.");
00165 
00166     if (Nelemental != 0 || type.substr(2, 1) == "E")
00167       throw WrongArgument("ReadHarwellBoeing(string filename, "
00168                           "Matrix& A, string value_type, string matrix_type)",
00169                           "File \"" + filename + "\" contains an elemental "
00170                           "matrix, which is not supported.");
00171 
00172     getline(input_stream, line);
00173 
00174     // Fourth line.
00175     getline(input_stream, line);
00176     int line_width_ptr, element_width_ptr, line_width_ind, element_width_ind;
00177     element = line.substr(0, 16);
00178     sscanf(element.c_str(), "(%dI%d)", &line_width_ptr, &element_width_ptr);
00179     element = line.substr(16, 16);
00180     sscanf(element.c_str(), "(%dI%d)", &line_width_ind, &element_width_ind);
00181     int line_width_val = 0;
00182     int element_width_val = 0;
00183     if (type.substr(0, 1) != "P")
00184       {
00185         element = line.substr(32, 16);
00186 
00187         // Splits the format to retrieve the useful widths. This part is
00188         // tricky because no parsing (in C++) of Fortran format was found.
00189         vector<int> vect;
00190         string delimiter = " (ABEFGILOPZ*.)";
00191         string tmp_str;
00192         int tmp_int;
00193         string::size_type index_beg = element.find_first_not_of(delimiter);
00194         string::size_type index_end;
00195         while (index_beg != string::npos)
00196           {
00197             index_end = element.find_first_of(delimiter, index_beg);
00198             tmp_str = element.substr(index_beg,
00199                                      index_end == string::npos ?
00200                                      string::npos : (index_end-index_beg));
00201             istringstream(tmp_str) >> tmp_int;
00202             vect.push_back(tmp_int);
00203             index_beg = element.find_first_not_of(delimiter, index_end);
00204           }
00205 
00206         if (vect.size() < 3)
00207           throw WrongArgument("ReadHarwellBoeing(string filename, Matrix& A, "
00208                               "string value_type, string matrix_type)",
00209                               "File \"" + filename + "\" contains values "
00210                               "written in format \"" + element + "\", which "
00211                               "could not be parsed.");
00212 
00213         line_width_val = vect[vect.size() - 3];
00214         element_width_val = vect[vect.size() - 2];
00215       }
00216 
00217     // Fifth header line, if any: ignored. RHS are not read.
00218     if (Nline_rhs != 0)
00219       getline(input_stream, line);
00220 
00221     /*** Allocations ***/
00222 
00223     // Content of output matrix A.
00224     int* A_ptr;
00225     int* A_ind;
00226     T* A_data;
00227 
00228 #ifdef SELDON_CHECK_MEMORY
00229     try
00230       {
00231 #endif
00232 
00233         A_ptr = reinterpret_cast<int*>(calloc(Ncol + 1, sizeof(int)));
00234 
00235 #ifdef SELDON_CHECK_MEMORY
00236       }
00237     catch (...)
00238       {
00239         A_ptr = NULL;
00240       }
00241 
00242     if (A_ptr == NULL)
00243       throw NoMemory("ReadHarwellBoeing(string filename, "
00244                      "Matrix& A, string value_type, string matrix_type)",
00245                      "Unable to allocate memory for an array of "
00246                      + to_str(Ncol + 1) + " integers.");
00247 #endif
00248 
00249 #ifdef SELDON_CHECK_MEMORY
00250     try
00251       {
00252 #endif
00253 
00254         // Reallocates 'A_ind' and 'A_data' in order to append the
00255         // elements of the i-th row of C.
00256         A_ind = reinterpret_cast<int*>(calloc(Nnonzero, sizeof(int)));
00257         A_data = reinterpret_cast<T*>
00258           (A.GetAllocator().allocate(Nnonzero));
00259 
00260 #ifdef SELDON_CHECK_MEMORY
00261       }
00262     catch (...)
00263       {
00264         A_ind = NULL;
00265         A_data = NULL;
00266       }
00267 
00268     if (A_ind == NULL || A_data == NULL)
00269       throw NoMemory("ReadHarwellBoeing(string filename, "
00270                      "Matrix& A, string value_type, string matrix_type)",
00271                      "Unable to allocate memory for an array of "
00272                      + to_str(Nnonzero) + " integers "
00273                      "and for an array of "
00274                      + to_str(sizeof(T) * Nnonzero) + " bytes.");
00275 #endif
00276 
00277     /*** Reads the structure ***/
00278 
00279     int index = 0;
00280     for (i = 0; i < Nline_ptr; i++)
00281       {
00282         getline(input_stream, line);
00283         k = 0;
00284         for (j = 0; j < line_width_ptr; j++)
00285           {
00286             istringstream(line.substr(k, element_width_ptr)) >> A_ptr[index];
00287             // The indexes are 1-based, so this corrects it:
00288             A_ptr[index]--;
00289             index++;
00290             if (index == Ncol + 1)
00291               // So as not to read more elements than actually available on
00292               // the line.
00293               break;
00294             k += element_width_ptr;
00295           }
00296         if (index == Ncol + 1)
00297           break;
00298       }
00299 
00300     index = 0;
00301     for (i = 0; i < Nline_ind; i++)
00302       {
00303         getline(input_stream, line);
00304         k = 0;
00305         for (j = 0; j < line_width_ind; j++)
00306           {
00307             istringstream(line.substr(k, element_width_ind)) >> A_ind[index];
00308             // The indexes are 1-based, so this corrects it:
00309             A_ind[index]--;
00310             index++;
00311             if (index == Nnonzero)
00312               // So as not to read more elements than actually available on
00313               // the line.
00314               break;
00315             k += element_width_ind;
00316           }
00317         if (index == Nnonzero)
00318           break;
00319       }
00320 
00321     /*** Reads the values ***/
00322 
00323     if (type.substr(0, 1) == "P")
00324       for (i = 0; i < Nnonzero; i++)
00325         A_data[i] = T(1);
00326     else
00327       {
00328         index = 0;
00329         for (i = 0; i < Nline_val; i++)
00330           {
00331             getline(input_stream, line);
00332             k = 0;
00333             for (j = 0; j < line_width_val; j++)
00334               {
00335                 istringstream(line.substr(k, element_width_val))
00336                   >> A_data[index];
00337                 index++;
00338                 if (index == Nnonzero)
00339                   // So as not to read more elements than actually available
00340                   // on the line.
00341                   break;
00342                 k += element_width_val;
00343               }
00344             if (index == Nnonzero)
00345               break;
00346           }
00347       }
00348 
00349 #ifdef SELDON_CHECK_IO
00350     // Checks if the stream is still in good shape.
00351     if (!input_stream.good())
00352       throw IOError("ReadHarwellBoeing(string filename, "
00353                     "Matrix& A, string value_type, string matrix_type)",
00354                     "Unable to read all values in file \""
00355                     + filename + "\".");
00356 #endif
00357 
00358     input_stream.close();
00359 
00360     A.SetData(Nrow, Ncol, Nnonzero, A_data, A_ptr, A_ind);
00361   }
00362 
00363 
00364   template<class T>
00365   void PrintComplexValuesHarwell(int nnz, const Vector<complex<T> >& Val,
00366                                  ofstream& file_out)
00367   {
00368     for (int i = 0; i < 2*nnz; i += 3)
00369       {
00370         for (int j = i; j < min(i+3, 2*nnz); j++)
00371           {
00372             if (j%2 == 0)
00373               file_out << setw(23) << real(Val(j/2));
00374             else
00375               file_out << setw(23) << imag(Val(j/2));
00376           }
00377 
00378         file_out << '\n';
00379       }
00380   }
00381 
00382 
00383   template<class T>
00384   void PrintComplexValuesHarwell(int nnz, const Vector<T>& Val,
00385                                  ofstream& file_out)
00386   {
00387     for (int i = 0; i < nnz; i += 3)
00388       {
00389         for (int j = i; j < min(i+3, nnz); j++)
00390           file_out << setw(23) << Val(j);
00391 
00392         file_out << '\n';
00393       }
00394   }
00395 
00396 
00397   template<class T, class Prop, class Storage, class Allocator>
00398   void WriteHarwellBoeing(const Matrix<T, Prop, Storage, Allocator>& A,
00399                           const string& file_name, bool complex)
00400   {
00401     // converting to CSR
00402     IVect Ptr, Ind;
00403     Vector<T> Val;
00404     General sym;
00405     ConvertToCSC(A, sym, Ptr, Ind, Val);
00406 
00407     // number of columns and non-zero entries
00408     int nnz = Val.GetM();
00409     int m = A.GetM();
00410     int n = A.GetN();
00411 
00412     // First line
00413     ofstream file_out(file_name.data());
00414 
00415     string title("Seldon");
00416     string key("S0000008");
00417     file_out.setf(ios::left);
00418     file_out << setw(72) << title;
00419     file_out << setw(8) << key;
00420     file_out << endl;
00421 
00422     // Compute column pointer format
00423     int ptr_len = int(ceil( log10(0.1 + nnz + 1) )) + 1;
00424     int ptr_nperline = min(80 / ptr_len, n+1);
00425     int ptrcrd = n / ptr_nperline + 1;
00426     string ptrfmt = string("(") + to_str(ptr_nperline)
00427       + "I" + to_str(ptr_len) + ")";
00428 
00429     // Compute row index format
00430     int ind_len = int(ceil( log10(0.1 + n + 1) )) + 1;
00431     int ind_nperline = min(80 / ind_len, nnz);
00432     int indcrd = (nnz-1) / ind_nperline + 1;
00433     string indfmt = string("(") + to_str(ind_nperline)
00434       + 'I' + to_str(ind_len) + ')';
00435 
00436     // compute value format
00437     string valfmt("(3D23.15)");
00438     int valcrd = (nnz-1) / 3 + 1;
00439     if (complex)
00440       valcrd = (2*nnz-1) / 3 + 1;
00441 
00442     int rhscrd = 0;
00443     int totcrd = ptrcrd + indcrd + valcrd + rhscrd;
00444 
00445     // Second line
00446     file_out << setw(14) << totcrd;
00447     file_out << setw(14) << ptrcrd;
00448     file_out << setw(14) << indcrd;
00449     file_out << setw(14) << valcrd;
00450     file_out << setw(14) << rhscrd;
00451     file_out << endl;
00452 
00453     // Third line
00454     int neltvl = 0;
00455     char mxtype[4];
00456     if (complex)
00457       mxtype[0] = 'C';
00458     else
00459       mxtype[0] = 'R';
00460 
00461     if (m == n)
00462       mxtype[1] = 'U';
00463     else
00464       mxtype[1] = 'R';
00465 
00466     mxtype[2] = 'A';
00467     mxtype[3] = '\0';
00468 
00469     file_out << mxtype << "           ";
00470     file_out << setw(14) << m;
00471     file_out << setw(14) << n;
00472     file_out << setw(14) << nnz;
00473     file_out << setw(14) << neltvl;
00474     file_out << endl;
00475 
00476     // Fourth line
00477     file_out << setw(16) << ptrfmt;
00478     file_out << setw(16) << indfmt;
00479     file_out << setw(20) << valfmt;
00480     file_out << setw(20) << valfmt;
00481     file_out << endl;
00482 
00483     // printing ptr values
00484     file_out.setf(ios::left);
00485     for (int i = 0; i <= n; i += ptr_nperline)
00486       {
00487         for (int j = i; j < min(i+ptr_nperline, n+1); j++)
00488           file_out << setw(ptr_len) << Ptr(j)+1;
00489 
00490         file_out << '\n';
00491       }
00492 
00493     // printing ind values
00494     for (int i = 0; i < nnz; i += ind_nperline)
00495       {
00496         for (int j = i; j < min(i+ind_nperline, nnz); j++)
00497           file_out << setw(ind_len) << Ind(j)+1;
00498 
00499         file_out << '\n';
00500       }
00501 
00502     // printing values
00503     file_out.precision(15);
00504     file_out.setf(ios::scientific);
00505     PrintComplexValuesHarwell(nnz, Val, file_out);
00506 
00507     file_out.close();
00508   }
00509 
00510 
00512   template<class T, class Prop, class Storage, class Allocator>
00513   void WriteHarwellBoeing(const Matrix<T, Prop, Storage, Allocator>& A,
00514                           const string& file_name)
00515   {
00516     WriteHarwellBoeing(A, file_name, false);
00517   }
00518 
00519 
00521   template<class T, class Prop, class Storage, class Allocator>
00522   void WriteHarwellBoeing(const Matrix<complex<T>,
00523                           Prop, Storage, Allocator>& A,
00524                           const string& file_name)
00525   {
00526     WriteHarwellBoeing(A, file_name, true);
00527   }
00528 
00529 }
00530 
00531 
00532 #define SELDON_FILE_MATRIX_SPARSE_IOMATRIXMARKET_CXX
00533 #endif