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 
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 }
00365 
00366 
00367 #define SELDON_FILE_MATRIX_SPARSE_IOMATRIXMARKET_CXX
00368 #endif