00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MTL_IO_MATRIX_MARKET_INCLUDE
00013 #define MTL_IO_MATRIX_MARKET_INCLUDE
00014
00015 #include <string>
00016 #include <fstream>
00017 #include <iostream>
00018
00019 #include <boost/utility/enable_if.hpp>
00020 #include <boost/type_traits.hpp>
00021 #include <boost/algorithm/string/case_conv.hpp>
00022 #include <boost/numeric/conversion/cast.hpp>
00023
00024 #include <boost/numeric/mtl/io/matrix_file.hpp>
00025 #include <boost/numeric/mtl/io/read_filter.hpp>
00026 #include <boost/numeric/mtl/utility/property_map.hpp>
00027 #include <boost/numeric/mtl/utility/range_generator.hpp>
00028 #include <boost/numeric/mtl/utility/exception.hpp>
00029 #include <boost/numeric/mtl/utility/tag.hpp>
00030 #include <boost/numeric/mtl/utility/category.hpp>
00031 #include <boost/numeric/mtl/utility/string_to_enum.hpp>
00032 #include <boost/numeric/mtl/matrix/inserter.hpp>
00033 #include <boost/numeric/mtl/operation/set_to_zero.hpp>
00034
00035 namespace mtl { namespace io {
00036
00037
00039 class matrix_market_istream
00040 {
00041 class pattern_type {};
00042 typedef matrix_market_istream self;
00043 public:
00044 explicit matrix_market_istream(const char* p) : new_stream(new std::ifstream(p)), my_stream(*new_stream) {}
00045 explicit matrix_market_istream(const std::string& s) : new_stream(new std::ifstream(s.c_str())), my_stream(*new_stream) {}
00046 explicit matrix_market_istream(std::istream& s= std::cin) : new_stream(0), my_stream(s) {}
00047
00048 ~matrix_market_istream() { if (new_stream) delete new_stream; }
00049
00050 template <typename Coll>
00051 self& operator>>(Coll& c)
00052 {
00053 return read(c, typename mtl::traits::category<Coll>::type());
00054 }
00055
00057 void close() { if (new_stream) new_stream->close(); }
00058
00059 protected:
00060 template <typename Matrix> self& read(Matrix& A, tag::matrix);
00061
00062 void set_symmetry(std::string& symmetry_text)
00063 {
00064 boost::to_lower(symmetry_text);
00065 const char* symmetry_options[]= {"general", "symmetric", "skew-symmetric", "hermitian"};
00066 my_symmetry= string_to_enum(symmetry_text, symmetry_options, symmetry());
00067 }
00068
00069 void set_sparsity(std::string& sparsity_text)
00070 {
00071 boost::to_lower(sparsity_text);
00072 const char* sparsity_options[]= {"coordinate", "array"};
00073 my_sparsity= string_to_enum(sparsity_text, sparsity_options, sparsity());
00074 }
00075
00076 template <typename Inserter, typename Value>
00077 void read_matrix(Inserter& ins, Value)
00078 {
00079 typedef typename Collection<typename Inserter::matrix_type>::size_type size_type;
00080 read_filter<Inserter> filter(ins);
00081 if (my_sparsity == coordinate)
00082
00083 for (std::size_t i= 0; i < nnz; i++) {
00084 size_type r, c;
00085 my_stream >> r >> c;
00086 insert_value(ins, r-1, c-1, filter, Value());
00087 }
00088 else
00089 for (size_type r= 0; r < nrows; r++)
00090 for (size_type c= 0; c < ncols; c++)
00091 insert_value(ins, r, c, filter, Value());
00092 }
00093
00094 template <typename Inserter, typename Filter, typename Value>
00095 void insert_value(Inserter& ins, std::size_t r, std::size_t c, const Filter& filter, Value)
00096 {
00097 typedef typename Collection<typename Inserter::matrix_type>::value_type mvt;
00098 Value v;
00099 read_value(v);
00100
00101 if (filter(r, c))
00102 ins[r][c] << which_value(v, mvt());
00103 if (r != c && filter(c, r))
00104 switch(my_symmetry) {
00105 case symmetric: ins[c][r] << which_value(v, mvt()); break;
00106 case skew: ins[c][r] << -which_value(v, mvt()); break;
00107 case Hermitian: ins[c][r] << conj(which_value(v, mvt())); break;
00108 default: ;
00109 }
00110 }
00111
00112 void read_value(pattern_type) {}
00113 void read_value(double& v) { my_stream >> v;}
00114 void read_value(long& v) { my_stream >> v;}
00115 void read_value(std::complex<double>& v)
00116 {
00117 double r, i; my_stream >> r >> i; v= std::complex<double>(r, i);
00118 }
00119
00120
00121 template <typename Value, typename MValue> MValue which_value(Value v, MValue) { return boost::numeric_cast<MValue>(v); }
00122 template <typename MValue> MValue which_value(pattern_type, MValue) { return boost::numeric_cast<MValue>(0.0); }
00123 template <typename MValue> MValue which_value(std::complex<double> v, MValue) { using std::abs; return boost::numeric_cast<MValue>(abs(v)); }
00124 std::complex<long double> which_value(std::complex<double> v, std::complex<long double>) { return boost::numeric_cast<std::complex<long double> >(v); }
00125 std::complex<double> which_value(std::complex<double> v, std::complex<double>) { return v; }
00126 std::complex<float> which_value(std::complex<double> v, std::complex<float>) { return std::complex<float>(float(real(v)), float(imag(v))); }
00127
00128 std::ifstream *new_stream;
00129 std::istream &my_stream;
00130 enum symmetry {general, symmetric, skew, Hermitian} my_symmetry;
00131 enum sparsity {coordinate, array} my_sparsity;
00132 std::size_t nrows, ncols, nnz;
00133 };
00134
00135
00136
00137
00138 template <typename Matrix>
00139 matrix_market_istream& matrix_market_istream::read(Matrix& A, tag::matrix)
00140 {
00141 std::string marker, type, sparsity_text, value_format, symmetry_text;
00142 my_stream >> marker >> type >> sparsity_text >> value_format >> symmetry_text;
00143 #if 0
00144 std::cout << marker << ", " << type << ", " << sparsity_text << ", "
00145 << value_format << ", " << symmetry_text << "\n";
00146 #endif
00147 MTL_THROW_IF(marker != std::string("%%MatrixMarket"),
00148 runtime_error("File not in Matrix Market format"));
00149 MTL_THROW_IF(type != std::string("matrix"),
00150 runtime_error("Try to read matrix from non-matrix file"));
00151
00152 set_symmetry(symmetry_text);
00153 set_sparsity(sparsity_text);
00154
00155 char first, comment[80];
00156 do {
00157 my_stream >> first;
00158 if (first == '%')
00159 my_stream.getline(comment, 80, '\n');
00160 else
00161 my_stream.putback(first);
00162 } while (first == '%');
00163
00164 my_stream >> nrows >> ncols;
00165 if (sparsity_text == std::string("coordinate"))
00166 my_stream >> nnz;
00167
00168
00169 A.change_dim(nrows, ncols);
00170 set_to_zero(A);
00171
00172
00173 matrix::inserter<Matrix> ins(A, int(double(nnz) / double(A.dim1()) * 1.3));
00174
00175 if (value_format == std::string("real"))
00176 read_matrix(ins, double());
00177 else if (value_format == std::string("integer"))
00178 read_matrix(ins, long());
00179 else if (value_format == std::string("complex"))
00180 read_matrix(ins, std::complex<double>());
00181 else if (value_format == std::string("pattern"))
00182 read_matrix(ins, pattern_type());
00183 else
00184 MTL_THROW(runtime_error("Unknown tag for matrix value type in file"));
00185
00186 return *this;
00187 }
00188
00189
00190 class matrix_market_ostream
00191 {
00192 typedef matrix_market_ostream self;
00193 public:
00194 explicit matrix_market_ostream(const char* p) : new_stream(new std::ofstream(p)), my_stream(*new_stream) {}
00195 explicit matrix_market_ostream(const std::string& s) : new_stream(new std::ofstream(s.c_str())), my_stream(*new_stream) {}
00196 explicit matrix_market_ostream(std::ostream& s= std::cout) : new_stream(0), my_stream(s) {}
00197
00198 ~matrix_market_ostream() { if (new_stream) delete new_stream; }
00199
00200 template <typename Coll>
00201 self& operator<<(const Coll& c)
00202 {
00203 return write(c, typename mtl::traits::category<Coll>::type());
00204 }
00205
00207 void close() { if (new_stream) new_stream->close(); }
00208
00209 private:
00210 template <typename Matrix> self& write(const Matrix& A, tag::matrix)
00211 {
00212 matrix_status_line(A);
00213 if (sparsity(A) == std::string("coordinate "))
00214 return write_sparse_matrix(A);
00215 else
00216 return write_dense_matrix(A);
00217 }
00218
00219 template <typename Matrix> self& write_sparse_matrix(const Matrix& A)
00220 {
00221 my_stream << num_rows(A) << " " << num_cols(A) << " " << A.nnz() << "\n";
00222
00223 typename mtl::traits::row<Matrix>::type row(A);
00224 typename mtl::traits::col<Matrix>::type col(A);
00225 typename mtl::traits::const_value<Matrix>::type value(A);
00226 typedef typename mtl::traits::range_generator<tag::major, Matrix>::type cursor_type;
00227 typedef typename mtl::traits::range_generator<tag::nz, cursor_type>::type icursor_type;
00228
00229 for (cursor_type cursor = begin<tag::major>(A), cend = end<tag::major>(A); cursor != cend; ++cursor)
00230 for (icursor_type icursor = begin<tag::nz>(cursor), icend = end<tag::nz>(cursor); icursor != icend; ++icursor)
00231 my_stream << row(*icursor)+1 << " " << col(*icursor)+1 << " ", write_value(value(*icursor)), my_stream << "\n";
00232 return *this;
00233 }
00234
00235 template <typename Matrix> self& write_dense_matrix(const Matrix& A)
00236 {
00237 my_stream << num_rows(A) << " " << num_cols(A) << "\n";
00238 for (std::size_t r = 0; r < num_rows(A); ++r) {
00239 for (std::size_t c = 0; c < num_cols(A); ++c)
00240 write_value(A[r][c]), my_stream << " ";
00241 my_stream << "\n";
00242 }
00243 return *this;
00244 }
00245
00246 template <typename Value>
00247 typename boost::enable_if<boost::is_integral<Value> >::type
00248 write_value(const Value& v) { my_stream << v; }
00249
00250 template <typename Value>
00251 typename boost::enable_if<boost::is_floating_point<Value> >::type
00252 write_value(const Value& v)
00253 {
00254 my_stream.setf(std::ios::scientific);
00255 my_stream << v;
00256 my_stream.unsetf(std::ios::scientific);
00257 }
00258
00259 template <typename Value>
00260 void write_value(const std::complex<Value>& v)
00261 {
00262 my_stream.setf(std::ios::scientific);
00263 my_stream << real(v) << " " << imag(v);
00264 my_stream.unsetf(std::ios::scientific);
00265 }
00266
00267
00268 template <typename Matrix>
00269 std::string symmetry(const Matrix&) const { return std::string("general\n"); }
00270
00271 template <typename Matrix>
00272 std::string sparsity(const Matrix&) const
00273 {
00274 return std::string( mtl::traits::is_sparse<Matrix>::value ? "coordinate " : "array " );
00275 }
00276
00277 template <typename Value>
00278 typename boost::enable_if<boost::is_integral<Value>, std::string>::type
00279 value(const Value&) const { return std::string("integer "); }
00280
00281 template <typename Value>
00282 typename boost::enable_if<boost::is_floating_point<Value>, std::string>::type
00283 value(const Value&) const { return std::string("real "); }
00284
00285 template <typename Value>
00286 std::string value(const std::complex<Value>&) const { return std::string("complex "); }
00287
00288 template <typename Matrix>
00289 void matrix_status_line(const Matrix& A) const
00290 {
00291 typedef typename Collection<Matrix>::value_type value_type;
00292 std::string st(std::string("%%MatrixMarket matrix ") + sparsity(A) + value(value_type()) + symmetry(A));
00293 my_stream << st;
00294 }
00295
00296 protected:
00297 std::ofstream *new_stream;
00298 std::ostream &my_stream;
00299 };
00300
00301
00302 }}
00303
00304 #endif // MTL_IO_MATRIX_MARKET_INCLUDE