dune-istl  2.2.0
bcrsmatrix.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 
4 #ifndef DUNE_BCRSMATRIX_HH
5 #define DUNE_BCRSMATRIX_HH
6 
7 #include<cmath>
8 #include<complex>
9 #include<set>
10 #include<iostream>
11 #include<algorithm>
12 #include<numeric>
13 #include<vector>
14 
15 #include "istlexception.hh"
16 #include "bvector.hh"
17 #include <dune/common/shared_ptr.hh>
18 #include <dune/common/stdstreams.hh>
19 #include <dune/common/iteratorfacades.hh>
20 #include <dune/common/typetraits.hh>
21 #include <dune/common/static_assert.hh>
22 
27 namespace Dune {
28 
68  template<typename M>
69  struct MatrixDimension;
70 
178  template<class B, class A=std::allocator<B> >
180  {
181  friend struct MatrixDimension<BCRSMatrix>;
182 
183  private:
184  enum BuildStage{
186  notbuilt=0,
191  rowSizesBuilt=1,
193  built=2
194  };
195 
196  public:
197 
198  //===== type definitions and constants
199 
201  typedef typename B::field_type field_type;
202 
204  typedef B block_type;
205 
207  typedef A allocator_type;
208 
211 
213  typedef typename A::size_type size_type;
214 
216  enum {
218  blocklevel = B::blocklevel+1
219  };
220 
222  enum BuildMode {
247  };
248 
249 
250  //===== random access interface to rows of the matrix
251 
254  {
255 #ifdef DUNE_ISTL_WITH_CHECKING
256  if (r==0) DUNE_THROW(ISTLError,"row not initialized yet");
257  if (i>=n) DUNE_THROW(ISTLError,"index out of range");
258  if (r[i].getptr()==0) DUNE_THROW(ISTLError,"row not initialized yet");
259 #endif
260  return r[i];
261  }
262 
265  {
266 #ifdef DUNE_ISTL_WITH_CHECKING
267  if (built!=ready) DUNE_THROW(ISTLError,"row not initialized yet");
268  if (i>=n) DUNE_THROW(ISTLError,"index out of range");
269 #endif
270  return r[i];
271  }
272 
273 
274  //===== iterator interface to rows of the matrix
275 
277  template<class T>
279  : public RandomAccessIteratorFacade<RealRowIterator<T>, T>
280  {
281 
282  public:
285 
286  friend class RandomAccessIteratorFacade<RealRowIterator<const ValueType>, const ValueType>;
287  friend class RandomAccessIteratorFacade<RealRowIterator<ValueType>, ValueType>;
288  friend class RealRowIterator<const ValueType>;
289  friend class RealRowIterator<ValueType>;
290 
293  : p(_p), i(_i)
294  {}
295 
298  : p(0), i(0)
299  {}
300 
302  : p(it.p), i(it.i)
303  {}
304 
305 
307  size_type index () const
308  {
309  return i;
310  }
311 
312  std::ptrdiff_t distanceTo(const RealRowIterator<ValueType>& other) const
313  {
314  assert(other.p==p);
315  return (other.i-i);
316  }
317 
318  std::ptrdiff_t distanceTo(const RealRowIterator<const ValueType>& other) const
319  {
320  assert(other.p==p);
321  return (other.i-i);
322  }
323 
325  bool equals (const RealRowIterator<ValueType>& other) const
326  {
327  assert(other.p==p);
328  return i==other.i;
329  }
330 
332  bool equals (const RealRowIterator<const ValueType>& other) const
333  {
334  assert(other.p==p);
335  return i==other.i;
336  }
337 
338  private:
340  void increment()
341  {
342  ++i;
343  }
344 
346  void decrement()
347  {
348  --i;
349  }
350 
351  void advance(std::ptrdiff_t diff)
352  {
353  i+=diff;
354  }
355 
356  T& elementAt(std::ptrdiff_t diff) const
357  {
358  return p[i+diff];
359  }
360 
362  row_type& dereference () const
363  {
364  return p[i];
365  }
366 
367  row_type* p;
368  size_type i;
369  };
370 
374 
377  {
378  return Iterator(r,0);
379  }
380 
383  {
384  return Iterator(r,n);
385  }
386 
390  {
391  return Iterator(r,n-1);
392  }
393 
397  {
398  return Iterator(r,-1);
399  }
400 
403 
405  typedef typename row_type::Iterator ColIterator;
406 
410 
411 
414  {
415  return ConstIterator(r,0);
416  }
417 
420  {
421  return ConstIterator(r,n);
422  }
423 
427  {
428  return ConstIterator(r,n-1);
429  }
430 
434  {
435  return ConstIterator(r,-1);
436  }
437 
440 
443 
444  //===== constructors & resizers
445 
448  : build_mode(unknown), ready(notbuilt), n(0), m(0), nnz(0),
449  r(0), a(0)
450  {}
451 
454  : build_mode(bm), ready(notbuilt)
455  {
456  allocate(_n, _m, _nnz);
457  }
458 
461  : build_mode(bm), ready(notbuilt)
462  {
463  allocate(_n, _m);
464  }
465 
471  BCRSMatrix (const BCRSMatrix& Mat)
472  : n(Mat.n), nnz(0)
473  {
474  // deep copy in global array
475  size_type _nnz = Mat.nnz;
476 
477  // in case of row-wise allocation
478  if (_nnz<=0)
479  {
480  _nnz = 0;
481  for (size_type i=0; i<n; i++)
482  _nnz += Mat.r[i].getsize();
483  }
484 
485  j = Mat.j; // enable column index sharing, release array in case of row-wise allocation
486  allocate(Mat.n, Mat.m, _nnz);
487 
488  // build window structure
489  copyWindowStructure(Mat);
490  }
491 
494  {
495  deallocate();
496  }
497 
503  {
504  if(ready==notbuilt)
505  build_mode = bm;
506  else
507  DUNE_THROW(InvalidStateException, "Matrix structure is already built (ready="<<ready<<").");
508  }
509 
525  void setSize(size_type rows, size_type columns, size_type nnz=0)
526  {
527  // deallocate already setup memory
528  deallocate();
529 
530  // allocate matrix memory
531  allocate(rows, columns, nnz);
532  }
533 
541  {
542  // return immediately when self-assignment
543  if (&Mat==this) return *this;
544 
545  // make it simple: ALWAYS throw away memory for a and j
546  deallocate(false);
547 
548  // reallocate the rows if required
549  if (n>0 && n!=Mat.n) {
550  // free rows
551  int i=n;
552  while (i)
553  r[--i].~row_type();
554  rowAllocator_.deallocate(r,n);
555  }
556 
557  nnz=Mat.nnz;
558  if (nnz<=0)
559  {
560  for (size_type i=0; i<Mat.n; i++)
561  nnz += Mat.r[i].getsize();
562  }
563 
564  // allocate a, share j
565  j = Mat.j;
566  allocate(Mat.n, Mat.m, nnz, n!=Mat.n);
567 
568  // build window structure
569  copyWindowStructure(Mat);
570  return *this;
571  }
572 
575  {
576  for (size_type i=0; i<n; i++) r[i] = k;
577  return *this;
578  }
579 
580  //===== row-wise creation interface
581 
584  {
585  public:
588  : Mat(_Mat), i(_i), nnz(0), current_row(Mat.a, Mat.j.get(), 0)
589  {
590  if (i==0 && Mat.ready)
591  DUNE_THROW(ISTLError,"creation only allowed for uninitialized matrix");
592  if(Mat.build_mode!=row_wise)
593  {
594  if(Mat.build_mode==unknown)
595  Mat.build_mode=row_wise;
596  else
597  DUNE_THROW(ISTLError,"creation only allowed if row wise allocation was requested in the constructor");
598  }
599  }
600 
603  {
604  // this should only be called if matrix is in creation
605  if (Mat.ready)
606  DUNE_THROW(ISTLError,"matrix already built up");
607 
608  // row i is defined through the pattern
609  // get memory for the row and initialize the j array
610  // this depends on the allocation mode
611 
612  // compute size of the row
613  size_type s = pattern.size();
614 
615  if(s>0){
616  // update number of nonzeroes including this row
617  nnz += s;
618 
619  // alloc memory / set window
620  if (Mat.nnz>0)
621  {
622  // memory is allocated in one long array
623 
624  // check if that memory is sufficient
625  if (nnz>Mat.nnz)
626  DUNE_THROW(ISTLError,"allocated nnz too small");
627 
628  // set row i
629  Mat.r[i].set(s,current_row.getptr(),current_row.getindexptr());
630  current_row.setptr(current_row.getptr()+s);
631  current_row.setindexptr(current_row.getindexptr()+s);
632  }else{
633  // memory is allocated individually per row
634  // allocate and set row i
635  B* a = Mat.allocator_.allocate(s);
636  new (a) B[s];
637  size_type* j = Mat.sizeAllocator_.allocate(s);
638  new (j) size_type[s];
639  Mat.r[i].set(s,a,j);
640  }
641  }else
642  // setup empty row
643  Mat.r[i].set(0,0,0);
644 
645  // initialize the j array for row i from pattern
646  size_type k=0;
647  size_type *j = Mat.r[i].getindexptr();
648  for (typename PatternType::const_iterator it=pattern.begin(); it!=pattern.end(); ++it)
649  j[k++] = *it;
650 
651  // now go to next row
652  i++;
653  pattern.clear();
654 
655  // check if this was last row
656  if (i==Mat.n)
657  {
658  Mat.ready = built;
659  if(Mat.nnz>0)
660  // Set nnz to the exact number of nonzero blocks inserted
661  // as some methods rely on it
662  Mat.nnz=nnz;
663  }
664  // done
665  return *this;
666  }
667 
669  bool operator!= (const CreateIterator& it) const
670  {
671  return (i!=it.i) || (&Mat!=&it.Mat);
672  }
673 
675  bool operator== (const CreateIterator& it) const
676  {
677  return (i==it.i) && (&Mat==&it.Mat);
678  }
679 
681  size_type index () const
682  {
683  return i;
684  }
685 
687  void insert (size_type j)
688  {
689  pattern.insert(j);
690  }
691 
694  {
695  if (pattern.find(j)!=pattern.end())
696  return true;
697  else
698  return false;
699  }
705  size_type size() const
706  {
707  return pattern.size();
708  }
709 
710  private:
711  BCRSMatrix& Mat; // the matrix we are defining
712  size_type i; // current row to be defined
713  size_type nnz; // count total number of nonzeros
714  typedef std::set<size_type,std::less<size_type> > PatternType;
715  PatternType pattern; // used to compile entries in a row
716  row_type current_row; // row pointing to the current row to setup
717  };
718 
720  friend class CreateIterator;
721 
724  {
725  return CreateIterator(*this,0);
726  }
727 
730  {
731  return CreateIterator(*this,n);
732  }
733 
734 
735  //===== random creation interface
736 
739  {
740  if (build_mode!=random)
741  DUNE_THROW(ISTLError,"requires random build mode");
742  if (ready)
743  DUNE_THROW(ISTLError,"matrix row sizes already built up");
744 
745  r[i].setsize(s);
746  }
747 
750  {
751 #ifdef DUNE_ISTL_WITH_CHECKING
752  if (r==0) DUNE_THROW(ISTLError,"row not initialized yet");
753  if (i>=n) DUNE_THROW(ISTLError,"index out of range");
754 #endif
755  return r[i].getsize();
756  }
757 
760  {
761  if (build_mode!=random)
762  DUNE_THROW(ISTLError,"requires random build mode");
763  if (ready)
764  DUNE_THROW(ISTLError,"matrix row sizes already built up");
765 
766  r[i].setsize(r[i].getsize()+s);
767  }
768 
770  void endrowsizes ()
771  {
772  if (build_mode!=random)
773  DUNE_THROW(ISTLError,"requires random build mode");
774  if (ready)
775  DUNE_THROW(ISTLError,"matrix row sizes already built up");
776 
777  // compute total size, check positivity
778  size_type total=0;
779  for (size_type i=0; i<n; i++)
780  {
781  if (r[i].getsize()<0)
782  DUNE_THROW(ISTLError,"rowsize must be nonnegative");
783  total += r[i].getsize();
784  }
785 
786  if(nnz==0)
787  // allocate/check memory
788  allocate(n,m,total,false);
789  else if(nnz<total)
790  DUNE_THROW(ISTLError,"Specified number of nonzeros ("<<nnz<<") not "
791  <<"sufficient for calculated nonzeros ("<<total<<"! ");
792 
793  // set the window pointers correctly
794  setWindowPointers(begin());
795 
796  // initialize j array with m (an invalid column index)
797  // this indicates an unused entry
798  for (size_type k=0; k<nnz; k++)
799  j.get()[k] = m;
800  ready = rowSizesBuilt;
801  }
802 
804 
815  {
816  if (build_mode!=random)
817  DUNE_THROW(ISTLError,"requires random build mode");
818  if (ready==built)
819  DUNE_THROW(ISTLError,"matrix already built up");
820  if (ready==notbuilt)
821  DUNE_THROW(ISTLError,"matrix row sizes not built up yet");
822 
823  if (col >= m)
824  DUNE_THROW(ISTLError,"column index exceeds matrix size");
825 
826  // get row range
827  size_type* const first = r[row].getindexptr();
828  size_type* const last = first + r[row].getsize();
829 
830  // find correct insertion position for new column index
831  size_type* pos = std::lower_bound(first,last,col);
832 
833  // check if index is already in row
834  if (pos!=last && *pos == col) return;
835 
836  // find end of already inserted column indices
837  size_type* end = std::lower_bound(pos,last,m);
838  if (end==last)
839  DUNE_THROW(ISTLError,"row is too small");
840 
841  // insert new column index at correct position
842  std::copy_backward(pos,end,end+1);
843  *pos = col;
844 
845  }
846 
848  void endindices ()
849  {
850  if (build_mode!=random)
851  DUNE_THROW(ISTLError,"requires random build mode");
852  if (ready==built)
853  DUNE_THROW(ISTLError,"matrix already built up");
854  if (ready==notbuilt)
855  DUNE_THROW(ISTLError,"row sizes are not built up yet");
856 
857  // check if there are undefined indices
858  RowIterator endi=end();
859  for (RowIterator i=begin(); i!=endi; ++i)
860  {
861  ColIterator endj = (*i).end();
862  for (ColIterator j=(*i).begin(); j!=endj; ++j){
863  if (j.index()<0)
864  {
865  std::cout << "j[" << j.offset() << "]=" << j.index() << std::endl;
866  DUNE_THROW(ISTLError,"undefined index detected");
867  }
868  if (j.index()>=m){
869  dwarn << "WARNING: size of row "<< i.index()<<" is "<<j.offset()<<". But was specified as being "<< (*i).end().offset()
870  <<". This means you are wasting valuable space and creating additional cache misses!"<<std::endl;
871  r[i.index()].setsize(j.offset());
872  break;
873  }
874  }
875  }
876 
877  // if not, set matrix to built
878  ready = built;
879  }
880 
881  //===== vector space arithmetic
882 
885  {
886  if (nnz>0)
887  {
888  // process 1D array
889  for (size_type i=0; i<nnz; i++)
890  a[i] *= k;
891  }
892  else
893  {
894  RowIterator endi=end();
895  for (RowIterator i=begin(); i!=endi; ++i)
896  {
897  ColIterator endj = (*i).end();
898  for (ColIterator j=(*i).begin(); j!=endj; ++j)
899  (*j) *= k;
900  }
901  }
902 
903  return *this;
904  }
905 
908  {
909  if (nnz>0)
910  {
911  // process 1D array
912  for (size_type i=0; i<nnz; i++)
913  a[i] /= k;
914  }
915  else
916  {
917  RowIterator endi=end();
918  for (RowIterator i=begin(); i!=endi; ++i)
919  {
920  ColIterator endj = (*i).end();
921  for (ColIterator j=(*i).begin(); j!=endj; ++j)
922  (*j) /= k;
923  }
924  }
925 
926  return *this;
927  }
928 
929 
936  {
937 #ifdef DUNE_ISTL_WITH_CHECKING
938  if(N()!=b.N() || M() != b.M())
939  DUNE_THROW(RangeError, "Matrix sizes do not match!");
940 #endif
941  RowIterator endi=end();
942  ConstRowIterator j=b.begin();
943  for (RowIterator i=begin(); i!=endi; ++i, ++j){
944  i->operator+=(*j);
945  }
946 
947  return *this;
948  }
949 
956  {
957 #ifdef DUNE_ISTL_WITH_CHECKING
958  if(N()!=b.N() || M() != b.M())
959  DUNE_THROW(RangeError, "Matrix sizes do not match!");
960 #endif
961  RowIterator endi=end();
962  ConstRowIterator j=b.begin();
963  for (RowIterator i=begin(); i!=endi; ++i, ++j){
964  i->operator-=(*j);
965  }
966 
967  return *this;
968  }
969 
979  {
980 #ifdef DUNE_ISTL_WITH_CHECKING
981  if(N()!=b.N() || M() != b.M())
982  DUNE_THROW(RangeError, "Matrix sizes do not match!");
983 #endif
984  RowIterator endi=end();
985  ConstRowIterator j=b.begin();
986  for(RowIterator i=begin(); i!=endi; ++i, ++j)
987  i->axpy(alpha, *j);
988 
989  return *this;
990  }
991 
992  //===== linear maps
993 
995  template<class X, class Y>
996  void mv (const X& x, Y& y) const
997  {
998 #ifdef DUNE_ISTL_WITH_CHECKING
999  if (x.N()!=M()) DUNE_THROW(ISTLError,
1000  "Size mismatch: M: " << N() << "x" << M() << " x: " << x.N());
1001  if (y.N()!=N()) DUNE_THROW(ISTLError,
1002  "Size mismatch: M: " << N() << "x" << M() << " y: " << y.N());
1003 #endif
1004  ConstRowIterator endi=end();
1005  for (ConstRowIterator i=begin(); i!=endi; ++i)
1006  {
1007  y[i.index()]=0;
1008  ConstColIterator endj = (*i).end();
1009  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1010  (*j).umv(x[j.index()],y[i.index()]);
1011  }
1012  }
1013 
1015  template<class X, class Y>
1016  void umv (const X& x, Y& y) const
1017  {
1018 #ifdef DUNE_ISTL_WITH_CHECKING
1019  if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1020  if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1021 #endif
1022  ConstRowIterator endi=end();
1023  for (ConstRowIterator i=begin(); i!=endi; ++i)
1024  {
1025  ConstColIterator endj = (*i).end();
1026  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1027  (*j).umv(x[j.index()],y[i.index()]);
1028  }
1029  }
1030 
1032  template<class X, class Y>
1033  void mmv (const X& x, Y& y) const
1034  {
1035 #ifdef DUNE_ISTL_WITH_CHECKING
1036  if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1037  if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1038 #endif
1039  ConstRowIterator endi=end();
1040  for (ConstRowIterator i=begin(); i!=endi; ++i)
1041  {
1042  ConstColIterator endj = (*i).end();
1043  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1044  (*j).mmv(x[j.index()],y[i.index()]);
1045  }
1046  }
1047 
1049  template<class X, class Y>
1050  void usmv (const field_type& alpha, const X& x, Y& y) const
1051  {
1052 #ifdef DUNE_ISTL_WITH_CHECKING
1053  if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1054  if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1055 #endif
1056  ConstRowIterator endi=end();
1057  for (ConstRowIterator i=begin(); i!=endi; ++i)
1058  {
1059  ConstColIterator endj = (*i).end();
1060  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1061  (*j).usmv(alpha,x[j.index()],y[i.index()]);
1062  }
1063  }
1064 
1066  template<class X, class Y>
1067  void mtv (const X& x, Y& y) const
1068  {
1069 #ifdef DUNE_ISTL_WITH_CHECKING
1070  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1071  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1072 #endif
1073  for(size_type i=0; i<y.N(); ++i)
1074  y[i]=0;
1075  umtv(x,y);
1076  }
1077 
1079  template<class X, class Y>
1080  void umtv (const X& x, Y& y) const
1081  {
1082 #ifdef DUNE_ISTL_WITH_CHECKING
1083  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1084  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1085 #endif
1086  ConstRowIterator endi=end();
1087  for (ConstRowIterator i=begin(); i!=endi; ++i)
1088  {
1089  ConstColIterator endj = (*i).end();
1090  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1091  (*j).umtv(x[i.index()],y[j.index()]);
1092  }
1093  }
1094 
1096  template<class X, class Y>
1097  void mmtv (const X& x, Y& y) const
1098  {
1099 #ifdef DUNE_ISTL_WITH_CHECKING
1100  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1101  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1102 #endif
1103  ConstRowIterator endi=end();
1104  for (ConstRowIterator i=begin(); i!=endi; ++i)
1105  {
1106  ConstColIterator endj = (*i).end();
1107  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1108  (*j).mmtv(x[i.index()],y[j.index()]);
1109  }
1110  }
1111 
1113  template<class X, class Y>
1114  void usmtv (const field_type& alpha, const X& x, Y& y) const
1115  {
1116 #ifdef DUNE_ISTL_WITH_CHECKING
1117  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1118  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1119 #endif
1120  ConstRowIterator endi=end();
1121  for (ConstRowIterator i=begin(); i!=endi; ++i)
1122  {
1123  ConstColIterator endj = (*i).end();
1124  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1125  (*j).usmtv(alpha,x[i.index()],y[j.index()]);
1126  }
1127  }
1128 
1130  template<class X, class Y>
1131  void umhv (const X& x, Y& y) const
1132  {
1133 #ifdef DUNE_ISTL_WITH_CHECKING
1134  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1135  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1136 #endif
1137  ConstRowIterator endi=end();
1138  for (ConstRowIterator i=begin(); i!=endi; ++i)
1139  {
1140  ConstColIterator endj = (*i).end();
1141  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1142  (*j).umhv(x[i.index()],y[j.index()]);
1143  }
1144  }
1145 
1147  template<class X, class Y>
1148  void mmhv (const X& x, Y& y) const
1149  {
1150 #ifdef DUNE_ISTL_WITH_CHECKING
1151  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1152  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1153 #endif
1154  ConstRowIterator endi=end();
1155  for (ConstRowIterator i=begin(); i!=endi; ++i)
1156  {
1157  ConstColIterator endj = (*i).end();
1158  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1159  (*j).mmhv(x[i.index()],y[j.index()]);
1160  }
1161  }
1162 
1164  template<class X, class Y>
1165  void usmhv (const field_type& alpha, const X& x, Y& y) const
1166  {
1167 #ifdef DUNE_ISTL_WITH_CHECKING
1168  if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range");
1169  if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range");
1170 #endif
1171  ConstRowIterator endi=end();
1172  for (ConstRowIterator i=begin(); i!=endi; ++i)
1173  {
1174  ConstColIterator endj = (*i).end();
1175  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1176  (*j).usmhv(alpha,x[i.index()],y[j.index()]);
1177  }
1178  }
1179 
1180 
1181  //===== norms
1182 
1184  double frobenius_norm2 () const
1185  {
1186  double sum=0;
1187 
1188  ConstRowIterator endi=end();
1189  for (ConstRowIterator i=begin(); i!=endi; ++i)
1190  {
1191  ConstColIterator endj = (*i).end();
1192  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1193  sum += (*j).frobenius_norm2();
1194  }
1195 
1196  return sum;
1197  }
1198 
1200  double frobenius_norm () const
1201  {
1202  return sqrt(frobenius_norm2());
1203  }
1204 
1206  double infinity_norm () const
1207  {
1208  double max=0;
1209  ConstRowIterator endi=end();
1210  for (ConstRowIterator i=begin(); i!=endi; ++i)
1211  {
1212  double sum=0;
1213  ConstColIterator endj = (*i).end();
1214  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1215  sum += (*j).infinity_norm();
1216  max = std::max(max,sum);
1217  }
1218  return max;
1219  }
1220 
1222  double infinity_norm_real () const
1223  {
1224  double max=0;
1225  ConstRowIterator endi=end();
1226  for (ConstRowIterator i=begin(); i!=endi; ++i)
1227  {
1228  double sum=0;
1229  ConstColIterator endj = (*i).end();
1230  for (ConstColIterator j=(*i).begin(); j!=endj; ++j)
1231  sum += (*j).infinity_norm_real();
1232  max = std::max(max,sum);
1233  }
1234  return max;
1235  }
1236 
1237 
1238  //===== sizes
1239 
1241  size_type N () const
1242  {
1243  return n;
1244  }
1245 
1247  size_type M () const
1248  {
1249  return m;
1250  }
1251 
1254  {
1255  return nnz;
1256  }
1257 
1258 
1259  //===== query
1260 
1262  bool exists (size_type i, size_type j) const
1263  {
1264 #ifdef DUNE_ISTL_WITH_CHECKING
1265  if (i<0 || i>=n) DUNE_THROW(ISTLError,"index out of range");
1266  if (j<0 || i>=m) DUNE_THROW(ISTLError,"index out of range");
1267 #endif
1268  if (r[i].size() && r[i].find(j)!=r[i].end())
1269  return true;
1270  else
1271  return false;
1272  }
1273 
1274 
1275  private:
1276  // state information
1277  BuildMode build_mode; // row wise or whole matrix
1278  BuildStage ready; // indicate the stage the matrix building is in
1279 
1280  // The allocator used for memory management
1281  typename A::template rebind<B>::other allocator_;
1282 
1283  typename A::template rebind<row_type>::other rowAllocator_;
1284 
1285  typename A::template rebind<size_type>::other sizeAllocator_;
1286 
1287  // size of the matrix
1288  size_type n; // number of rows
1289  size_type m; // number of columns
1290  size_type nnz; // number of nonzeros allocated in the a and j array below
1291  // zero means that memory is allocated separately for each row.
1292 
1293  // the rows are dynamically allocated
1294  row_type* r; // [n] the individual rows having pointers into a,j arrays
1295 
1296  // dynamically allocated memory
1297  B* a; // [nnz] non-zero entries of the matrix in row-wise ordering
1298  // If a single array of column indices is used, it can be shared
1299  // between different matrices with the same sparsity pattern
1300  Dune::shared_ptr<size_type> j; // [nnz] column indices of entries
1301 
1302 
1303  void setWindowPointers(ConstRowIterator row)
1304  {
1305  row_type current_row(a,j.get(),0); // Pointers to current row data
1306  for (size_type i=0; i<n; i++, ++row){
1307  // set row i
1308  size_type s = row->getsize();
1309 
1310  if (s>0){
1311  // setup pointers and size
1312  r[i].set(s,current_row.getptr(), current_row.getindexptr());
1313  // update pointer for next row
1314  current_row.setptr(current_row.getptr()+s);
1315  current_row.setindexptr(current_row.getindexptr()+s);
1316  } else{
1317  // empty row
1318  r[i].set(0,0,0);
1319  }
1320  }
1321  }
1322 
1324  void copyWindowStructure(const BCRSMatrix& Mat)
1325  {
1326  setWindowPointers(Mat.begin());
1327 
1328  // copy data
1329  for (size_type i=0; i<n; i++) r[i] = Mat.r[i];
1330 
1331  // finish off
1332  build_mode = row_wise; // dummy
1333  ready = built;
1334  }
1335 
1341  void deallocate(bool deallocateRows=true)
1342  {
1343 
1344  if (nnz>0)
1345  {
1346  // a,j have been allocated as one long vector
1347  j.reset();
1348  int i=nnz;
1349  while (i)
1350  a[--i].~B();
1351  allocator_.deallocate(a,n);
1352  }
1353  else
1354  {
1355  // check if memory for rows have been allocated individually
1356  for (size_type i=0; i<n; i++)
1357  if (r[i].getsize()>0)
1358  {
1359  int j=r[i].getsize();
1360  while (j) {
1361  r[i].getindexptr()[--j].~size_type();
1362  r[i].getptr()[j].~B();
1363  }
1364  sizeAllocator_.deallocate(r[i].getindexptr(),1);
1365  allocator_.deallocate(r[i].getptr(),1);
1366  }
1367  }
1368 
1369  // deallocate the rows
1370  if (n>0 && deallocateRows) {
1371  int i=n;
1372  while (i)
1373  r[--i].~row_type();
1374  rowAllocator_.deallocate(r,n);
1375  }
1376 
1377  // Mark matrix as not built at all.
1378  ready=notbuilt;
1379 
1380  }
1381 
1383  class Deallocator
1384  {
1385  typename A::template rebind<size_type>::other& sizeAllocator_;
1386 
1387  public:
1388  Deallocator(typename A::template rebind<size_type>::other& sizeAllocator)
1389  : sizeAllocator_(sizeAllocator)
1390  {}
1391 
1392  void operator()(size_type* p) { sizeAllocator_.deallocate(p,1); }
1393  };
1394 
1395 
1413  void allocate(size_type rows, size_type columns, size_type nnz_=0, bool allocateRows=true)
1414  {
1415  // Store size
1416  n = rows;
1417  m = columns;
1418  nnz = nnz_;
1419 
1420  // allocate rows
1421  if(allocateRows){
1422  if (n>0){
1423  r = rowAllocator_.allocate(rows);
1424  new (r) row_type[rows];
1425  }else{
1426  r = 0;
1427  }
1428  }
1429 
1430 
1431  // allocate a and j array
1432  if (nnz>0){
1433  a = allocator_.allocate(nnz);
1434  // allocate column indices only if not yet present (enable sharing)
1435  if (!j.get())
1436  j.reset(sizeAllocator_.allocate(nnz),Deallocator(sizeAllocator_));
1437  }else{
1438  a = 0;
1439  j.reset();
1440  }
1441  // Mark the matrix as not built.
1442  ready = notbuilt;
1443  }
1444 
1445  };
1446 
1447 
1450 } // end namespace
1451 
1452 #endif