DUNE PDELab (2.8)

densematrix.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 #ifndef DUNE_DENSEMATRIX_HH
4 #define DUNE_DENSEMATRIX_HH
5 
6 #include <cmath>
7 #include <cstddef>
8 #include <iostream>
9 #include <type_traits>
10 #include <utility>
11 #include <vector>
12 
14 #include <dune/common/classname.hh>
17 #include <dune/common/fvector.hh>
18 #include <dune/common/math.hh>
19 #include <dune/common/precision.hh>
20 #include <dune/common/simd/simd.hh>
23 
24 namespace Dune
25 {
26 
27  template<typename M> class DenseMatrix;
28 
29  template<typename M>
30  struct FieldTraits< DenseMatrix<M> >
31  {
32  typedef const typename FieldTraits< typename DenseMatVecTraits<M>::value_type >::field_type field_type;
33  typedef const typename FieldTraits< typename DenseMatVecTraits<M>::value_type >::real_type real_type;
34  };
35 
43  template<class K, int N, int M> class FieldMatrix;
44  template<class K, int N> class FieldVector;
45  namespace {
46  template<class V>
47  struct [[deprecated("VectorSize is deprecated; please call the 'size()' method directly instead")]] VectorSize
48  {
49  static typename V::size_type size(const V & v) { return v.size(); }
50  };
51 
52  DUNE_NO_DEPRECATED_BEGIN
53  template<class K, int N>
54  struct [[deprecated("VectorSize is deprecated; please call the 'size()' method directly instead")]] VectorSize< const FieldVector<K,N> >
55  {
56  typedef FieldVector<K,N> V;
57  static typename V::size_type size([[maybe_unused]] const V & v)
58  {
59  return N;
60  }
61  };
62  DUNE_NO_DEPRECATED_END
63  }
64 
83  template< class DenseMatrix, class RHS >
84  struct DenseMatrixAssigner;
85 
86 #ifndef DOXYGEN
87  namespace Impl
88  {
89 
90  template< class DenseMatrix, class RHS, class = void >
91  class DenseMatrixAssigner
92  {};
93 
94  template< class DenseMatrix, class RHS >
95  class DenseMatrixAssigner< DenseMatrix, RHS, std::enable_if_t< Dune::IsNumber< RHS >::value > >
96  {
97  public:
98  static void apply ( DenseMatrix &denseMatrix, const RHS &rhs )
99  {
100  typedef typename DenseMatrix::field_type field_type;
101  std::fill( denseMatrix.begin(), denseMatrix.end(), static_cast< field_type >( rhs ) );
102  }
103  };
104 
105  template< class DenseMatrix, class RHS >
106  class DenseMatrixAssigner< DenseMatrix, RHS, std::enable_if_t< !std::is_same< typename RHS::const_iterator, void >::value
107  && std::is_convertible< typename RHS::const_iterator::value_type, typename DenseMatrix::iterator::value_type >::value > >
108  {
109  public:
110  static void apply ( DenseMatrix &denseMatrix, const RHS &rhs )
111  {
112  DUNE_ASSERT_BOUNDS(rhs.N() == denseMatrix.N());
113  DUNE_ASSERT_BOUNDS(rhs.M() == denseMatrix.M());
114  typename DenseMatrix::iterator tIt = std::begin(denseMatrix);
115  typename RHS::const_iterator sIt = std::begin(rhs);
116  for(; sIt != std::end(rhs); ++tIt, ++sIt)
117  std::copy(std::begin(*sIt), std::end(*sIt), std::begin(*tIt));
118  }
119  };
120 
121  } // namespace Impl
122 
123 
124 
125  template< class DenseMatrix, class RHS >
126  struct DenseMatrixAssigner
127  : public Impl::DenseMatrixAssigner< DenseMatrix, RHS >
128  {};
129 
130 
131  namespace Impl
132  {
133 
134  template< class DenseMatrix, class RHS >
135  std::true_type hasDenseMatrixAssigner ( DenseMatrix &, const RHS &, decltype( Dune::DenseMatrixAssigner< DenseMatrix, RHS >::apply( std::declval< DenseMatrix & >(), std::declval< const RHS & >() ) ) * = nullptr );
136 
137  std::false_type hasDenseMatrixAssigner ( ... );
138 
139  } // namespace Impl
140 
141  template< class DenseMatrix, class RHS >
142  struct HasDenseMatrixAssigner
143  : public decltype( Impl::hasDenseMatrixAssigner( std::declval< DenseMatrix & >(), std::declval< const RHS & >() ) )
144  {};
145 
146 #endif // #ifndef DOXYGEN
147 
148 
149 
151  class FMatrixError : public MathError {};
152 
163  template<typename MAT>
164  class DenseMatrix
165  {
166  typedef DenseMatVecTraits<MAT> Traits;
167 
168  // Curiously recurring template pattern
169  constexpr MAT & asImp() { return static_cast<MAT&>(*this); }
170  constexpr const MAT & asImp() const { return static_cast<const MAT&>(*this); }
171 
172  template <class>
173  friend class DenseMatrix;
174 
175  public:
176  //===== type definitions and constants
177 
179  typedef typename Traits::derived_type derived_type;
180 
182  typedef typename Traits::value_type value_type;
183 
185  typedef typename Traits::value_type field_type;
186 
188  typedef typename Traits::value_type block_type;
189 
191  typedef typename Traits::size_type size_type;
192 
194  typedef typename Traits::row_type row_type;
195 
197  typedef typename Traits::row_reference row_reference;
198 
200  typedef typename Traits::const_row_reference const_row_reference;
201 
203  enum {
205  blocklevel = 1
206  };
207 
208  private:
211  using simd_index_type = Simd::Rebind<std::size_t, value_type>;
212 
213  public:
214  //===== access to components
215 
217  row_reference operator[] ( size_type i )
218  {
219  return asImp().mat_access(i);
220  }
221 
222  const_row_reference operator[] ( size_type i ) const
223  {
224  return asImp().mat_access(i);
225  }
226 
228  size_type size() const
229  {
230  return rows();
231  }
232 
233  //===== iterator interface to rows of the matrix
235  typedef DenseIterator<DenseMatrix,row_type,row_reference> Iterator;
237  typedef Iterator iterator;
239  typedef Iterator RowIterator;
241  typedef typename std::remove_reference<row_reference>::type::Iterator ColIterator;
242 
244  Iterator begin ()
245  {
246  return Iterator(*this,0);
247  }
248 
250  Iterator end ()
251  {
252  return Iterator(*this,rows());
253  }
254 
257  Iterator beforeEnd ()
258  {
259  return Iterator(*this,rows()-1);
260  }
261 
264  Iterator beforeBegin ()
265  {
266  return Iterator(*this,-1);
267  }
268 
270  typedef DenseIterator<const DenseMatrix,const row_type,const_row_reference> ConstIterator;
272  typedef ConstIterator const_iterator;
274  typedef ConstIterator ConstRowIterator;
276  typedef typename std::remove_reference<const_row_reference>::type::ConstIterator ConstColIterator;
277 
279  ConstIterator begin () const
280  {
281  return ConstIterator(*this,0);
282  }
283 
285  ConstIterator end () const
286  {
287  return ConstIterator(*this,rows());
288  }
289 
292  ConstIterator beforeEnd () const
293  {
294  return ConstIterator(*this,rows()-1);
295  }
296 
299  ConstIterator beforeBegin () const
300  {
301  return ConstIterator(*this,-1);
302  }
303 
304  //===== assignment
305 
306  template< class RHS, class = std::enable_if_t< HasDenseMatrixAssigner< MAT, RHS >::value > >
307  derived_type &operator= ( const RHS &rhs )
308  {
309  DenseMatrixAssigner< MAT, RHS >::apply( asImp(), rhs );
310  return asImp();
311  }
312 
313  //===== vector space arithmetic
314 
316  template <class Other>
317  derived_type &operator+= (const DenseMatrix<Other>& x)
318  {
319  DUNE_ASSERT_BOUNDS(rows() == x.rows());
320  for (size_type i=0; i<rows(); i++)
321  (*this)[i] += x[i];
322  return asImp();
323  }
324 
326  derived_type operator- () const
327  {
328  MAT result;
329  using idx_type = typename decltype(result)::size_type;
330 
331  for (idx_type i = 0; i < rows(); ++i)
332  for (idx_type j = 0; j < cols(); ++j)
333  result[i][j] = - asImp()[i][j];
334 
335  return result;
336  }
337 
339  template <class Other>
340  derived_type &operator-= (const DenseMatrix<Other>& x)
341  {
342  DUNE_ASSERT_BOUNDS(rows() == x.rows());
343  for (size_type i=0; i<rows(); i++)
344  (*this)[i] -= x[i];
345  return asImp();
346  }
347 
349  derived_type &operator*= (const field_type& k)
350  {
351  for (size_type i=0; i<rows(); i++)
352  (*this)[i] *= k;
353  return asImp();
354  }
355 
357  derived_type &operator/= (const field_type& k)
358  {
359  for (size_type i=0; i<rows(); i++)
360  (*this)[i] /= k;
361  return asImp();
362  }
363 
365  template <class Other>
366  derived_type &axpy (const field_type &a, const DenseMatrix<Other> &x )
367  {
368  DUNE_ASSERT_BOUNDS(rows() == x.rows());
369  for( size_type i = 0; i < rows(); ++i )
370  (*this)[ i ].axpy( a, x[ i ] );
371  return asImp();
372  }
373 
375  template <class Other>
376  bool operator== (const DenseMatrix<Other>& x) const
377  {
378  DUNE_ASSERT_BOUNDS(rows() == x.rows());
379  for (size_type i=0; i<rows(); i++)
380  if ((*this)[i]!=x[i])
381  return false;
382  return true;
383  }
385  template <class Other>
386  bool operator!= (const DenseMatrix<Other>& x) const
387  {
388  return !operator==(x);
389  }
390 
391 
392  //===== linear maps
393 
395  template<class X, class Y>
396  void mv (const X& x, Y& y) const
397  {
398  auto&& xx = Impl::asVector(x);
399  auto&& yy = Impl::asVector(y);
400  DUNE_ASSERT_BOUNDS((void*)(&x) != (void*)(&y));
401  DUNE_ASSERT_BOUNDS(xx.N() == M());
402  DUNE_ASSERT_BOUNDS(yy.N() == N());
403 
404  using y_field_type = typename FieldTraits<Y>::field_type;
405  for (size_type i=0; i<rows(); ++i)
406  {
407  yy[i] = y_field_type(0);
408  for (size_type j=0; j<cols(); j++)
409  yy[i] += (*this)[i][j] * xx[j];
410  }
411  }
412 
414  template< class X, class Y >
415  void mtv ( const X &x, Y &y ) const
416  {
417  auto&& xx = Impl::asVector(x);
418  auto&& yy = Impl::asVector(y);
419  DUNE_ASSERT_BOUNDS((void*)(&x) != (void*)(&y));
420  DUNE_ASSERT_BOUNDS(xx.N() == N());
421  DUNE_ASSERT_BOUNDS(yy.N() == M());
422 
423  using y_field_type = typename FieldTraits<Y>::field_type;
424  for(size_type i = 0; i < cols(); ++i)
425  {
426  yy[i] = y_field_type(0);
427  for(size_type j = 0; j < rows(); ++j)
428  yy[i] += (*this)[j][i] * xx[j];
429  }
430  }
431 
433  template<class X, class Y>
434  void umv (const X& x, Y& y) const
435  {
436  auto&& xx = Impl::asVector(x);
437  auto&& yy = Impl::asVector(y);
438  DUNE_ASSERT_BOUNDS(xx.N() == M());
439  DUNE_ASSERT_BOUNDS(yy.N() == N());
440  for (size_type i=0; i<rows(); ++i)
441  for (size_type j=0; j<cols(); j++)
442  yy[i] += (*this)[i][j] * xx[j];
443  }
444 
446  template<class X, class Y>
447  void umtv (const X& x, Y& y) const
448  {
449  auto&& xx = Impl::asVector(x);
450  auto&& yy = Impl::asVector(y);
451  DUNE_ASSERT_BOUNDS(xx.N() == N());
452  DUNE_ASSERT_BOUNDS(yy.N() == M());
453  for(size_type i = 0; i<rows(); ++i)
454  for (size_type j=0; j<cols(); j++)
455  yy[j] += (*this)[i][j]*xx[i];
456  }
457 
459  template<class X, class Y>
460  void umhv (const X& x, Y& y) const
461  {
462  auto&& xx = Impl::asVector(x);
463  auto&& yy = Impl::asVector(y);
464  DUNE_ASSERT_BOUNDS(xx.N() == N());
465  DUNE_ASSERT_BOUNDS(yy.N() == M());
466  for (size_type i=0; i<rows(); i++)
467  for (size_type j=0; j<cols(); j++)
468  yy[j] += conjugateComplex((*this)[i][j])*xx[i];
469  }
470 
472  template<class X, class Y>
473  void mmv (const X& x, Y& y) const
474  {
475  auto&& xx = Impl::asVector(x);
476  auto&& yy = Impl::asVector(y);
477  DUNE_ASSERT_BOUNDS(xx.N() == M());
478  DUNE_ASSERT_BOUNDS(yy.N() == N());
479  for (size_type i=0; i<rows(); i++)
480  for (size_type j=0; j<cols(); j++)
481  yy[i] -= (*this)[i][j] * xx[j];
482  }
483 
485  template<class X, class Y>
486  void mmtv (const X& x, Y& y) const
487  {
488  auto&& xx = Impl::asVector(x);
489  auto&& yy = Impl::asVector(y);
490  DUNE_ASSERT_BOUNDS(xx.N() == N());
491  DUNE_ASSERT_BOUNDS(yy.N() == M());
492  for (size_type i=0; i<rows(); i++)
493  for (size_type j=0; j<cols(); j++)
494  yy[j] -= (*this)[i][j]*xx[i];
495  }
496 
498  template<class X, class Y>
499  void mmhv (const X& x, Y& y) const
500  {
501  auto&& xx = Impl::asVector(x);
502  auto&& yy = Impl::asVector(y);
503  DUNE_ASSERT_BOUNDS(xx.N() == N());
504  DUNE_ASSERT_BOUNDS(yy.N() == M());
505  for (size_type i=0; i<rows(); i++)
506  for (size_type j=0; j<cols(); j++)
507  yy[j] -= conjugateComplex((*this)[i][j])*xx[i];
508  }
509 
511  template<class X, class Y>
512  void usmv (const typename FieldTraits<Y>::field_type & alpha,
513  const X& x, Y& y) const
514  {
515  auto&& xx = Impl::asVector(x);
516  auto&& yy = Impl::asVector(y);
517  DUNE_ASSERT_BOUNDS(xx.N() == M());
518  DUNE_ASSERT_BOUNDS(yy.N() == N());
519  for (size_type i=0; i<rows(); i++)
520  for (size_type j=0; j<cols(); j++)
521  yy[i] += alpha * (*this)[i][j] * xx[j];
522  }
523 
525  template<class X, class Y>
526  void usmtv (const typename FieldTraits<Y>::field_type & alpha,
527  const X& x, Y& y) const
528  {
529  auto&& xx = Impl::asVector(x);
530  auto&& yy = Impl::asVector(y);
531  DUNE_ASSERT_BOUNDS(xx.N() == N());
532  DUNE_ASSERT_BOUNDS(yy.N() == M());
533  for (size_type i=0; i<rows(); i++)
534  for (size_type j=0; j<cols(); j++)
535  yy[j] += alpha*(*this)[i][j]*xx[i];
536  }
537 
539  template<class X, class Y>
540  void usmhv (const typename FieldTraits<Y>::field_type & alpha,
541  const X& x, Y& y) const
542  {
543  auto&& xx = Impl::asVector(x);
544  auto&& yy = Impl::asVector(y);
545  DUNE_ASSERT_BOUNDS(xx.N() == N());
546  DUNE_ASSERT_BOUNDS(yy.N() == M());
547  for (size_type i=0; i<rows(); i++)
548  for (size_type j=0; j<cols(); j++)
549  yy[j] +=
550  alpha*conjugateComplex((*this)[i][j])*xx[i];
551  }
552 
553  //===== norms
554 
556  typename FieldTraits<value_type>::real_type frobenius_norm () const
557  {
558  typename FieldTraits<value_type>::real_type sum=(0.0);
559  for (size_type i=0; i<rows(); ++i) sum += (*this)[i].two_norm2();
560  return fvmeta::sqrt(sum);
561  }
562 
564  typename FieldTraits<value_type>::real_type frobenius_norm2 () const
565  {
566  typename FieldTraits<value_type>::real_type sum=(0.0);
567  for (size_type i=0; i<rows(); ++i) sum += (*this)[i].two_norm2();
568  return sum;
569  }
570 
572  template <typename vt = value_type,
573  typename std::enable_if<!HasNaN<vt>::value, int>::type = 0>
574  typename FieldTraits<vt>::real_type infinity_norm() const {
575  using real_type = typename FieldTraits<vt>::real_type;
576  using std::max;
577 
578  real_type norm = 0;
579  for (auto const &x : *this) {
580  real_type const a = x.one_norm();
581  norm = max(a, norm);
582  }
583  return norm;
584  }
585 
587  template <typename vt = value_type,
588  typename std::enable_if<!HasNaN<vt>::value, int>::type = 0>
589  typename FieldTraits<vt>::real_type infinity_norm_real() const {
590  using real_type = typename FieldTraits<vt>::real_type;
591  using std::max;
592 
593  real_type norm = 0;
594  for (auto const &x : *this) {
595  real_type const a = x.one_norm_real();
596  norm = max(a, norm);
597  }
598  return norm;
599  }
600 
602  template <typename vt = value_type,
603  typename std::enable_if<HasNaN<vt>::value, int>::type = 0>
604  typename FieldTraits<vt>::real_type infinity_norm() const {
605  using real_type = typename FieldTraits<vt>::real_type;
606  using std::max;
607 
608  real_type norm = 0;
609  real_type isNaN = 1;
610  for (auto const &x : *this) {
611  real_type const a = x.one_norm();
612  norm = max(a, norm);
613  isNaN += a;
614  }
615  return norm * (isNaN / isNaN);
616  }
617 
619  template <typename vt = value_type,
620  typename std::enable_if<HasNaN<vt>::value, int>::type = 0>
621  typename FieldTraits<vt>::real_type infinity_norm_real() const {
622  using real_type = typename FieldTraits<vt>::real_type;
623  using std::max;
624 
625  real_type norm = 0;
626  real_type isNaN = 1;
627  for (auto const &x : *this) {
628  real_type const a = x.one_norm_real();
629  norm = max(a, norm);
630  isNaN += a;
631  }
632  return norm * (isNaN / isNaN);
633  }
634 
635  //===== solve
636 
641  template <class V1, class V2>
642  void solve (V1& x, const V2& b, bool doPivoting = true) const;
643 
648  void invert(bool doPivoting = true);
649 
651  field_type determinant (bool doPivoting = true) const;
652 
654  template<typename M2>
655  MAT& leftmultiply (const DenseMatrix<M2>& M)
656  {
657  DUNE_ASSERT_BOUNDS(M.rows() == M.cols());
658  DUNE_ASSERT_BOUNDS(M.rows() == rows());
659  AutonomousValue<MAT> C(asImp());
660 
661  for (size_type i=0; i<rows(); i++)
662  for (size_type j=0; j<cols(); j++) {
663  (*this)[i][j] = 0;
664  for (size_type k=0; k<rows(); k++)
665  (*this)[i][j] += M[i][k]*C[k][j];
666  }
667 
668  return asImp();
669  }
670 
672  template<typename M2>
673  MAT& rightmultiply (const DenseMatrix<M2>& M)
674  {
675  DUNE_ASSERT_BOUNDS(M.rows() == M.cols());
676  DUNE_ASSERT_BOUNDS(M.cols() == cols());
677  AutonomousValue<MAT> C(asImp());
678 
679  for (size_type i=0; i<rows(); i++)
680  for (size_type j=0; j<cols(); j++) {
681  (*this)[i][j] = 0;
682  for (size_type k=0; k<cols(); k++)
683  (*this)[i][j] += C[i][k]*M[k][j];
684  }
685  return asImp();
686  }
687 
688 #if 0
690  template<int l>
691  DenseMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M) const
692  {
693  FieldMatrix<K,l,cols> C;
694 
695  for (size_type i=0; i<l; i++) {
696  for (size_type j=0; j<cols(); j++) {
697  C[i][j] = 0;
698  for (size_type k=0; k<rows(); k++)
699  C[i][j] += M[i][k]*(*this)[k][j];
700  }
701  }
702  return C;
703  }
704 
706  template<int l>
707  FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M) const
708  {
709  FieldMatrix<K,rows,l> C;
710 
711  for (size_type i=0; i<rows(); i++) {
712  for (size_type j=0; j<l; j++) {
713  C[i][j] = 0;
714  for (size_type k=0; k<cols(); k++)
715  C[i][j] += (*this)[i][k]*M[k][j];
716  }
717  }
718  return C;
719  }
720 #endif
721 
722  //===== sizes
723 
725  constexpr size_type N () const
726  {
727  return rows();
728  }
729 
731  constexpr size_type M () const
732  {
733  return cols();
734  }
735 
737  constexpr size_type rows() const
738  {
739  return asImp().mat_rows();
740  }
741 
743  constexpr size_type cols() const
744  {
745  return asImp().mat_cols();
746  }
747 
748  //===== query
749 
751  bool exists ([[maybe_unused]] size_type i, [[maybe_unused]] size_type j) const
752  {
753  DUNE_ASSERT_BOUNDS(i >= 0 && i < rows());
754  DUNE_ASSERT_BOUNDS(j >= 0 && j < cols());
755  return true;
756  }
757 
758  protected:
759 
760 #ifndef DOXYGEN
761  struct ElimPivot
762  {
763  ElimPivot(std::vector<simd_index_type> & pivot);
764 
765  void swap(std::size_t i, simd_index_type j);
766 
767  template<typename T>
768  void operator()(const T&, int, int)
769  {}
770 
771  std::vector<simd_index_type> & pivot_;
772  };
773 
774  template<typename V>
775  struct Elim
776  {
777  Elim(V& rhs);
778 
779  void swap(std::size_t i, simd_index_type j);
780 
781  void operator()(const typename V::field_type& factor, int k, int i);
782 
783  V* rhs_;
784  };
785 
786  struct ElimDet
787  {
788  ElimDet(field_type& sign) : sign_(sign)
789  { sign_ = 1; }
790 
791  void swap(std::size_t i, simd_index_type j)
792  {
793  sign_ *=
794  Simd::cond(simd_index_type(i) == j, field_type(1), field_type(-1));
795  }
796 
797  void operator()(const field_type&, int, int)
798  {}
799 
800  field_type& sign_;
801  };
802 #endif // DOXYGEN
803 
805 
843  template<class Func, class Mask>
844  static void luDecomposition(DenseMatrix<MAT>& A, Func func,
845  Mask &nonsingularLanes, bool throwEarly, bool doPivoting);
846  };
847 
848 #ifndef DOXYGEN
849  template<typename MAT>
850  DenseMatrix<MAT>::ElimPivot::ElimPivot(std::vector<simd_index_type> & pivot)
851  : pivot_(pivot)
852  {
853  typedef typename std::vector<size_type>::size_type size_type;
854  for(size_type i=0; i < pivot_.size(); ++i) pivot_[i]=i;
855  }
856 
857  template<typename MAT>
858  void DenseMatrix<MAT>::ElimPivot::swap(std::size_t i, simd_index_type j)
859  {
860  pivot_[i] =
861  Simd::cond(Simd::Scalar<simd_index_type>(i) == j, pivot_[i], j);
862  }
863 
864  template<typename MAT>
865  template<typename V>
866  DenseMatrix<MAT>::Elim<V>::Elim(V& rhs)
867  : rhs_(&rhs)
868  {}
869 
870  template<typename MAT>
871  template<typename V>
872  void DenseMatrix<MAT>::Elim<V>::swap(std::size_t i, simd_index_type j)
873  {
874  using std::swap;
875 
876  // see the comment in luDecomposition()
877  for(std::size_t l = 0; l < Simd::lanes(j); ++l)
878  swap(Simd::lane(l, (*rhs_)[ i ]),
879  Simd::lane(l, (*rhs_)[Simd::lane(l, j)]));
880  }
881 
882  template<typename MAT>
883  template<typename V>
884  void DenseMatrix<MAT>::
885  Elim<V>::operator()(const typename V::field_type& factor, int k, int i)
886  {
887  (*rhs_)[k] -= factor*(*rhs_)[i];
888  }
889 
890  template<typename MAT>
891  template<typename Func, class Mask>
892  inline void DenseMatrix<MAT>::
893  luDecomposition(DenseMatrix<MAT>& A, Func func, Mask &nonsingularLanes,
894  bool throwEarly, bool doPivoting)
895  {
896  using std::max;
897  using std::swap;
898 
899  typedef typename FieldTraits<value_type>::real_type real_type;
900 
901  // LU decomposition of A in A
902  for (size_type i=0; i<A.rows(); i++) // loop over all rows
903  {
904  real_type pivmax = fvmeta::absreal(A[i][i]);
905 
906  if (doPivoting)
907  {
908  // compute maximum of column
909  simd_index_type imax=i;
910  for (size_type k=i+1; k<A.rows(); k++)
911  {
912  auto abs = fvmeta::absreal(A[k][i]);
913  auto mask = abs > pivmax;
914  pivmax = Simd::cond(mask, abs, pivmax);
915  imax = Simd::cond(mask, simd_index_type(k), imax);
916  }
917  // swap rows
918  for (size_type j=0; j<A.rows(); j++)
919  {
920  // This is a swap operation where the second operand is scattered,
921  // and on top of that is also extracted from deep within a
922  // moderately complicated data structure (a DenseMatrix), where we
923  // can't assume much on the memory layout. On intel processors,
924  // the only instruction that might help us here is vgather, but it
925  // is unclear whether that is even faster than a software
926  // implementation, and we would also need vscatter which does not
927  // exist. So break vectorization here and do it manually.
928  for(std::size_t l = 0; l < Simd::lanes(A[i][j]); ++l)
929  swap(Simd::lane(l, A[i][j]),
930  Simd::lane(l, A[Simd::lane(l, imax)][j]));
931  }
932  func.swap(i, imax); // swap the pivot or rhs
933  }
934 
935  // singular ?
936  nonsingularLanes = nonsingularLanes && (pivmax != real_type(0));
937  if (throwEarly) {
938  if(!Simd::allTrue(nonsingularLanes))
939  DUNE_THROW(FMatrixError, "matrix is singular");
940  }
941  else { // !throwEarly
942  if(!Simd::anyTrue(nonsingularLanes))
943  return;
944  }
945 
946  // eliminate
947  for (size_type k=i+1; k<A.rows(); k++)
948  {
949  // in the simd case, A[i][i] may be close to zero in some lanes. Pray
950  // that the result is no worse than a quiet NaN.
951  field_type factor = A[k][i]/A[i][i];
952  A[k][i] = factor;
953  for (size_type j=i+1; j<A.rows(); j++)
954  A[k][j] -= factor*A[i][j];
955  func(factor, k, i);
956  }
957  }
958  }
959 
960  template<typename MAT>
961  template <class V1, class V2>
962  inline void DenseMatrix<MAT>::solve(V1& x, const V2& b, bool doPivoting) const
963  {
964  using real_type = typename FieldTraits<value_type>::real_type;
965  // never mind those ifs, because they get optimized away
966  if (rows()!=cols())
967  DUNE_THROW(FMatrixError, "Can't solve for a " << rows() << "x" << cols() << " matrix!");
968 
969  if (rows()==1) {
970 
971 #ifdef DUNE_FMatrix_WITH_CHECKING
972  if (Simd::anyTrue(fvmeta::absreal((*this)[0][0])
973  < FMatrixPrecision<>::absolute_limit()))
974  DUNE_THROW(FMatrixError,"matrix is singular");
975 #endif
976  x[0] = b[0]/(*this)[0][0];
977 
978  }
979  else if (rows()==2) {
980 
981  field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0];
982 #ifdef DUNE_FMatrix_WITH_CHECKING
983  if (Simd::anyTrue(fvmeta::absreal(detinv)
984  < FMatrixPrecision<>::absolute_limit()))
985  DUNE_THROW(FMatrixError,"matrix is singular");
986 #endif
987  detinv = real_type(1.0)/detinv;
988 
989  x[0] = detinv*((*this)[1][1]*b[0]-(*this)[0][1]*b[1]);
990  x[1] = detinv*((*this)[0][0]*b[1]-(*this)[1][0]*b[0]);
991 
992  }
993  else if (rows()==3) {
994 
995  field_type d = determinant(doPivoting);
996 #ifdef DUNE_FMatrix_WITH_CHECKING
997  if (Simd::anyTrue(fvmeta::absreal(d)
998  < FMatrixPrecision<>::absolute_limit()))
999  DUNE_THROW(FMatrixError,"matrix is singular");
1000 #endif
1001 
1002  x[0] = (b[0]*(*this)[1][1]*(*this)[2][2] - b[0]*(*this)[2][1]*(*this)[1][2]
1003  - b[1] *(*this)[0][1]*(*this)[2][2] + b[1]*(*this)[2][1]*(*this)[0][2]
1004  + b[2] *(*this)[0][1]*(*this)[1][2] - b[2]*(*this)[1][1]*(*this)[0][2]) / d;
1005 
1006  x[1] = ((*this)[0][0]*b[1]*(*this)[2][2] - (*this)[0][0]*b[2]*(*this)[1][2]
1007  - (*this)[1][0] *b[0]*(*this)[2][2] + (*this)[1][0]*b[2]*(*this)[0][2]
1008  + (*this)[2][0] *b[0]*(*this)[1][2] - (*this)[2][0]*b[1]*(*this)[0][2]) / d;
1009 
1010  x[2] = ((*this)[0][0]*(*this)[1][1]*b[2] - (*this)[0][0]*(*this)[2][1]*b[1]
1011  - (*this)[1][0] *(*this)[0][1]*b[2] + (*this)[1][0]*(*this)[2][1]*b[0]
1012  + (*this)[2][0] *(*this)[0][1]*b[1] - (*this)[2][0]*(*this)[1][1]*b[0]) / d;
1013 
1014  }
1015  else {
1016 
1017  V1& rhs = x; // use x to store rhs
1018  rhs = b; // copy data
1019  Elim<V1> elim(rhs);
1020  AutonomousValue<MAT> A(asImp());
1021  Simd::Mask<typename FieldTraits<value_type>::real_type>
1022  nonsingularLanes(true);
1023 
1024  AutonomousValue<MAT>::luDecomposition(A, elim, nonsingularLanes, true, doPivoting);
1025 
1026  // backsolve
1027  for(int i=rows()-1; i>=0; i--) {
1028  for (size_type j=i+1; j<rows(); j++)
1029  rhs[i] -= A[i][j]*x[j];
1030  x[i] = rhs[i]/A[i][i];
1031  }
1032  }
1033  }
1034 
1035  template<typename MAT>
1036  inline void DenseMatrix<MAT>::invert(bool doPivoting)
1037  {
1038  using real_type = typename FieldTraits<MAT>::real_type;
1039  using std::swap;
1040 
1041  // never mind those ifs, because they get optimized away
1042  if (rows()!=cols())
1043  DUNE_THROW(FMatrixError, "Can't invert a " << rows() << "x" << cols() << " matrix!");
1044 
1045  if (rows()==1) {
1046 
1047 #ifdef DUNE_FMatrix_WITH_CHECKING
1048  if (Simd::anyTrue(fvmeta::absreal((*this)[0][0])
1049  < FMatrixPrecision<>::absolute_limit()))
1050  DUNE_THROW(FMatrixError,"matrix is singular");
1051 #endif
1052  (*this)[0][0] = real_type( 1 ) / (*this)[0][0];
1053 
1054  }
1055  else if (rows()==2) {
1056 
1057  field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0];
1058 #ifdef DUNE_FMatrix_WITH_CHECKING
1059  if (Simd::anyTrue(fvmeta::absreal(detinv)
1060  < FMatrixPrecision<>::absolute_limit()))
1061  DUNE_THROW(FMatrixError,"matrix is singular");
1062 #endif
1063  detinv = real_type( 1 ) / detinv;
1064 
1065  field_type temp=(*this)[0][0];
1066  (*this)[0][0] = (*this)[1][1]*detinv;
1067  (*this)[0][1] = -(*this)[0][1]*detinv;
1068  (*this)[1][0] = -(*this)[1][0]*detinv;
1069  (*this)[1][1] = temp*detinv;
1070 
1071  }
1072  else if (rows()==3)
1073  {
1074  using K = field_type;
1075  // code generated by maple
1076  K t4 = (*this)[0][0] * (*this)[1][1];
1077  K t6 = (*this)[0][0] * (*this)[1][2];
1078  K t8 = (*this)[0][1] * (*this)[1][0];
1079  K t10 = (*this)[0][2] * (*this)[1][0];
1080  K t12 = (*this)[0][1] * (*this)[2][0];
1081  K t14 = (*this)[0][2] * (*this)[2][0];
1082 
1083  K det = (t4*(*this)[2][2]-t6*(*this)[2][1]-t8*(*this)[2][2]+
1084  t10*(*this)[2][1]+t12*(*this)[1][2]-t14*(*this)[1][1]);
1085  K t17 = K(1.0)/det;
1086 
1087  K matrix01 = (*this)[0][1];
1088  K matrix00 = (*this)[0][0];
1089  K matrix10 = (*this)[1][0];
1090  K matrix11 = (*this)[1][1];
1091 
1092  (*this)[0][0] = ((*this)[1][1] * (*this)[2][2] - (*this)[1][2] * (*this)[2][1])*t17;
1093  (*this)[0][1] = -((*this)[0][1] * (*this)[2][2] - (*this)[0][2] * (*this)[2][1])*t17;
1094  (*this)[0][2] = (matrix01 * (*this)[1][2] - (*this)[0][2] * (*this)[1][1])*t17;
1095  (*this)[1][0] = -((*this)[1][0] * (*this)[2][2] - (*this)[1][2] * (*this)[2][0])*t17;
1096  (*this)[1][1] = (matrix00 * (*this)[2][2] - t14) * t17;
1097  (*this)[1][2] = -(t6-t10) * t17;
1098  (*this)[2][0] = (matrix10 * (*this)[2][1] - matrix11 * (*this)[2][0]) * t17;
1099  (*this)[2][1] = -(matrix00 * (*this)[2][1] - t12) * t17;
1100  (*this)[2][2] = (t4-t8) * t17;
1101  }
1102  else {
1103  using std::swap;
1104 
1105  AutonomousValue<MAT> A(asImp());
1106  std::vector<simd_index_type> pivot(rows());
1107  Simd::Mask<typename FieldTraits<value_type>::real_type>
1108  nonsingularLanes(true);
1109  AutonomousValue<MAT>::luDecomposition(A, ElimPivot(pivot), nonsingularLanes, true, doPivoting);
1110  auto& L=A;
1111  auto& U=A;
1112 
1113  // initialize inverse
1114  *this=field_type();
1115 
1116  for(size_type i=0; i<rows(); ++i)
1117  (*this)[i][i]=1;
1118 
1119  // L Y = I; multiple right hand sides
1120  for (size_type i=0; i<rows(); i++)
1121  for (size_type j=0; j<i; j++)
1122  for (size_type k=0; k<rows(); k++)
1123  (*this)[i][k] -= L[i][j]*(*this)[j][k];
1124 
1125  // U A^{-1} = Y
1126  for (size_type i=rows(); i>0;) {
1127  --i;
1128  for (size_type k=0; k<rows(); k++) {
1129  for (size_type j=i+1; j<rows(); j++)
1130  (*this)[i][k] -= U[i][j]*(*this)[j][k];
1131  (*this)[i][k] /= U[i][i];
1132  }
1133  }
1134 
1135  for(size_type i=rows(); i>0; ) {
1136  --i;
1137  for(std::size_t l = 0; l < Simd::lanes((*this)[0][0]); ++l)
1138  {
1139  std::size_t pi = Simd::lane(l, pivot[i]);
1140  if(i!=pi)
1141  for(size_type j=0; j<rows(); ++j)
1142  swap(Simd::lane(l, (*this)[j][pi]),
1143  Simd::lane(l, (*this)[j][ i]));
1144  }
1145  }
1146  }
1147  }
1148 
1149  // implementation of the determinant
1150  template<typename MAT>
1151  inline typename DenseMatrix<MAT>::field_type
1152  DenseMatrix<MAT>::determinant(bool doPivoting) const
1153  {
1154  // never mind those ifs, because they get optimized away
1155  if (rows()!=cols())
1156  DUNE_THROW(FMatrixError, "There is no determinant for a " << rows() << "x" << cols() << " matrix!");
1157 
1158  if (rows()==1)
1159  return (*this)[0][0];
1160 
1161  if (rows()==2)
1162  return (*this)[0][0]*(*this)[1][1] - (*this)[0][1]*(*this)[1][0];
1163 
1164  if (rows()==3) {
1165  // code generated by maple
1166  field_type t4 = (*this)[0][0] * (*this)[1][1];
1167  field_type t6 = (*this)[0][0] * (*this)[1][2];
1168  field_type t8 = (*this)[0][1] * (*this)[1][0];
1169  field_type t10 = (*this)[0][2] * (*this)[1][0];
1170  field_type t12 = (*this)[0][1] * (*this)[2][0];
1171  field_type t14 = (*this)[0][2] * (*this)[2][0];
1172 
1173  return (t4*(*this)[2][2]-t6*(*this)[2][1]-t8*(*this)[2][2]+
1174  t10*(*this)[2][1]+t12*(*this)[1][2]-t14*(*this)[1][1]);
1175 
1176  }
1177 
1178  AutonomousValue<MAT> A(asImp());
1179  field_type det;
1180  Simd::Mask<typename FieldTraits<value_type>::real_type>
1181  nonsingularLanes(true);
1182 
1183  AutonomousValue<MAT>::luDecomposition(A, ElimDet(det), nonsingularLanes, false, doPivoting);
1184  det = Simd::cond(nonsingularLanes, det, field_type(0));
1185 
1186  for (size_type i = 0; i < rows(); ++i)
1187  det *= A[i][i];
1188  return det;
1189  }
1190 
1191 #endif // DOXYGEN
1192 
1193  namespace DenseMatrixHelp {
1194 
1196  template <typename MAT, typename V1, typename V2>
1197  static inline void multAssign(const DenseMatrix<MAT> &matrix, const DenseVector<V1> & x, DenseVector<V2> & ret)
1198  {
1199  DUNE_ASSERT_BOUNDS(x.size() == matrix.cols());
1200  DUNE_ASSERT_BOUNDS(ret.size() == matrix.rows());
1201  typedef typename DenseMatrix<MAT>::size_type size_type;
1202 
1203  for(size_type i=0; i<matrix.rows(); ++i)
1204  {
1205  ret[i] = 0.0;
1206  for(size_type j=0; j<matrix.cols(); ++j)
1207  {
1208  ret[i] += matrix[i][j]*x[j];
1209  }
1210  }
1211  }
1212 
1213 #if 0
1215  template <typename K, int rows, int cols>
1216  static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret)
1217  {
1218  typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
1219 
1220  for(size_type i=0; i<cols(); ++i)
1221  {
1222  ret[i] = 0.0;
1223  for(size_type j=0; j<rows(); ++j)
1224  ret[i] += matrix[j][i]*x[j];
1225  }
1226  }
1227 
1229  template <typename K, int rows, int cols>
1230  static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x)
1231  {
1232  FieldVector<K,rows> ret;
1233  multAssign(matrix,x,ret);
1234  return ret;
1235  }
1236 
1238  template <typename K, int rows, int cols>
1239  static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x)
1240  {
1241  FieldVector<K,cols> ret;
1242  multAssignTransposed( matrix, x, ret );
1243  return ret;
1244  }
1245 #endif
1246 
1247  } // end namespace DenseMatrixHelp
1248 
1250  template<typename MAT>
1251  std::ostream& operator<< (std::ostream& s, const DenseMatrix<MAT>& a)
1252  {
1253  for (typename DenseMatrix<MAT>::size_type i=0; i<a.rows(); i++)
1254  s << a[i] << std::endl;
1255  return s;
1256  }
1257 
1260 } // end namespace Dune
1261 
1262 #endif
Macro for wrapping boundary checks.
A free function to provide the demangled class name of a given object or type as a string.
Definition of the DUNE_DEPRECATED macro for the case that config.h is not available.
A few common exception classes.
Traits for type conversions and type information.
Implements a vector constructed from a given type representing a field and a compile-time given size.
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:11
Various precision settings for calculations with FieldMatrix and FieldVector.
Implements a scalar vector view wrapper around an existing scalar.
Include file for users of the SIMD abstraction layer.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 10, 22:30, 2024)