dune-istl  2.11
matrixmarket.hh
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 // vi: set et ts=4 sw=2 sts=2:
5 #ifndef DUNE_ISTL_MATRIXMARKET_HH
6 #define DUNE_ISTL_MATRIXMARKET_HH
7 
8 #include <algorithm>
9 #include <complex>
10 #include <cstddef>
11 #include <fstream>
12 #include <ios>
13 #include <iostream>
14 #include <istream>
15 #include <limits>
16 #include <ostream>
17 #include <set>
18 #include <sstream>
19 #include <string>
20 #include <tuple>
21 #include <type_traits>
22 #include <vector>
23 
24 #include <dune/common/exceptions.hh>
25 #include <dune/common/fmatrix.hh>
26 #include <dune/common/fvector.hh>
27 #include <dune/common/gmpfield.hh>
28 #include <dune/common/hybridutilities.hh>
29 #include <dune/common/quadmath.hh>
30 #include <dune/common/stdstreams.hh>
31 #include <dune/common/simd/simd.hh>
32 
33 #include <dune/istl/bcrsmatrix.hh>
34 #include <dune/istl/bvector.hh>
35 #include <dune/istl/matrixutils.hh> // countNonZeros()
37 
38 namespace Dune
39 {
40 
66  namespace MatrixMarketImpl
67  {
77  template<class T>
78  struct mm_numeric_type {
79  enum {
83  is_numeric=false
84  };
85 
86  static std::string str()
87  {
88  return "unknown";
89  }
90  };
91 
92  template<>
93  struct mm_numeric_type<int>
94  {
95  enum {
100  };
101 
102  static std::string str()
103  {
104  return "integer";
105  }
106  };
107 
108  template<>
109  struct mm_numeric_type<double>
110  {
111  enum {
116  };
117 
118  static std::string str()
119  {
120  return "real";
121  }
122  };
123 
124  template<>
125  struct mm_numeric_type<float>
126  {
127  enum {
132  };
133 
134  static std::string str()
135  {
136  return "real";
137  }
138  };
139 
140 #if HAVE_GMP
141  template<unsigned int precision>
142  struct mm_numeric_type<Dune::GMPField<precision>>
143  {
144  enum {
148  is_numeric=true
149  };
150 
151  static std::string str()
152  {
153  return "real";
154  }
155  };
156 #endif
157 
158 #if HAVE_QUADMATH
159  template<>
160  struct mm_numeric_type<Dune::Float128>
161  {
162  enum {
166  is_numeric=true
167  };
168 
169  static std::string str()
170  {
171  return "real";
172  }
173  };
174 #endif
175 
176  template<>
177  struct mm_numeric_type<std::complex<double> >
178  {
179  enum {
184  };
185 
186  static std::string str()
187  {
188  return "complex";
189  }
190  };
191 
192  template<>
193  struct mm_numeric_type<std::complex<float> >
194  {
195  enum {
200  };
201 
202  static std::string str()
203  {
204  return "complex";
205  }
206  };
207 
216  template<class M>
218 
219  template<typename T, typename A>
221  {
222  static void print(std::ostream& os)
223  {
224  os<<"%%MatrixMarket matrix coordinate ";
225  os<<mm_numeric_type<Simd::Scalar<typename Imp::BlockTraits<T>::field_type>>::str()<<" general"<<std::endl;
226  }
227  };
228 
229  template<typename B, typename A>
231  {
232  static void print(std::ostream& os)
233  {
234  os<<"%%MatrixMarket matrix array ";
235  os<<mm_numeric_type<Simd::Scalar<typename Imp::BlockTraits<B>::field_type>>::str()<<" general"<<std::endl;
236  }
237  };
238 
239  template<typename T, int j>
240  struct mm_header_printer<FieldVector<T,j> >
241  {
242  static void print(std::ostream& os)
243  {
244  os<<"%%MatrixMarket matrix array ";
245  os<<mm_numeric_type<T>::str()<<" general"<<std::endl;
246  }
247  };
248 
249  template<typename T, int i, int j>
251  {
252  static void print(std::ostream& os)
253  {
254  os<<"%%MatrixMarket matrix array ";
255  os<<mm_numeric_type<T>::str()<<" general"<<std::endl;
256  }
257  };
258 
267  template<class M>
269 
270  template<typename T, typename A>
272  {
274  static_assert(IsNumber<T>::value, "Only scalar entries are expected here!");
275 
276  static void print(std::ostream& os, const M&)
277  {
278  os<<"% ISTL_STRUCT blocked ";
279  os<<"1 1"<<std::endl;
280  }
281  };
282 
283  template<typename T, typename A, int i>
284  struct mm_block_structure_header<BlockVector<FieldVector<T,i>,A> >
285  {
287 
288  static void print(std::ostream& os, const M&)
289  {
290  os<<"% ISTL_STRUCT blocked ";
291  os<<i<<" "<<1<<std::endl;
292  }
293  };
294 
295  template<typename T, typename A>
297  {
299  static_assert(IsNumber<T>::value, "Only scalar entries are expected here!");
300 
301  static void print(std::ostream& os, const M&)
302  {
303  os<<"% ISTL_STRUCT blocked ";
304  os<<"1 1"<<std::endl;
305  }
306  };
307 
308  template<typename T, typename A, int i, int j>
310  {
312 
313  static void print(std::ostream& os, const M&)
314  {
315  os<<"% ISTL_STRUCT blocked ";
316  os<<i<<" "<<j<<std::endl;
317  }
318  };
319 
320 
321  template<typename T, int i, int j>
323  {
325 
326  static void print(std::ostream& /*os*/, const M& /*m*/)
327  {}
328  };
329 
330  template<typename T, int i>
331  struct mm_block_structure_header<FieldVector<T,i> >
332  {
333  typedef FieldVector<T,i> M;
334 
335  static void print(std::ostream& /*os*/, const M& /*m*/)
336  {}
337  };
338 
340  enum { MM_MAX_LINE_LENGTH=1025 };
341 
343 
345 
347 
348  struct MMHeader
349  {
352  {}
356  };
357 
358  inline bool lineFeed(std::istream& file)
359  {
360  char c;
361  if(!file.eof())
362  c=file.peek();
363  else
364  return false;
365  // ignore whitespace
366  while(c==' ')
367  {
368  file.get();
369  if(file.eof())
370  return false;
371  c=file.peek();
372  }
373 
374  if(c=='\n') {
375  /* eat the line feed */
376  file.get();
377  return true;
378  }
379  return false;
380  }
381 
382  inline void skipComments(std::istream& file)
383  {
384  lineFeed(file);
385  char c=file.peek();
386  // ignore comment lines
387  while(c=='%')
388  {
389  /* discard the rest of the line */
390  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
391  c=file.peek();
392  }
393  }
394 
395 
396  inline bool readMatrixMarketBanner(std::istream& file, MMHeader& mmHeader)
397  {
398  std::string buffer;
399  char c;
400  file >> buffer;
401  c=buffer[0];
402  mmHeader=MMHeader();
403  if(c!='%')
404  return false;
405  dverb<<buffer<<std::endl;
406  /* read the banner */
407  if(buffer!="%%MatrixMarket") {
408  /* discard the rest of the line */
409  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
410  return false;
411  }
412 
413  if(lineFeed(file))
414  /* premature end of line */
415  return false;
416 
417  /* read the matrix_type */
418  file >> buffer;
419 
420  if(buffer != "matrix")
421  {
422  /* discard the rest of the line */
423  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
424  return false;
425  }
426 
427  if(lineFeed(file))
428  /* premature end of line */
429  return false;
430 
431  /* The type of the matrix */
432  file >> buffer;
433 
434  if(buffer.empty())
435  return false;
436 
437  std::transform(buffer.begin(), buffer.end(), buffer.begin(),
438  ::tolower);
439 
440  switch(buffer[0])
441  {
442  case 'a' :
443  /* sanity check */
444  if(buffer != "array")
445  {
446  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
447  return false;
448  }
449  mmHeader.type=array_type;
450  break;
451  case 'c' :
452  /* sanity check */
453  if(buffer != "coordinate")
454  {
455  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
456  return false;
457  }
458  mmHeader.type=coordinate_type;
459  break;
460  default :
461  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
462  return false;
463  }
464 
465  if(lineFeed(file))
466  /* premature end of line */
467  return false;
468 
469  /* The numeric type used. */
470  file >> buffer;
471 
472  if(buffer.empty())
473  return false;
474 
475  std::transform(buffer.begin(), buffer.end(), buffer.begin(),
476  ::tolower);
477  switch(buffer[0])
478  {
479  case 'i' :
480  /* sanity check */
481  if(buffer != "integer")
482  {
483  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
484  return false;
485  }
486  mmHeader.ctype=integer_type;
487  break;
488  case 'r' :
489  /* sanity check */
490  if(buffer != "real")
491  {
492  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
493  return false;
494  }
495  mmHeader.ctype=double_type;
496  break;
497  case 'c' :
498  /* sanity check */
499  if(buffer != "complex")
500  {
501  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
502  return false;
503  }
504  mmHeader.ctype=complex_type;
505  break;
506  case 'p' :
507  /* sanity check */
508  if(buffer != "pattern")
509  {
510  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
511  return false;
512  }
513  mmHeader.ctype=pattern;
514  break;
515  default :
516  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
517  return false;
518  }
519 
520  if(lineFeed(file))
521  return false;
522 
523  file >> buffer;
524 
525  std::transform(buffer.begin(), buffer.end(), buffer.begin(),
526  ::tolower);
527  switch(buffer[0])
528  {
529  case 'g' :
530  /* sanity check */
531  if(buffer != "general")
532  {
533  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
534  return false;
535  }
536  mmHeader.structure=general;
537  break;
538  case 'h' :
539  /* sanity check */
540  if(buffer != "hermitian")
541  {
542  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
543  return false;
544  }
545  mmHeader.structure=hermitian;
546  break;
547  case 's' :
548  if(buffer.size()==1) {
549  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
550  return false;
551  }
552 
553  switch(buffer[1])
554  {
555  case 'y' :
556  /* sanity check */
557  if(buffer != "symmetric")
558  {
559  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
560  return false;
561  }
562  mmHeader.structure=symmetric;
563  break;
564  case 'k' :
565  /* sanity check */
566  if(buffer != "skew-symmetric")
567  {
568  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
569  return false;
570  }
571  mmHeader.structure=skew_symmetric;
572  break;
573  default :
574  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
575  return false;
576  }
577  break;
578  default :
579  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
580  return false;
581  }
582  file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
583  c=file.peek();
584  return true;
585 
586  }
587 
588  template<std::size_t brows, std::size_t bcols>
589  std::tuple<std::size_t, std::size_t, std::size_t>
590  calculateNNZ(std::size_t rows, std::size_t cols, std::size_t entries, const MMHeader& header)
591  {
592  std::size_t blockrows=rows/brows;
593  std::size_t blockcols=cols/bcols;
594  std::size_t blocksize=brows*bcols;
595  std::size_t blockentries=0;
596 
597  switch(header.structure)
598  {
599  case general :
600  blockentries = entries/blocksize; break;
601  case skew_symmetric :
602  blockentries = 2*entries/blocksize; break;
603  case symmetric :
604  blockentries = (2*entries-rows)/blocksize; break;
605  case hermitian :
606  blockentries = (2*entries-rows)/blocksize; break;
607  default :
608  throw Dune::NotImplemented();
609  }
610  return std::make_tuple(blockrows, blockcols, blockentries);
611  }
612 
613  /*
614  * @brief Storage class for the column index and the numeric value.
615  *
616  * \tparam T Either a NumericWrapper of the numeric type or PatternDummy
617  * for MatrixMarket pattern case.
618  */
619  template<typename T>
620  struct IndexData : public T
621  {
622  std::size_t index = {};
623  };
624 
625 
636  template<typename T>
638  {
639  T number = {};
640  operator T&()
641  {
642  return number;
643  }
644  };
645 
650  {};
651 
652  template<>
654  {};
655 
656  template<typename T>
657  std::istream& operator>>(std::istream& is, NumericWrapper<T>& num)
658  {
659  return is>>num.number;
660  }
661 
662  inline std::istream& operator>>(std::istream& is, [[maybe_unused]] NumericWrapper<PatternDummy>& num)
663  {
664  return is;
665  }
666 
672  template<typename T>
673  bool operator<(const IndexData<T>& i1, const IndexData<T>& i2)
674  {
675  return i1.index<i2.index;
676  }
677 
683  template<typename T>
684  std::istream& operator>>(std::istream& is, IndexData<T>& data)
685  {
686  is>>data.index;
687  /* MatrixMarket indices are one based. Decrement for C++ */
688  --data.index;
689  return is>>data.number;
690  }
691 
697  template<typename T>
698  std::istream& operator>>(std::istream& is, IndexData<NumericWrapper<std::complex<T>>>& data)
699  {
700  is>>data.index;
701  /* MatrixMarket indices are one based. Decrement for C++ */
702  --data.index;
703  // real and imaginary part needs to be read separately as
704  // complex numbers are not provided in pair form. (x,y)
705  NumericWrapper<T> real, imag;
706  is>>real;
707  is>>imag;
708  data.number = {real.number, imag.number};
709  return is;
710  }
711 
718  template<typename D, int brows, int bcols>
720  {
726  template<typename T>
727  void operator()(const std::vector<std::set<IndexData<D> > >& rows,
728  BCRSMatrix<T>& matrix)
729  {
730  static_assert(IsNumber<T>::value && brows==1 && bcols==1, "Only scalar entries are expected here!");
731  for (auto iter=matrix.begin(); iter!= matrix.end(); ++iter)
732  {
733  auto brow=iter.index();
734  for (auto siter=rows[brow].begin(); siter != rows[brow].end(); ++siter)
735  (*iter)[siter->index] = siter->number;
736  }
737  }
738 
744  template<typename T>
745  void operator()(const std::vector<std::set<IndexData<D> > >& rows,
747  {
748  for (auto iter=matrix.begin(); iter!= matrix.end(); ++iter)
749  {
750  for (auto brow=iter.index()*brows,
751  browend=iter.index()*brows+brows;
752  brow<browend; ++brow)
753  {
754  for (auto siter=rows[brow].begin(), send=rows[brow].end();
755  siter != send; ++siter)
756  (*iter)[siter->index/bcols][brow%brows][siter->index%bcols]=siter->number;
757  }
758  }
759  }
760  };
761 
762  template<int brows, int bcols>
763  struct MatrixValuesSetter<PatternDummy,brows,bcols>
764  {
765  template<typename M>
766  void operator()(const std::vector<std::set<IndexData<PatternDummy> > >& /*rows*/,
767  M& /*matrix*/)
768  {}
769  };
770 
771  template<class T> struct is_complex : std::false_type {};
772  template<class T> struct is_complex<std::complex<T>> : std::true_type {};
773 
774  // wrapper for std::conj. Returns T if T is not complex.
775  template<class T>
776  std::enable_if_t<!is_complex<T>::value, T> conj(const T& r){
777  return r;
778  }
779 
780  template<class T>
781  std::enable_if_t<is_complex<T>::value, T> conj(const T& r){
782  return std::conj(r);
783  }
784 
785  template<typename M>
787  {};
788 
789  template<typename B, typename A>
791  {
792  enum {
793  rows = 1,
794  cols = 1
795  };
796  };
797 
798  template<typename B, int i, int j, typename A>
800  {
801  enum {
802  rows = i,
803  cols = j
804  };
805  };
806 
807  template<typename T, typename A, typename D>
809  std::istream& file, std::size_t entries,
810  const MMHeader& mmHeader, const D&)
811  {
813 
814  // Number of rows and columns of T, if it is a matrix (1x1 otherwise)
815  constexpr int brows = mm_multipliers<Matrix>::rows;
816  constexpr int bcols = mm_multipliers<Matrix>::cols;
817 
818  // First path
819  // store entries together with column index in a separate
820  // data structure
821  std::vector<std::set<IndexData<D> > > rows(matrix.N()*brows);
822 
823  auto readloop = [&] (auto symmetryFixup) {
824  for(std::size_t i = 0; i < entries; ++i) {
825  std::size_t row;
826  IndexData<D> data;
827  skipComments(file);
828  file>>row;
829  --row; // Index was 1 based.
830  assert(row/bcols<matrix.N());
831  file>>data;
832  assert(data.index/bcols<matrix.M());
833  rows[row].insert(data);
834  if(row!=data.index)
835  symmetryFixup(row, data);
836  }
837  };
838 
839  switch(mmHeader.structure)
840  {
841  case general:
842  readloop([](auto...){});
843  break;
844  case symmetric :
845  readloop([&](auto row, auto data) {
846  IndexData<D> data_sym(data);
847  data_sym.index = row;
848  rows[data.index].insert(data_sym);
849  });
850  break;
851  case skew_symmetric :
852  readloop([&](auto row, auto data) {
853  IndexData<D> data_sym;
854  data_sym.number = -data.number;
855  data_sym.index = row;
856  rows[data.index].insert(data_sym);
857  });
858  break;
859  case hermitian :
860  readloop([&](auto row, auto data) {
861  IndexData<D> data_sym;
862  data_sym.number = conj(data.number);
863  data_sym.index = row;
864  rows[data.index].insert(data_sym);
865  });
866  break;
867  default:
868  DUNE_THROW(Dune::NotImplemented,
869  "Only general, symmetric, skew-symmetric and hermitian is supported right now!");
870  }
871 
872  // Setup the matrix sparsity pattern
873  int nnz=0;
874  for(typename Matrix::CreateIterator iter=matrix.createbegin();
875  iter!= matrix.createend(); ++iter)
876  {
877  for(std::size_t brow=iter.index()*brows, browend=iter.index()*brows+brows;
878  brow<browend; ++brow)
879  {
880  typedef typename std::set<IndexData<D> >::const_iterator Siter;
881  for(Siter siter=rows[brow].begin(), send=rows[brow].end();
882  siter != send; ++siter, ++nnz)
883  iter.insert(siter->index/bcols);
884  }
885  }
886 
887  //Set the matrix values
888  matrix=0;
889 
891 
892  Setter(rows, matrix);
893  }
894 
895  inline std::tuple<std::string, std::string> splitFilename(const std::string& filename) {
896  std::size_t lastdot = filename.find_last_of(".");
897  if(lastdot == std::string::npos)
898  return std::make_tuple(filename, "");
899  else {
900  std::string potentialFileExtension = filename.substr(lastdot);
901  if (potentialFileExtension == ".mm" || potentialFileExtension == ".mtx")
902  return std::make_tuple(filename.substr(0, lastdot), potentialFileExtension);
903  else
904  return std::make_tuple(filename, "");
905  }
906  }
907 
908  } // end namespace MatrixMarketImpl
909 
910  class MatrixMarketFormatError : public Dune::Exception
911  {};
912 
913 
914  inline void mm_read_header(std::size_t& rows, std::size_t& cols,
915  MatrixMarketImpl::MMHeader& header, std::istream& istr,
916  bool isVector)
917  {
918  using namespace MatrixMarketImpl;
919 
920  if(!readMatrixMarketBanner(istr, header)) {
921  std::cerr << "First line was not a correct Matrix Market banner. Using default:\n"
922  << "%%MatrixMarket matrix coordinate real general"<<std::endl;
923  // Go to the beginning of the file
924  istr.clear() ;
925  istr.seekg(0, std::ios::beg);
926  if(isVector)
927  header.type=array_type;
928  }
929 
930  skipComments(istr);
931 
932  if(lineFeed(istr))
933  throw MatrixMarketFormatError();
934 
935  istr >> rows;
936 
937  if(lineFeed(istr))
938  throw MatrixMarketFormatError();
939  istr >> cols;
940  }
941 
942  template<typename T, typename A>
944  std::size_t size,
945  std::istream& istr,
946  size_t lane)
947  {
948  for (int i=0; size>0; ++i, --size)
949  istr>>Simd::lane(lane,vector[i]);
950  }
951 
952  template<typename T, typename A, int entries>
953  void mm_read_vector_entries(Dune::BlockVector<Dune::FieldVector<T,entries>,A>& vector,
954  std::size_t size,
955  std::istream& istr,
956  size_t lane)
957  {
958  for(int i=0; size>0; ++i, --size) {
959  Simd::Scalar<T> val;
960  istr>>val;
961  Simd::lane(lane, vector[i/entries][i%entries])=val;
962  }
963  }
964 
965 
972  template<typename T, typename A>
974  std::istream& istr)
975  {
976  typedef typename Dune::BlockVector<T,A>::field_type field_type;
977  using namespace MatrixMarketImpl;
978 
979  MMHeader header;
980  std::size_t rows, cols;
981  mm_read_header(rows,cols,header,istr, true);
982  if(cols!=Simd::lanes<field_type>()) {
983  if(Simd::lanes<field_type>() == 1)
984  DUNE_THROW(MatrixMarketFormatError, "cols!=1, therefore this is no vector!");
985  else
986  DUNE_THROW(MatrixMarketFormatError, "cols does not match the number of lanes in the field_type!");
987  }
988 
989  if(header.type!=array_type)
990  DUNE_THROW(MatrixMarketFormatError, "Vectors have to be stored in array format!");
991 
992 
993  if constexpr (Dune::IsNumber<T>())
994  vector.resize(rows);
995  else
996  {
997  T dummy;
998  auto blocksize = dummy.size();
999  std::size_t size=rows/blocksize;
1000  if(size*blocksize!=rows)
1001  DUNE_THROW(MatrixMarketFormatError, "Block size of vector is not correct!");
1002 
1003  vector.resize(size);
1004  }
1005 
1006  istr.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
1007  for(size_t l=0;l<Simd::lanes<field_type>();++l){
1008  mm_read_vector_entries(vector, rows, istr, l);
1009  }
1010  }
1011 
1018  template<typename T, typename A>
1020  std::istream& istr)
1021  {
1022  using namespace MatrixMarketImpl;
1023  using Matrix = Dune::BCRSMatrix<T,A>;
1024 
1025  MMHeader header;
1026  if(!readMatrixMarketBanner(istr, header)) {
1027  std::cerr << "First line was not a correct Matrix Market banner. Using default:\n"
1028  << "%%MatrixMarket matrix coordinate real general"<<std::endl;
1029  // Go to the beginning of the file
1030  istr.clear() ;
1031  istr.seekg(0, std::ios::beg);
1032  }
1033  skipComments(istr);
1034 
1035  std::size_t rows, cols, entries;
1036 
1037  if(lineFeed(istr))
1038  throw MatrixMarketFormatError();
1039 
1040  istr >> rows;
1041 
1042  if(lineFeed(istr))
1043  throw MatrixMarketFormatError();
1044  istr >> cols;
1045 
1046  if(lineFeed(istr))
1047  throw MatrixMarketFormatError();
1048 
1049  istr >>entries;
1050 
1051  std::size_t nnz, blockrows, blockcols;
1052 
1053  // Number of rows and columns of T, if it is a matrix (1x1 otherwise)
1054  constexpr int brows = mm_multipliers<Matrix>::rows;
1055  constexpr int bcols = mm_multipliers<Matrix>::cols;
1056 
1057  std::tie(blockrows, blockcols, nnz) = calculateNNZ<brows, bcols>(rows, cols, entries, header);
1058 
1059  istr.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
1060 
1061 
1062  matrix.setSize(blockrows, blockcols, nnz);
1064 
1065  if(header.type==array_type)
1066  DUNE_THROW(Dune::NotImplemented, "Array format currently not supported for matrices!");
1067 
1068  readSparseEntries(matrix, istr, entries, header, NumericWrapper<typename Matrix::field_type>());
1069  }
1070 
1071  // Print a scalar entry
1072  template<typename B>
1073  void mm_print_entry(const B& entry,
1074  std::size_t rowidx,
1075  std::size_t colidx,
1076  std::ostream& ostr)
1077  {
1078  if constexpr (IsNumber<B>())
1079  ostr << rowidx << " " << colidx << " " << entry << std::endl;
1080  else
1081  {
1082  for (auto row=entry.begin(); row != entry.end(); ++row, ++rowidx) {
1083  int coli=colidx;
1084  for (auto col = row->begin(); col != row->end(); ++col, ++coli)
1085  ostr<< rowidx<<" "<<coli<<" "<<*col<<std::endl;
1086  }
1087  }
1088  }
1089 
1090  // Write a vector entry
1091  template<typename V>
1092  void mm_print_vector_entry(const V& entry, std::ostream& ostr,
1093  const std::integral_constant<int,1>&,
1094  size_t lane)
1095  {
1096  ostr<<Simd::lane(lane,entry)<<std::endl;
1097  }
1098 
1099  // Write a vector
1100  template<typename V>
1101  void mm_print_vector_entry(const V& vector, std::ostream& ostr,
1102  const std::integral_constant<int,0>&,
1103  size_t lane)
1104  {
1105  using namespace MatrixMarketImpl;
1106 
1107  // Is the entry a supported numeric type?
1108  const int isnumeric = mm_numeric_type<Simd::Scalar<typename V::block_type>>::is_numeric;
1109  typedef typename V::const_iterator VIter;
1110 
1111  for(VIter i=vector.begin(); i != vector.end(); ++i)
1112 
1113  mm_print_vector_entry(*i, ostr,
1114  std::integral_constant<int,isnumeric>(),
1115  lane);
1116  }
1117 
1118  template<typename T, typename A>
1119  std::size_t countEntries(const BlockVector<T,A>& vector)
1120  {
1121  return vector.size();
1122  }
1123 
1124  template<typename T, typename A, int i>
1125  std::size_t countEntries(const BlockVector<FieldVector<T,i>,A>& vector)
1126  {
1127  return vector.size()*i;
1128  }
1129 
1130  // Version for writing vectors.
1131  template<typename V>
1132  void writeMatrixMarket(const V& vector, std::ostream& ostr,
1133  const std::integral_constant<int,0>&)
1134  {
1135  using namespace MatrixMarketImpl;
1136  typedef typename V::field_type field_type;
1137 
1138  ostr<<countEntries(vector)<<" "<<Simd::lanes<field_type>()<<std::endl;
1139  const int isnumeric = mm_numeric_type<Simd::Scalar<V>>::is_numeric;
1140  for(size_t l=0;l<Simd::lanes<field_type>(); ++l){
1141  mm_print_vector_entry(vector,ostr, std::integral_constant<int,isnumeric>(), l);
1142  }
1143  }
1144 
1145  // Versions for writing matrices
1146  template<typename M>
1147  void writeMatrixMarket(const M& matrix,
1148  std::ostream& ostr,
1149  const std::integral_constant<int,1>&)
1150  {
1151  ostr<<matrix.N()*MatrixMarketImpl::mm_multipliers<M>::rows<<" "
1153  <<countNonZeros(matrix)<<std::endl;
1154 
1155  typedef typename M::const_iterator riterator;
1156  typedef typename M::ConstColIterator citerator;
1157  for(riterator row=matrix.begin(); row != matrix.end(); ++row)
1158  for(citerator col = row->begin(); col != row->end(); ++col)
1159  // Matrix Market indexing start with 1!
1162  }
1163 
1164 
1168  template<typename M>
1169  void writeMatrixMarket(const M& matrix,
1170  std::ostream& ostr)
1171  {
1172  using namespace MatrixMarketImpl;
1173 
1174  // Write header information
1175  mm_header_printer<M>::print(ostr);
1176  mm_block_structure_header<M>::print(ostr,matrix);
1177  // Choose the correct function for matrix and vector
1178  writeMatrixMarket(matrix,ostr,std::integral_constant<int,IsMatrix<M>::value>());
1179  }
1180 
1181  static const int default_precision = -1;
1193  template<typename M>
1194  void storeMatrixMarket(const M& matrix,
1195  std::string filename,
1196  int prec=default_precision)
1197  {
1198  auto [pureFilename, extension] = MatrixMarketImpl::splitFilename(filename);
1199  std::string rfilename;
1200  std::ofstream file;
1201  if (extension != "") {
1202  rfilename = pureFilename + extension;
1203  file.open(rfilename.c_str());
1204  if(!file)
1205  DUNE_THROW(IOError, "Could not open file for storage: " << rfilename.c_str());
1206  }
1207  else {
1208  // only try .mm so we do not ignore potential errors
1209  rfilename = pureFilename + ".mm";
1210  file.open(rfilename.c_str());
1211  if(!file)
1212  DUNE_THROW(IOError, "Could not open file for storage: " << rfilename.c_str());
1213  }
1214 
1215  file.setf(std::ios::scientific,std::ios::floatfield);
1216  if(prec>0)
1217  file.precision(prec);
1218  writeMatrixMarket(matrix, file);
1219  file.close();
1220  }
1221 
1222 #if HAVE_MPI
1223 
1237  template<typename M, typename G, typename L>
1238  void storeMatrixMarket(const M& matrix,
1239  std::string filename,
1241  bool storeIndices=true,
1242  int prec=default_precision)
1243  {
1244  // Get our rank
1245  int rank = comm.communicator().rank();
1246  // Write the local matrix
1247  auto [pureFilename, extension] = MatrixMarketImpl::splitFilename(filename);
1248  std::string rfilename;
1249  std::ofstream file;
1250  if (extension != "") {
1251  rfilename = pureFilename + "_" + std::to_string(rank) + extension;
1252  file.open(rfilename.c_str());
1253  dverb<< rfilename <<std::endl;
1254  if(!file)
1255  DUNE_THROW(IOError, "Could not open file for storage: " << rfilename.c_str());
1256  }
1257  else {
1258  // only try .mm so we do not ignore potential errors
1259  rfilename = pureFilename + "_" + std::to_string(rank) + ".mm";
1260  file.open(rfilename.c_str());
1261  dverb<< rfilename <<std::endl;
1262  if(!file)
1263  DUNE_THROW(IOError, "Could not open file for storage: " << rfilename.c_str());
1264  }
1265  file.setf(std::ios::scientific,std::ios::floatfield);
1266  if(prec>0)
1267  file.precision(prec);
1268  writeMatrixMarket(matrix, file);
1269  file.close();
1270 
1271  if(!storeIndices)
1272  return;
1273 
1274  // Write the global to local index mapping
1275  rfilename = pureFilename + "_" + std::to_string(rank) + ".idx";
1276  file.open(rfilename.c_str());
1277  if(!file)
1278  DUNE_THROW(IOError, "Could not open file for storage: " << rfilename.c_str());
1279  file.setf(std::ios::scientific,std::ios::floatfield);
1280  typedef typename OwnerOverlapCopyCommunication<G,L>::ParallelIndexSet IndexSet;
1281  typedef typename IndexSet::const_iterator Iterator;
1282  for(Iterator iter = comm.indexSet().begin();
1283  iter != comm.indexSet().end(); ++iter) {
1284  file << iter->global()<<" "<<(std::size_t)iter->local()<<" "
1285  <<(int)iter->local().attribute()<<" "<<(int)iter->local().isPublic()<<std::endl;
1286  }
1287  // Store neighbour information for efficient remote indices setup.
1288  file<<"neighbours:";
1289  const std::set<int>& neighbours=comm.remoteIndices().getNeighbours();
1290  typedef std::set<int>::const_iterator SIter;
1291  for(SIter neighbour=neighbours.begin(); neighbour != neighbours.end(); ++neighbour) {
1292  file<<" "<< *neighbour;
1293  }
1294  file.close();
1295  }
1296 
1311  template<typename M, typename G, typename L>
1312  void loadMatrixMarket(M& matrix,
1313  const std::string& filename,
1315  bool readIndices=true)
1316  {
1317  using namespace MatrixMarketImpl;
1318 
1320  typedef typename LocalIndexT::Attribute Attribute;
1321  // Get our rank
1322  int rank = comm.communicator().rank();
1323  // load local matrix
1324  auto [pureFilename, extension] = MatrixMarketImpl::splitFilename(filename);
1325  std::string rfilename;
1326  std::ifstream file;
1327  if (extension != "") {
1328  rfilename = pureFilename + "_" + std::to_string(rank) + extension;
1329  file.open(rfilename.c_str(), std::ios::in);
1330  dverb<< rfilename <<std::endl;
1331  if(!file)
1332  DUNE_THROW(IOError, "Could not open file: " << rfilename.c_str());
1333  }
1334  else {
1335  // try both .mm and .mtx
1336  rfilename = pureFilename + "_" + std::to_string(rank) + ".mm";
1337  file.open(rfilename.c_str(), std::ios::in);
1338  if(!file) {
1339  rfilename = pureFilename + "_" + std::to_string(rank) + ".mtx";
1340  file.open(rfilename.c_str(), std::ios::in);
1341  dverb<< rfilename <<std::endl;
1342  if(!file)
1343  DUNE_THROW(IOError, "Could not open file: " << rfilename.c_str());
1344  }
1345  }
1346  readMatrixMarket(matrix,file);
1347  file.close();
1348 
1349  if(!readIndices)
1350  return;
1351 
1352  // read indices
1353  typedef typename OwnerOverlapCopyCommunication<G,L>::ParallelIndexSet IndexSet;
1354  IndexSet& pis=comm.pis;
1355  rfilename = pureFilename + "_" + std::to_string(rank) + ".idx";
1356  file.open(rfilename.c_str());
1357  if(!file)
1358  DUNE_THROW(IOError, "Could not open file: " << rfilename.c_str());
1359  if(pis.size()!=0)
1360  DUNE_THROW(InvalidIndexSetState, "Index set is not empty!");
1361 
1362  pis.beginResize();
1363  while(!file.eof() && file.peek()!='n') {
1364  G g;
1365  file >>g;
1366  std::size_t l;
1367  file >>l;
1368  int c;
1369  file >>c;
1370  bool b;
1371  file >> b;
1372  pis.add(g,LocalIndexT(l,Attribute(c),b));
1373  lineFeed(file);
1374  }
1375  pis.endResize();
1376  if(!file.eof()) {
1377  // read neighbours
1378  std::string s;
1379  file>>s;
1380  if(s!="neighbours:")
1381  DUNE_THROW(MatrixMarketFormatError, "was expecting the string: \"neighbours:\"");
1382  std::set<int> nb;
1383  while(!file.eof()) {
1384  int i;
1385  file >> i;
1386  nb.insert(i);
1387  }
1388  file.close();
1389  comm.ri.setNeighbours(nb);
1390  }
1391  comm.ri.template rebuild<false>();
1392  }
1393 
1394  #endif
1395 
1406  template<typename M>
1407  void loadMatrixMarket(M& matrix,
1408  const std::string& filename)
1409  {
1410  auto [pureFilename, extension] = MatrixMarketImpl::splitFilename(filename);
1411  std::string rfilename;
1412  std::ifstream file;
1413  if (extension != "") {
1414  rfilename = pureFilename + extension;
1415  file.open(rfilename.c_str());
1416  if(!file)
1417  DUNE_THROW(IOError, "Could not open file: " << rfilename.c_str());
1418  }
1419  else {
1420  // try both .mm and .mtx
1421  rfilename = pureFilename + ".mm";
1422  file.open(rfilename.c_str(), std::ios::in);
1423  if(!file) {
1424  rfilename = pureFilename + ".mtx";
1425  file.open(rfilename.c_str(), std::ios::in);
1426  if(!file)
1427  DUNE_THROW(IOError, "Could not open file: " << rfilename.c_str());
1428  }
1429  }
1430  readMatrixMarket(matrix,file);
1431  file.close();
1432  }
1433 
1435 }
1436 #endif
std::enable_if_t< is_complex< T >::value, T > conj(const T &r)
Definition: matrixmarket.hh:781
Functor to the data values of the matrix.
Definition: matrixmarket.hh:719
void loadMatrixMarket(M &matrix, const std::string &filename, OwnerOverlapCopyCommunication< G, L > &comm, bool readIndices=true)
Load a parallel matrix/vector stored in matrix market format.
Definition: matrixmarket.hh:1312
a wrapper class of numeric values.
Definition: matrixmarket.hh:637
A generic dynamic dense matrix.
Definition: matrix.hh:560
MM_TYPE type
Definition: matrixmarket.hh:353
Classes providing communication interfaces for overlapping Schwarz methods.
void mm_read_header(std::size_t &rows, std::size_t &cols, MatrixMarketImpl::MMHeader &header, std::istream &istr, bool isVector)
Definition: matrixmarket.hh:914
MMHeader()
Definition: matrixmarket.hh:350
MM_CTYPE ctype
Definition: matrixmarket.hh:354
Meta program to write the correct Matrix Market header.
Definition: matrixmarket.hh:217
A class setting up standard communication for a two-valued attribute set with owner/overlap/copy sema...
Definition: owneroverlapcopy.hh:173
bool readMatrixMarketBanner(std::istream &file, MMHeader &mmHeader)
Definition: matrixmarket.hh:396
void readMatrixMarket(Dune::BlockVector< T, A > &vector, std::istream &istr)
Reads a BlockVector from a matrix market file.
Definition: matrixmarket.hh:973
static std::string str()
Definition: matrixmarket.hh:86
Test whether a type is an ISTL Matrix.
Definition: matrixutils.hh:503
Definition: matrixmarket.hh:771
Definition: matrixmarket.hh:340
Helper metaprogram to get the matrix market string representation of the numeric type.
Definition: matrixmarket.hh:78
FieldMatrix< T, i, j > M
Definition: matrixmarket.hh:324
Definition: matrixmarket.hh:346
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:466
FieldVector< T, i > M
Definition: matrixmarket.hh:333
Definition: matrixmarket.hh:344
void setBuildMode(BuildMode bm)
Sets the build mode of the matrix.
Definition: bcrsmatrix.hh:831
Definition: matrixmarket.hh:346
Metaprogram for writing the ISTL block structure header.
Definition: matrixmarket.hh:268
std::tuple< std::string, std::string > splitFilename(const std::string &filename)
Definition: matrixmarket.hh:895
Definition: matrixmarket.hh:910
STL namespace.
Col col
Definition: matrixmatrix.hh:351
static void print(std::ostream &os)
Definition: matrixmarket.hh:252
size_type N() const
number of rows (counted in blocks)
Definition: bcrsmatrix.hh:2004
Definition: matrixmarket.hh:344
void skipComments(std::istream &file)
Definition: matrixmarket.hh:382
static void print(std::ostream &os, const M &)
Definition: matrixmarket.hh:288
void storeMatrixMarket(const M &matrix, std::string filename, int prec=default_precision)
Stores a parallel matrix/vector in matrix market format in a file.
Definition: matrixmarket.hh:1194
static void print(std::ostream &, const M &)
Definition: matrixmarket.hh:326
Definition: matrixmarket.hh:344
const Communication< MPI_Comm > & communicator() const
Definition: owneroverlapcopy.hh:299
static void print(std::ostream &os, const M &)
Definition: matrixmarket.hh:313
BlockVector< T, A > M
Definition: matrixmarket.hh:273
Definition: matrixmarket.hh:344
void mm_print_entry(const B &entry, std::size_t rowidx, std::size_t colidx, std::ostream &ostr)
Definition: matrixmarket.hh:1073
Definition: matrixmarket.hh:348
Definition: matrixutils.hh:27
Iterator end()
Get iterator to one beyond last row.
Definition: bcrsmatrix.hh:678
LineType
Definition: matrixmarket.hh:339
void readSparseEntries(Dune::BCRSMatrix< T, A > &matrix, std::istream &file, std::size_t entries, const MMHeader &mmHeader, const D &)
Definition: matrixmarket.hh:808
static const int default_precision
Definition: matrixmarket.hh:1181
static std::string str()
Definition: matrixmarket.hh:202
std::istream & operator>>(std::istream &is, NumericWrapper< T > &num)
Definition: matrixmarket.hh:657
void operator()(const std::vector< std::set< IndexData< D > > > &rows, BCRSMatrix< FieldMatrix< T, brows, bcols > > &matrix)
Sets the matrix values.
Definition: matrixmarket.hh:745
MM_STRUCTURE
Definition: matrixmarket.hh:346
MM_TYPE
Definition: matrixmarket.hh:342
Definition: matrixmarket.hh:344
static void print(std::ostream &os)
Definition: matrixmarket.hh:242
This file implements a vector space as a tensor product of a given vector space. The number of compon...
Whether T is a supported numeric type.
Definition: matrixmarket.hh:83
void writeMatrixMarket(const V &vector, std::ostream &ostr, const std::integral_constant< int, 0 > &)
Definition: matrixmarket.hh:1132
Implementation of the BCRSMatrix class.
Dune::ParallelIndexSet< GlobalIdType, LI, 512 > ParallelIndexSet
The type of the parallel index set.
Definition: owneroverlapcopy.hh:449
void operator()(const std::vector< std::set< IndexData< PatternDummy > > > &, M &)
Definition: matrixmarket.hh:766
CreateIterator createend()
get create iterator pointing to one after the last block
Definition: bcrsmatrix.hh:1103
std::tuple< std::size_t, std::size_t, std::size_t > calculateNNZ(std::size_t rows, std::size_t cols, std::size_t entries, const MMHeader &header)
Definition: matrixmarket.hh:590
std::size_t index
Definition: matrixmarket.hh:622
Iterator begin()
Get iterator to first row.
Definition: bcrsmatrix.hh:672
Definition: matrixmarket.hh:620
static void print(std::ostream &os, const M &)
Definition: matrixmarket.hh:301
bool lineFeed(std::istream &file)
Definition: matrixmarket.hh:358
Definition: matrixmarket.hh:346
static void print(std::ostream &os)
Definition: matrixmarket.hh:232
typename Imp::BlockTraits< B >::field_type field_type
export the type representing the field
Definition: bvector.hh:398
static std::string str()
Definition: matrixmarket.hh:118
static void print(std::ostream &, const M &)
Definition: matrixmarket.hh:335
Definition: matrixmarket.hh:339
std::size_t countEntries(const BlockVector< T, A > &vector)
Definition: matrixmarket.hh:1119
Definition: matrixmarket.hh:786
auto countNonZeros(const M &, [[maybe_unused]] typename std::enable_if_t< Dune::IsNumber< M >::value > *sfinae=nullptr)
Get the number of nonzero fields in the matrix.
Definition: matrixutils.hh:119
Definition: matrixmarket.hh:346
void operator()(const std::vector< std::set< IndexData< D > > > &rows, BCRSMatrix< T > &matrix)
Sets the matrix values.
Definition: matrixmarket.hh:727
static std::string str()
Definition: matrixmarket.hh:134
T number
Definition: matrixmarket.hh:639
Definition: matrixmarket.hh:342
void mm_read_vector_entries(Dune::BlockVector< T, A > &vector, std::size_t size, std::istream &istr, size_t lane)
Definition: matrixmarket.hh:943
static std::string str()
Definition: matrixmarket.hh:102
const RemoteIndices & remoteIndices() const
Get the underlying remote indices.
Definition: owneroverlapcopy.hh:471
MM_STRUCTURE structure
Definition: matrixmarket.hh:355
Definition: matrixmarket.hh:339
const ParallelIndexSet & indexSet() const
Get the underlying parallel index set.
Definition: owneroverlapcopy.hh:462
Definition: matrixmarket.hh:339
Some handy generic functions for ISTL matrices.
static std::string str()
Definition: matrixmarket.hh:186
size_type M() const
number of columns (counted in blocks)
Definition: bcrsmatrix.hh:2010
std::enable_if_t<!is_complex< T >::value, T > conj(const T &r)
Definition: matrixmarket.hh:776
static void print(std::ostream &os)
Definition: matrixmarket.hh:222
Definition: allocator.hh:11
A vector of blocks with memory management.
Definition: bvector.hh:391
Utility class for marking the pattern type of the MatrixMarket matrices.
Definition: matrixmarket.hh:649
void resize(size_type size)
Resize the vector.
Definition: bvector.hh:496
void mm_print_vector_entry(const V &entry, std::ostream &ostr, const std::integral_constant< int, 1 > &, size_t lane)
Definition: matrixmarket.hh:1092
Definition: matrixmarket.hh:342
void setSize(size_type rows, size_type columns, size_type nnz=0)
Set the size of the matrix.
Definition: bcrsmatrix.hh:859
static void print(std::ostream &os, const M &)
Definition: matrixmarket.hh:276
CreateIterator createbegin()
get initial create iterator
Definition: bcrsmatrix.hh:1097
Definition: matrixmarket.hh:346
MM_CTYPE
Definition: matrixmarket.hh:344
BCRSMatrix< T, A > M
Definition: matrixmarket.hh:298
Definition: matrixmarket.hh:342