ViennaCL - The Vienna Computing Library  1.5.1
viennacl/io/matrix_market.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_IO_MATRIX_MARKET_HPP
00002 #define VIENNACL_IO_MATRIX_MARKET_HPP
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2014, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008    Portions of this software are copyright by UChicago Argonne, LLC.
00009 
00010                             -----------------
00011                   ViennaCL - The Vienna Computing Library
00012                             -----------------
00013 
00014    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00015 
00016    (A list of authors and contributors can be found in the PDF manual)
00017 
00018    License:         MIT (X11), see file LICENSE in the base directory
00019 ============================================================================= */
00020 
00021 
00026 #include <algorithm>
00027 #include <string>
00028 #include <iostream>
00029 #include <fstream>
00030 #include <sstream>
00031 #include <vector>
00032 #include <map>
00033 #include <cctype>
00034 #include "viennacl/tools/adapter.hpp"
00035 #include "viennacl/traits/size.hpp"
00036 #include "viennacl/traits/fill.hpp"
00037 
00038 namespace viennacl
00039 {
00040   namespace io
00041   {
00042     //helper
00043     namespace detail
00044     {
00045       inline void trim(char * buffer, long max_size)
00046       {
00047         //trim at beginning of string
00048         long start = 0;
00049         for (long i=0; i<max_size; ++i)
00050         {
00051           if (buffer[i] == ' ')
00052             ++start;
00053           else
00054             break;
00055         }
00056 
00057         //trim at end of string
00058         long stop = start;
00059         for (long i=stop; i<max_size; ++i)
00060         {
00061           if (buffer[i] == 0)   //end of string
00062             break;
00063 
00064           if (buffer[i] != ' ')
00065             stop = i;
00066         }
00067 
00068         for (long i=0; i<=stop - start; ++i)
00069         {
00070           buffer[i] = buffer[start + i];
00071         }
00072 
00073         if (buffer[0] != ' ')
00074           buffer[stop - start + 1] = 0; //terminate string
00075         else
00076           buffer[0] = 0;
00077       }
00078 
00079       inline std::string tolower(std::string & s)
00080       {
00081         std::transform(s.begin(), s.end(), s.begin(), static_cast < int(*)(int) > (std::tolower));
00082         return s;
00083       }
00084 
00085 
00086 
00087     } //namespace
00088 
00090 
00099     template <typename MatrixType>
00100     long read_matrix_market_file_impl(MatrixType & mat,
00101                                       const char * file,
00102                                       long index_base)
00103     {
00104       typedef typename viennacl::result_of::cpu_value_type<typename viennacl::result_of::value_type<MatrixType>::type>::type    ScalarType;
00105 
00106       //std::cout << "Reading matrix market file" << std::endl;
00107       char buffer[1025];
00108       std::ifstream reader(file);
00109       std::string token;
00110       long linenum = 0;
00111       bool symmetric = false;
00112       bool dense_format = false;
00113       bool is_header = true;
00114       long cur_row = 0;
00115       long cur_col = 0;
00116       long valid_entries = 0;
00117       long nnz = 0;
00118 
00119 
00120       if (!reader){
00121         std::cerr << "ViennaCL: Matrix Market Reader: Cannot open file " << file << std::endl;
00122         return EXIT_FAILURE;
00123       }
00124 
00125       while (reader.good())
00126       {
00127         // get a non-empty line
00128         do
00129         {
00130           reader.getline(buffer, 1024);
00131           ++linenum;
00132           detail::trim(buffer, 1024);
00133         }
00134         while (reader.good() && buffer[0] == 0);
00135 
00136         if (buffer[0] == '%')
00137         {
00138           if (buffer[1] == '%')
00139           {
00140             //parse header:
00141             std::stringstream line(std::string(buffer + 2));
00142             line >> token;
00143             if (detail::tolower(token) != "matrixmarket")
00144             {
00145               std::cerr << "Error in file " << file << " at line " << linenum << " in file " << file << ": Expected 'MatrixMarket', got '" << token << "'" << std::endl;
00146               return 0;
00147             }
00148 
00149             line >> token;
00150             if (detail::tolower(token) != "matrix")
00151             {
00152               std::cerr << "Error in file " << file << " at line " << linenum << " in file " << file << ": Expected 'matrix', got '" << token << "'" << std::endl;
00153               return 0;
00154             }
00155 
00156             line >> token;
00157             if (detail::tolower(token) != "coordinate")
00158             {
00159               if (detail::tolower(token) == "array")
00160               {
00161                 dense_format = true;
00162                 std::cerr << "Error in file " << file << " at line " << linenum << " in file " << file << ": 'array' type is not supported yet!" << std::endl;
00163                 return 0;
00164               }
00165               else
00166               {
00167                 std::cerr << "Error in file " << file << " at line " << linenum << " in file " << file << ": Expected 'array' or 'coordinate', got '" << token << "'" << std::endl;
00168                 return 0;
00169               }
00170             }
00171 
00172             line >> token;
00173             if (detail::tolower(token) != "real")
00174             {
00175               std::cerr << "Error in file " << file << ": The MatrixMarket reader provided with ViennaCL supports only real valued floating point arithmetic." << std::endl;
00176               return 0;
00177             }
00178 
00179             line >> token;
00180             if (detail::tolower(token) == "general"){ }
00181             else if (detail::tolower(token) == "symmetric"){ symmetric = true; }
00182             else
00183             {
00184               std::cerr << "Error in file " << file << ": The MatrixMarket reader provided with ViennaCL supports only general or symmetric matrices." << std::endl;
00185               return 0;
00186             }
00187 
00188           }
00189         }
00190         else
00191         {
00192           std::stringstream line(std::stringstream::in | std::stringstream::out);
00193           line << std::string(buffer);
00194 
00195           if (is_header)
00196           {
00197             //read header line
00198             long rows;
00199             long cols;
00200 
00201             if (line.good())
00202               line >> rows;
00203             else
00204             {
00205               std::cerr << "Error in file " << file << ": Could not get matrix dimensions (rows) in line " << linenum << std::endl;
00206               return 0;
00207             }
00208 
00209             if (line.good())
00210               line >> cols;
00211             else
00212             {
00213               std::cerr << "Error in file " << file << ": Could not get matrix dimensions (columns) in line " << linenum << std::endl;
00214               return 0;
00215             }
00216             if (!dense_format)
00217             {
00218               if (line.good())
00219                 line >> nnz;
00220               else
00221               {
00222                 std::cerr << "Error in file " << file << ": Could not get matrix dimensions (columns) in line " << linenum << std::endl;
00223                 return 0;
00224               }
00225             }
00226 
00227             if (rows > 0 && cols > 0)
00228               viennacl::traits::resize(mat, rows, cols);
00229 
00230             is_header = false;
00231           }
00232           else
00233           {
00234             //read data
00235             if (dense_format)
00236             {
00237               ScalarType value;
00238               line >> value;
00239               viennacl::traits::fill(mat, cur_row, cur_col, value);
00240 
00241               if (++cur_row == static_cast<long>(viennacl::traits::size1(mat)))
00242               {
00243                 //next column
00244                 ++cur_col;
00245                 cur_row = 0;
00246               }
00247             }
00248             else //sparse format
00249             {
00250               long row;
00251               long col;
00252               ScalarType value;
00253 
00254               //parse data:
00255               if (line.good())
00256                 line >> row;
00257               else
00258               {
00259                 std::cerr << "Error in file " << file << ": Parse error for matrix entry in line " << linenum << std::endl;
00260                 return 0;
00261               }
00262 
00263               if (line.good())
00264                 line >> col;
00265               else
00266               {
00267                 std::cerr << "Error in file " << file << ": Parse error for matrix entry in line " << linenum << std::endl;
00268                 return 0;
00269               }
00270 
00271               //take index_base base into account:
00272               row -= index_base;
00273               col -= index_base;
00274 
00275               if (line.good())
00276                 line >> value;
00277               else
00278               {
00279                 std::cerr << "Error in file " << file << ": Parse error for matrix entry in line " << linenum << std::endl;
00280                 return 0;
00281               }
00282 
00283               if (row >= static_cast<long>(viennacl::traits::size1(mat)) || row < 0)
00284               {
00285                 std::cerr << "Error in file " << file << " at line " << linenum << ": Row index out of bounds: " << row << " (matrix dim: " << viennacl::traits::size1(mat) << " x " << viennacl::traits::size2(mat) << ")" << std::endl;
00286                 return 0;
00287               }
00288 
00289               if (col >= static_cast<long>(viennacl::traits::size2(mat)) || col < 0)
00290               {
00291                 std::cerr << "Error in file " << file << " at line " << linenum << ": Column index out of bounds: " << col << " (matrix dim: " << viennacl::traits::size1(mat) << " x " << viennacl::traits::size2(mat) << ")" << std::endl;
00292                 return 0;
00293               }
00294 
00295               viennacl::traits::fill(mat, row, col, value); //basically equivalent to mat(row, col) = value;
00296               if (symmetric)
00297                 viennacl::traits::fill(mat, col, row, value); //basically equivalent to mat(col, row) = value;
00298 
00299               if (++valid_entries == nnz)
00300                 break;
00301 
00302             } //else dense_format
00303           }
00304         }
00305       }
00306 
00307       //std::cout << linenum << " lines read." << std::endl;
00308       reader.close();
00309       return linenum;
00310     }
00311 
00312 
00321     template <typename MatrixType>
00322     long read_matrix_market_file(MatrixType & mat,
00323                                  const char * file,
00324                                  long index_base = 1)
00325     {
00326       return read_matrix_market_file_impl(mat, file, index_base);
00327     }
00328 
00329     template <typename MatrixType>
00330     long read_matrix_market_file(MatrixType & mat,
00331                                  const std::string & file,
00332                                  long index_base = 1)
00333     {
00334       return read_matrix_market_file_impl(mat, file.c_str(), index_base);
00335     }
00336 
00337     template <typename ScalarType>
00338     long read_matrix_market_file(std::vector< std::map<unsigned int, ScalarType> > & mat,
00339                                  const char * file,
00340                                  long index_base = 1)
00341     {
00342       viennacl::tools::sparse_matrix_adapter<ScalarType> adapted_matrix(mat);
00343       return read_matrix_market_file_impl(adapted_matrix, file, index_base);
00344     }
00345 
00346     template <typename ScalarType>
00347     long read_matrix_market_file(std::vector< std::map<unsigned int, ScalarType> > & mat,
00348                                  const std::string & file,
00349                                  long index_base = 1)
00350     {
00351       viennacl::tools::sparse_matrix_adapter<ScalarType> adapted_matrix(mat);
00352       return read_matrix_market_file_impl(adapted_matrix, file.c_str(), index_base);
00353     }
00354 
00355 
00357     template <typename MatrixType>
00358     void write_matrix_market_file_impl(MatrixType const & mat, const char * file, long index_base)
00359     {
00360       std::ofstream writer(file);
00361 
00362       long num_entries = 0;
00363       for (typename MatrixType::const_iterator1 row_it = mat.begin1();
00364             row_it != mat.end1();
00365             ++row_it)
00366         for (typename MatrixType::const_iterator2 col_it = row_it.begin();
00367               col_it != row_it.end();
00368               ++col_it)
00369           ++num_entries;
00370 
00371       writer << "%%MatrixMarket matrix coordinate real general" << std::endl;
00372       writer << mat.size1() << " " << mat.size2() << " " << num_entries << std::endl;
00373 
00374       for (typename MatrixType::const_iterator1 row_it = mat.begin1();
00375             row_it != mat.end1();
00376             ++row_it)
00377         for (typename MatrixType::const_iterator2 col_it = row_it.begin();
00378               col_it != row_it.end();
00379               ++col_it)
00380           writer << col_it.index1() + index_base << " " << col_it.index2() + index_base << " " << *col_it << std::endl;
00381 
00382       writer.close();
00383     }
00384 
00385     template <typename ScalarType>
00386     void write_matrix_market_file(std::vector< std::map<unsigned int, ScalarType> > const & mat,
00387                                   const char * file,
00388                                   long index_base = 1)
00389     {
00390       viennacl::tools::const_sparse_matrix_adapter<ScalarType> adapted_matrix(mat);
00391       return write_matrix_market_file_impl(adapted_matrix, file, index_base);
00392     }
00393 
00394     template <typename ScalarType>
00395     void write_matrix_market_file(std::vector< std::map<unsigned int, ScalarType> > const & mat,
00396                                   const std::string & file,
00397                                   long index_base = 1)
00398     {
00399       viennacl::tools::const_sparse_matrix_adapter<ScalarType> adapted_matrix(mat);
00400       return write_matrix_market_file_impl(adapted_matrix, file.c_str(), index_base);
00401     }
00402 
00411     template <typename MatrixType>
00412     void write_matrix_market_file(MatrixType const & mat,
00413                                   const std::string & file,
00414                                   long index_base = 1)
00415     {
00416       write_matrix_market_file_impl(mat, file.c_str(), index_base);
00417     }
00418 
00419 
00420   } //namespace io
00421 } //namespace viennacl
00422 
00423 #endif