1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2020 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_full_matrix_templates_h
17 #define dealii_full_matrix_templates_h
18 
19 
20 // TODO: this file has a lot of operations between matrices and matrices or
21 // matrices and vectors of different precision. we should go through the
22 // file and in each case pick the more accurate data type for intermediate
23 // results. currently, the choice is pretty much random. this may also allow
24 // us some operations where one operand is complex and the other is not
25 // -> use ProductType<T,U> type trait for the results
26 
27 #include <deal.II/base/config.h>
28 
29 #include <deal.II/base/template_constraints.h>
30 
31 #include <deal.II/lac/full_matrix.h>
32 #include <deal.II/lac/lapack_full_matrix.h>
33 #include <deal.II/lac/lapack_templates.h>
34 #include <deal.II/lac/vector.h>
35 
36 #include <algorithm>
37 #include <cmath>
38 #include <cstdio>
39 #include <cstdlib>
40 #include <vector>
41 
42 DEAL_II_NAMESPACE_OPEN
43 
44 
45 template <typename number>
FullMatrix(const size_type n)46 FullMatrix<number>::FullMatrix(const size_type n)
47   : Table<2, number>(n, n)
48 {}
49 
50 
51 template <typename number>
FullMatrix(const size_type m,const size_type n)52 FullMatrix<number>::FullMatrix(const size_type m, const size_type n)
53   : Table<2, number>(m, n)
54 {}
55 
56 
57 template <typename number>
FullMatrix(const size_type m,const size_type n,const number * entries)58 FullMatrix<number>::FullMatrix(const size_type m,
59                                const size_type n,
60                                const number *  entries)
61   : Table<2, number>(m, n)
62 {
63   this->fill(entries);
64 }
65 
66 
67 
68 template <typename number>
FullMatrix(const IdentityMatrix & id)69 FullMatrix<number>::FullMatrix(const IdentityMatrix &id)
70   : Table<2, number>(id.m(), id.n())
71 {
72   for (size_type i = 0; i < id.m(); ++i)
73     (*this)(i, i) = 1;
74 }
75 
76 
77 
78 template <typename number>
79 template <typename number2>
80 FullMatrix<number> &
81 FullMatrix<number>::operator=(const FullMatrix<number2> &M)
82 {
83   TableBase<2, number>::operator=(M);
84   return *this;
85 }
86 
87 
88 
89 template <typename number>
90 FullMatrix<number> &
91 FullMatrix<number>::operator=(const IdentityMatrix &id)
92 {
93   this->reinit(id.m(), id.n());
94   for (size_type i = 0; i < id.m(); ++i)
95     (*this)(i, i) = 1.;
96 
97   return *this;
98 }
99 
100 
101 
102 template <typename number>
103 template <typename number2>
104 FullMatrix<number> &
105 FullMatrix<number>::operator=(const LAPACKFullMatrix<number2> &M)
106 {
107   Assert(this->m() == M.n_rows(), ExcDimensionMismatch(this->m(), M.n_rows()));
108   Assert(this->n() == M.n_cols(), ExcDimensionMismatch(this->n(), M.n_cols()));
109   for (size_type i = 0; i < this->m(); ++i)
110     for (size_type j = 0; j < this->n(); ++j)
111       (*this)(i, j) = M(i, j);
112 
113   return *this;
114 }
115 
116 
117 
118 template <typename number>
119 bool
all_zero()120 FullMatrix<number>::all_zero() const
121 {
122   Assert(!this->empty(), ExcEmptyMatrix());
123 
124   const number *      p = this->values.data();
125   const number *const e = this->values.data() + this->n_elements();
126   while (p != e)
127     if (*p++ != number(0.0))
128       return false;
129 
130   return true;
131 }
132 
133 
134 
135 template <typename number>
136 FullMatrix<number> &
137 FullMatrix<number>::operator*=(const number factor)
138 {
139   AssertIsFinite(factor);
140   for (number &v : this->values)
141     v *= factor;
142 
143   return *this;
144 }
145 
146 
147 
148 template <typename number>
149 FullMatrix<number> &
150 FullMatrix<number>::operator/=(const number factor)
151 {
152   AssertIsFinite(factor);
153   const number factor_inv = number(1.) / factor;
154 
155   return *this *= factor_inv;
156 }
157 
158 
159 
160 template <typename number>
161 template <typename number2>
162 void
vmult(Vector<number2> & dst,const Vector<number2> & src,const bool adding)163 FullMatrix<number>::vmult(Vector<number2> &      dst,
164                           const Vector<number2> &src,
165                           const bool             adding) const
166 {
167   Assert(!this->empty(), ExcEmptyMatrix());
168 
169   Assert(dst.size() == m(), ExcDimensionMismatch(dst.size(), m()));
170   Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
171 
172   Assert(&src != &dst, ExcSourceEqualsDestination());
173 
174   const number *e = this->values.data();
175   // get access to the data in order to
176   // avoid copying it when using the ()
177   // operator
178   const number2 * src_ptr = src.begin();
179   const size_type size_m = m(), size_n = n();
180   for (size_type i = 0; i < size_m; ++i)
181     {
182       number2 s = adding ? dst(i) : 0.;
183       for (size_type j = 0; j < size_n; ++j)
184         s += src_ptr[j] * number2(*(e++));
185       dst(i) = s;
186     }
187 }
188 
189 
190 
191 template <typename number>
192 template <typename number2>
193 void
Tvmult(Vector<number2> & dst,const Vector<number2> & src,const bool adding)194 FullMatrix<number>::Tvmult(Vector<number2> &      dst,
195                            const Vector<number2> &src,
196                            const bool             adding) const
197 {
198   Assert(!this->empty(), ExcEmptyMatrix());
199 
200   Assert(dst.size() == n(), ExcDimensionMismatch(dst.size(), n()));
201   Assert(src.size() == m(), ExcDimensionMismatch(src.size(), m()));
202 
203   Assert(&src != &dst, ExcSourceEqualsDestination());
204 
205   const number *  e       = this->values.data();
206   number2 *       dst_ptr = &dst(0);
207   const size_type size_m = m(), size_n = n();
208 
209   // zero out data if we are not adding
210   if (!adding)
211     for (size_type j = 0; j < size_n; ++j)
212       dst_ptr[j] = 0.;
213 
214   // write the loop in a way that we can
215   // access the data contiguously
216   for (size_type i = 0; i < size_m; ++i)
217     {
218       const number2 d = src(i);
219       for (size_type j = 0; j < size_n; ++j)
220         dst_ptr[j] += d * number2(*(e++));
221     };
222 }
223 
224 
225 template <typename number>
226 template <typename number2, typename number3>
227 number
residual(Vector<number2> & dst,const Vector<number2> & src,const Vector<number3> & right)228 FullMatrix<number>::residual(Vector<number2> &      dst,
229                              const Vector<number2> &src,
230                              const Vector<number3> &right) const
231 {
232   Assert(!this->empty(), ExcEmptyMatrix());
233 
234   Assert(dst.size() == m(), ExcDimensionMismatch(dst.size(), m()));
235   Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
236   Assert(right.size() == m(), ExcDimensionMismatch(right.size(), m()));
237 
238   Assert(&src != &dst, ExcSourceEqualsDestination());
239 
240   number          res    = 0.;
241   const size_type size_m = m(), size_n = n();
242   for (size_type i = 0; i < size_m; ++i)
243     {
244       number s = number(right(i));
245       for (size_type j = 0; j < size_n; ++j)
246         s -= number(src(j)) * (*this)(i, j);
247       dst(i) = s;
248       res += s * s;
249     }
250   return std::sqrt(res);
251 }
252 
253 
254 
255 template <typename number>
256 template <typename number2>
257 void
forward(Vector<number2> & dst,const Vector<number2> & src)258 FullMatrix<number>::forward(Vector<number2> &      dst,
259                             const Vector<number2> &src) const
260 {
261   Assert(!this->empty(), ExcEmptyMatrix());
262 
263   Assert(dst.size() == m(), ExcDimensionMismatch(dst.size(), m()));
264   Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
265 
266   size_type i, j;
267   size_type nu = ((m() < n()) ? m() : n());
268   for (i = 0; i < nu; ++i)
269     {
270       typename ProductType<number, number2>::type s = src(i);
271       for (j = 0; j < i; ++j)
272         s -=
273           typename ProductType<number, number2>::type(dst(j)) * (*this)(i, j);
274       dst(i) = number2(s) / number2((*this)(i, i));
275       AssertIsFinite(dst(i));
276     }
277 }
278 
279 
280 
281 template <typename number>
282 template <typename number2>
283 void
backward(Vector<number2> & dst,const Vector<number2> & src)284 FullMatrix<number>::backward(Vector<number2> &      dst,
285                              const Vector<number2> &src) const
286 {
287   Assert(!this->empty(), ExcEmptyMatrix());
288 
289   size_type j;
290   size_type nu = (m() < n() ? m() : n());
291   for (std::make_signed<size_type>::type i = nu - 1; i >= 0; --i)
292     {
293       typename ProductType<number, number2>::type s = src(i);
294       for (j = i + 1; j < nu; ++j)
295         s -=
296           typename ProductType<number, number2>::type(dst(j)) * (*this)(i, j);
297       dst(i) = number2(s) / number2((*this)(i, i));
298       AssertIsFinite(dst(i));
299     }
300 }
301 
302 
303 
304 template <typename number>
305 template <typename number2>
306 void
fill(const FullMatrix<number2> & src,const size_type dst_offset_i,const size_type dst_offset_j,const size_type src_offset_i,const size_type src_offset_j)307 FullMatrix<number>::fill(const FullMatrix<number2> &src,
308                          const size_type            dst_offset_i,
309                          const size_type            dst_offset_j,
310                          const size_type            src_offset_i,
311                          const size_type            src_offset_j)
312 {
313   AssertIndexRange(dst_offset_i, m());
314   AssertIndexRange(dst_offset_j, n());
315   AssertIndexRange(src_offset_i, src.m());
316   AssertIndexRange(src_offset_j, src.n());
317 
318   // Compute maximal size of copied block
319   const size_type rows = std::min(m() - dst_offset_i, src.m() - src_offset_i);
320   const size_type cols = std::min(n() - dst_offset_j, src.n() - src_offset_j);
321 
322   for (size_type i = 0; i < rows; ++i)
323     for (size_type j = 0; j < cols; ++j)
324       (*this)(dst_offset_i + i, dst_offset_j + j) =
325         src(src_offset_i + i, src_offset_j + j);
326 }
327 
328 
329 template <typename number>
330 template <typename number2>
331 void
fill_permutation(const FullMatrix<number2> & src,const std::vector<size_type> & p_rows,const std::vector<size_type> & p_cols)332 FullMatrix<number>::fill_permutation(const FullMatrix<number2> &   src,
333                                      const std::vector<size_type> &p_rows,
334                                      const std::vector<size_type> &p_cols)
335 {
336   Assert(p_rows.size() == this->n_rows(),
337          ExcDimensionMismatch(p_rows.size(), this->n_rows()));
338   Assert(p_cols.size() == this->n_cols(),
339          ExcDimensionMismatch(p_cols.size(), this->n_cols()));
340 
341   for (size_type i = 0; i < this->n_rows(); ++i)
342     for (size_type j = 0; j < this->n_cols(); ++j)
343       (*this)(i, j) = src(p_rows[i], p_cols[j]);
344 }
345 
346 
347 
348 template <typename number>
349 void
add_row(const size_type i,const number s,const size_type j)350 FullMatrix<number>::add_row(const size_type i,
351                             const number    s,
352                             const size_type j)
353 {
354   Assert(!this->empty(), ExcEmptyMatrix());
355 
356   for (size_type k = 0; k < n(); ++k)
357     (*this)(i, k) += s * (*this)(j, k);
358 }
359 
360 
361 template <typename number>
362 void
add_row(const size_type i,const number s,const size_type j,const number t,const size_type k)363 FullMatrix<number>::add_row(const size_type i,
364                             const number    s,
365                             const size_type j,
366                             const number    t,
367                             const size_type k)
368 {
369   Assert(!this->empty(), ExcEmptyMatrix());
370 
371   const size_type size_m = n();
372   for (size_type l = 0; l < size_m; ++l)
373     (*this)(i, l) += s * (*this)(j, l) + t * (*this)(k, l);
374 }
375 
376 
377 template <typename number>
378 void
add_col(const size_type i,const number s,const size_type j)379 FullMatrix<number>::add_col(const size_type i,
380                             const number    s,
381                             const size_type j)
382 {
383   Assert(!this->empty(), ExcEmptyMatrix());
384 
385   for (size_type k = 0; k < m(); ++k)
386     (*this)(k, i) += s * (*this)(k, j);
387 }
388 
389 
390 template <typename number>
391 void
add_col(const size_type i,const number s,const size_type j,const number t,const size_type k)392 FullMatrix<number>::add_col(const size_type i,
393                             const number    s,
394                             const size_type j,
395                             const number    t,
396                             const size_type k)
397 {
398   Assert(!this->empty(), ExcEmptyMatrix());
399 
400   for (std::size_t l = 0; l < m(); ++l)
401     (*this)(l, i) += s * (*this)(l, j) + t * (*this)(l, k);
402 }
403 
404 
405 
406 template <typename number>
407 void
swap_row(const size_type i,const size_type j)408 FullMatrix<number>::swap_row(const size_type i, const size_type j)
409 {
410   Assert(!this->empty(), ExcEmptyMatrix());
411 
412   for (size_type k = 0; k < n(); ++k)
413     std::swap((*this)(i, k), (*this)(j, k));
414 }
415 
416 
417 template <typename number>
418 void
swap_col(const size_type i,const size_type j)419 FullMatrix<number>::swap_col(const size_type i, const size_type j)
420 {
421   Assert(!this->empty(), ExcEmptyMatrix());
422 
423   for (size_type k = 0; k < m(); ++k)
424     std::swap((*this)(k, i), (*this)(k, j));
425 }
426 
427 
428 template <typename number>
429 void
diagadd(const number src)430 FullMatrix<number>::diagadd(const number src)
431 {
432   Assert(!this->empty(), ExcEmptyMatrix());
433   Assert(m() == n(), ExcDimensionMismatch(m(), n()));
434 
435   for (size_type i = 0; i < n(); ++i)
436     (*this)(i, i) += src;
437 }
438 
439 
440 template <typename number>
441 template <typename number2>
442 void
equ(const number a,const FullMatrix<number2> & A)443 FullMatrix<number>::equ(const number a, const FullMatrix<number2> &A)
444 {
445   Assert(!this->empty(), ExcEmptyMatrix());
446 
447   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
448   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
449 
450   for (size_type i = 0; i < m(); ++i)
451     for (size_type j = 0; j < n(); ++j)
452       (*this)(i, j) = a * number(A(i, j));
453 }
454 
455 
456 template <typename number>
457 template <typename number2>
458 void
equ(const number a,const FullMatrix<number2> & A,const number b,const FullMatrix<number2> & B)459 FullMatrix<number>::equ(const number               a,
460                         const FullMatrix<number2> &A,
461                         const number               b,
462                         const FullMatrix<number2> &B)
463 {
464   Assert(!this->empty(), ExcEmptyMatrix());
465 
466   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
467   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
468   Assert(m() == B.m(), ExcDimensionMismatch(m(), B.m()));
469   Assert(n() == B.n(), ExcDimensionMismatch(n(), B.n()));
470 
471   for (size_type i = 0; i < m(); ++i)
472     for (size_type j = 0; j < n(); ++j)
473       (*this)(i, j) = a * number(A(i, j)) + b * number(B(i, j));
474 }
475 
476 
477 template <typename number>
478 template <typename number2>
479 void
equ(const number a,const FullMatrix<number2> & A,const number b,const FullMatrix<number2> & B,const number c,const FullMatrix<number2> & C)480 FullMatrix<number>::equ(const number               a,
481                         const FullMatrix<number2> &A,
482                         const number               b,
483                         const FullMatrix<number2> &B,
484                         const number               c,
485                         const FullMatrix<number2> &C)
486 {
487   Assert(!this->empty(), ExcEmptyMatrix());
488 
489   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
490   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
491   Assert(m() == B.m(), ExcDimensionMismatch(m(), B.m()));
492   Assert(n() == B.n(), ExcDimensionMismatch(n(), B.n()));
493   Assert(m() == C.m(), ExcDimensionMismatch(m(), C.m()));
494   Assert(n() == C.n(), ExcDimensionMismatch(n(), C.n()));
495 
496   for (size_type i = 0; i < m(); ++i)
497     for (size_type j = 0; j < n(); ++j)
498       (*this)(i, j) =
499         a * number(A(i, j)) + b * number(B(i, j)) + c * number(C(i, j));
500 }
501 
502 
503 
504 template <typename number>
505 template <typename number2>
506 void
mmult(FullMatrix<number2> & dst,const FullMatrix<number2> & src,const bool adding)507 FullMatrix<number>::mmult(FullMatrix<number2> &      dst,
508                           const FullMatrix<number2> &src,
509                           const bool                 adding) const
510 {
511   Assert(!this->empty(), ExcEmptyMatrix());
512   Assert(n() == src.m(), ExcDimensionMismatch(n(), src.m()));
513   Assert(dst.n() == src.n(), ExcDimensionMismatch(dst.n(), src.n()));
514   Assert(dst.m() == m(), ExcDimensionMismatch(m(), dst.m()));
515 
516   // see if we can use BLAS algorithms for this and if the type for 'number'
517   // works for us (it is usually not efficient to use BLAS for very small
518   // matrices):
519 #ifdef DEAL_II_WITH_LAPACK
520   const size_type max_blas_int = std::numeric_limits<types::blas_int>::max();
521   if ((std::is_same<number, double>::value ||
522        std::is_same<number, float>::value) &&
523       std::is_same<number, number2>::value)
524     if (this->n() * this->m() * src.n() > 300 && src.n() <= max_blas_int &&
525         this->m() <= max_blas_int && this->n() <= max_blas_int)
526       {
527         // In case we have the BLAS function gemm detected by CMake, we
528         // use that algorithm for matrix-matrix multiplication since it
529         // provides better performance than the deal.II native function (it
530         // uses cache and register blocking in order to access local data).
531         //
532         // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
533         // values in one column, then all in the next, etc.), whereas the
534         // FullMatrix stores them row-wise.  We ignore that difference, and
535         // give our row-wise data to BLAS, let BLAS build the product of
536         // transpose matrices, and read the result as if it were row-wise
537         // again. In other words, we calculate (B^T A^T)^T, which is AB.
538 
539         const types::blas_int m       = static_cast<types::blas_int>(src.n());
540         const types::blas_int n       = static_cast<types::blas_int>(this->m());
541         const types::blas_int k       = static_cast<types::blas_int>(this->n());
542         const char *          notrans = "n";
543 
544         const number alpha = 1.;
545         const number beta  = (adding == true) ? 1. : 0.;
546 
547         // Use the BLAS function gemm for calculating the matrix-matrix
548         // product.
549         gemm(notrans,
550              notrans,
551              &m,
552              &n,
553              &k,
554              &alpha,
555              &src(0, 0),
556              &m,
557              this->values.data(),
558              &k,
559              &beta,
560              &dst(0, 0),
561              &m);
562 
563         return;
564       }
565 
566 #endif
567 
568   const size_type m = this->m(), n = src.n(), l = this->n();
569 
570   // arrange the loops in a way that we keep write operations low, (writing is
571   // usually more costly than reading), even though we need to access the data
572   // in src not in a contiguous way.
573   for (size_type i = 0; i < m; ++i)
574     for (size_type j = 0; j < n; ++j)
575       {
576         number2 add_value = adding ? dst(i, j) : 0.;
577         for (size_type k = 0; k < l; ++k)
578           add_value += static_cast<number2>((*this)(i, k)) *
579                        static_cast<number2>((src(k, j)));
580         dst(i, j) = add_value;
581       }
582 }
583 
584 
585 
586 template <typename number>
587 template <typename number2>
588 void
Tmmult(FullMatrix<number2> & dst,const FullMatrix<number2> & src,const bool adding)589 FullMatrix<number>::Tmmult(FullMatrix<number2> &      dst,
590                            const FullMatrix<number2> &src,
591                            const bool                 adding) const
592 {
593   Assert(!this->empty(), ExcEmptyMatrix());
594   Assert(m() == src.m(), ExcDimensionMismatch(m(), src.m()));
595   Assert(n() == dst.m(), ExcDimensionMismatch(n(), dst.m()));
596   Assert(src.n() == dst.n(), ExcDimensionMismatch(src.n(), dst.n()));
597 
598 
599   // see if we can use BLAS algorithms for this and if the type for 'number'
600   // works for us (it is usually not efficient to use BLAS for very small
601   // matrices):
602 #ifdef DEAL_II_WITH_LAPACK
603   const size_type max_blas_int = std::numeric_limits<types::blas_int>::max();
604   if ((std::is_same<number, double>::value ||
605        std::is_same<number, float>::value) &&
606       std::is_same<number, number2>::value)
607     if (this->n() * this->m() * src.n() > 300 && src.n() <= max_blas_int &&
608         this->n() <= max_blas_int && this->m() <= max_blas_int)
609       {
610         // In case we have the BLAS function gemm detected by CMake, we
611         // use that algorithm for matrix-matrix multiplication since it
612         // provides better performance than the deal.II native function (it
613         // uses cache and register blocking in order to access local data).
614         //
615         // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
616         // values in one column, then all in the next, etc.), whereas the
617         // FullMatrix stores them row-wise.  We ignore that difference, and
618         // give our row-wise data to BLAS, let BLAS build the product of
619         // transpose matrices, and read the result as if it were row-wise
620         // again. In other words, we calculate (B^T A)^T, which is A^T B.
621 
622         const types::blas_int m       = static_cast<types::blas_int>(src.n());
623         const types::blas_int n       = static_cast<types::blas_int>(this->n());
624         const types::blas_int k       = static_cast<types::blas_int>(this->m());
625         const char *          trans   = "t";
626         const char *          notrans = "n";
627 
628         const number alpha = 1.;
629         const number beta  = (adding == true) ? 1. : 0.;
630 
631         // Use the BLAS function gemm for calculating the matrix-matrix
632         // product.
633         gemm(notrans,
634              trans,
635              &m,
636              &n,
637              &k,
638              &alpha,
639              &src(0, 0),
640              &m,
641              this->values.data(),
642              &n,
643              &beta,
644              &dst(0, 0),
645              &m);
646 
647         return;
648       }
649 
650 #endif
651 
652   const size_type m = n(), n = src.n(), l = this->m();
653 
654   // symmetric matrix if the two matrices are the same
655   if (PointerComparison::equal(this, &src))
656     for (size_type i = 0; i < m; ++i)
657       for (size_type j = i; j < m; ++j)
658         {
659           number2 add_value = 0.;
660           for (size_type k = 0; k < l; ++k)
661             add_value += static_cast<number2>((*this)(k, i)) *
662                          static_cast<number2>((*this)(k, j));
663           if (adding)
664             {
665               dst(i, j) += add_value;
666               if (i < j)
667                 dst(j, i) += add_value;
668             }
669           else
670             dst(i, j) = dst(j, i) = add_value;
671         }
672   // arrange the loops in a way that we keep write operations low, (writing is
673   // usually more costly than reading), even though we need to access the data
674   // in src not in a contiguous way. However, we should usually end up in the
675   // optimized gemm operation in case the matrix is big, so this shouldn't be
676   // too bad.
677   else
678     for (size_type i = 0; i < m; ++i)
679       for (size_type j = 0; j < n; ++j)
680         {
681           number2 add_value = adding ? dst(i, j) : 0.;
682           for (size_type k = 0; k < l; ++k)
683             add_value += static_cast<number2>((*this)(k, i)) *
684                          static_cast<number2>((src(k, j)));
685           dst(i, j) = add_value;
686         }
687 }
688 
689 
690 
691 template <typename number>
692 template <typename number2>
693 void
mTmult(FullMatrix<number2> & dst,const FullMatrix<number2> & src,const bool adding)694 FullMatrix<number>::mTmult(FullMatrix<number2> &      dst,
695                            const FullMatrix<number2> &src,
696                            const bool                 adding) const
697 {
698   Assert(!this->empty(), ExcEmptyMatrix());
699   Assert(n() == src.n(), ExcDimensionMismatch(n(), src.n()));
700   Assert(dst.n() == src.m(), ExcDimensionMismatch(dst.n(), src.m()));
701   Assert(dst.m() == m(), ExcDimensionMismatch(m(), dst.m()));
702 
703   // see if we can use BLAS algorithms for this and if the type for 'number'
704   // works for us (it is usually not efficient to use BLAS for very small
705   // matrices):
706 #ifdef DEAL_II_WITH_LAPACK
707   const size_type max_blas_int = std::numeric_limits<types::blas_int>::max();
708   if ((std::is_same<number, double>::value ||
709        std::is_same<number, float>::value) &&
710       std::is_same<number, number2>::value)
711     if (this->n() * this->m() * src.m() > 300 && src.m() <= max_blas_int &&
712         this->n() <= max_blas_int && this->m() <= max_blas_int)
713       {
714         // In case we have the BLAS function gemm detected by CMake, we
715         // use that algorithm for matrix-matrix multiplication since it
716         // provides better performance than the deal.II native function (it
717         // uses cache and register blocking in order to access local data).
718         //
719         // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
720         // values in one column, then all in the next, etc.), whereas the
721         // FullMatrix stores them row-wise.  We ignore that difference, and
722         // give our row-wise data to BLAS, let BLAS build the product of
723         // transpose matrices, and read the result as if it were row-wise
724         // again. In other words, we calculate (B A^T)^T, which is AB^T.
725 
726         const types::blas_int m       = static_cast<types::blas_int>(src.m());
727         const types::blas_int n       = static_cast<types::blas_int>(this->m());
728         const types::blas_int k       = static_cast<types::blas_int>(this->n());
729         const char *          notrans = "n";
730         const char *          trans   = "t";
731 
732         const number alpha = 1.;
733         const number beta  = (adding == true) ? 1. : 0.;
734 
735         // Use the BLAS function gemm for calculating the matrix-matrix
736         // product.
737         gemm(trans,
738              notrans,
739              &m,
740              &n,
741              &k,
742              &alpha,
743              &src(0, 0),
744              &k,
745              this->values.data(),
746              &k,
747              &beta,
748              &dst(0, 0),
749              &m);
750 
751         return;
752       }
753 
754 #endif
755 
756   const size_type m = this->m(), n = src.m(), l = this->n();
757 
758   // symmetric matrix if the two matrices are the same
759   if (PointerComparison::equal(this, &src))
760     for (size_type i = 0; i < m; ++i)
761       for (size_type j = i; j < m; ++j)
762         {
763           number2 add_value = 0.;
764           for (size_type k = 0; k < l; ++k)
765             add_value += static_cast<number2>((*this)(i, k)) *
766                          static_cast<number2>((*this)(j, k));
767           if (adding)
768             {
769               dst(i, j) += add_value;
770               if (i < j)
771                 dst(j, i) += add_value;
772             }
773           else
774             dst(i, j) = dst(j, i) = add_value;
775         }
776   else
777     // arrange the loops in a way that we keep write operations low, (writing is
778     // usually more costly than reading).
779     for (size_type i = 0; i < m; ++i)
780       for (size_type j = 0; j < n; ++j)
781         {
782           number2 add_value = adding ? dst(i, j) : 0.;
783           for (size_type k = 0; k < l; ++k)
784             add_value += static_cast<number2>((*this)(i, k)) *
785                          static_cast<number2>(src(j, k));
786           dst(i, j) = add_value;
787         }
788 }
789 
790 
791 
792 template <typename number>
793 template <typename number2>
794 void
TmTmult(FullMatrix<number2> & dst,const FullMatrix<number2> & src,const bool adding)795 FullMatrix<number>::TmTmult(FullMatrix<number2> &      dst,
796                             const FullMatrix<number2> &src,
797                             const bool                 adding) const
798 {
799   Assert(!this->empty(), ExcEmptyMatrix());
800   Assert(m() == src.n(), ExcDimensionMismatch(m(), src.n()));
801   Assert(n() == dst.m(), ExcDimensionMismatch(n(), dst.m()));
802   Assert(src.m() == dst.n(), ExcDimensionMismatch(src.m(), dst.n()));
803 
804 
805   // see if we can use BLAS algorithms for this and if the type for 'number'
806   // works for us (it is usually not efficient to use BLAS for very small
807   // matrices):
808 #ifdef DEAL_II_WITH_LAPACK
809   const size_type max_blas_int = std::numeric_limits<types::blas_int>::max();
810   if ((std::is_same<number, double>::value ||
811        std::is_same<number, float>::value) &&
812       std::is_same<number, number2>::value)
813     if (this->n() * this->m() * src.m() > 300 && src.m() <= max_blas_int &&
814         this->n() <= max_blas_int && this->m() <= max_blas_int)
815       {
816         // In case we have the BLAS function gemm detected by CMake, we
817         // use that algorithm for matrix-matrix multiplication since it
818         // provides better performance than the deal.II native function (it
819         // uses cache and register blocking in order to access local data).
820         //
821         // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
822         // values in one column, then all in the next, etc.), whereas the
823         // FullMatrix stores them row-wise.  We ignore that difference, and
824         // give our row-wise data to BLAS, let BLAS build the product of
825         // transpose matrices, and read the result as if it were row-wise
826         // again. In other words, we calculate (B A)^T, which is A^T B^T.
827 
828         const types::blas_int m     = static_cast<types::blas_int>(src.m());
829         const types::blas_int n     = static_cast<types::blas_int>(this->n());
830         const types::blas_int k     = static_cast<types::blas_int>(this->m());
831         const char *          trans = "t";
832 
833         const number alpha = 1.;
834         const number beta  = (adding == true) ? 1. : 0.;
835 
836         // Use the BLAS function gemm for calculating the matrix-matrix
837         // product.
838         gemm(trans,
839              trans,
840              &m,
841              &n,
842              &k,
843              &alpha,
844              &src(0, 0),
845              &k,
846              this->values.data(),
847              &n,
848              &beta,
849              &dst(0, 0),
850              &m);
851 
852         return;
853       }
854 
855 #endif
856 
857   const size_type m = n(), n = src.m(), l = this->m();
858 
859   // arrange the loops in a way that we keep write operations low, (writing is
860   // usually more costly than reading), even though we need to access the data
861   // in the calling matrix in a non-contiguous way, possibly leading to cache
862   // misses. However, we should usually end up in the optimized gemm operation
863   // in case the matrix is big, so this shouldn't be too bad.
864   for (size_type i = 0; i < m; ++i)
865     for (size_type j = 0; j < n; ++j)
866       {
867         number2 add_value = adding ? dst(i, j) : 0.;
868         for (size_type k = 0; k < l; ++k)
869           add_value += static_cast<number2>((*this)(k, i)) *
870                        static_cast<number2>(src(j, k));
871         dst(i, j) = add_value;
872       }
873 }
874 
875 
876 template <typename number>
877 void
triple_product(const FullMatrix<number> & A,const FullMatrix<number> & B,const FullMatrix<number> & D,const bool transpose_B,const bool transpose_D,const number scaling)878 FullMatrix<number>::triple_product(const FullMatrix<number> &A,
879                                    const FullMatrix<number> &B,
880                                    const FullMatrix<number> &D,
881                                    const bool                transpose_B,
882                                    const bool                transpose_D,
883                                    const number              scaling)
884 {
885   if (transpose_B)
886     {
887       AssertDimension(B.m(), A.m());
888       AssertDimension(B.n(), m());
889     }
890   else
891     {
892       AssertDimension(B.n(), A.m());
893       AssertDimension(B.m(), m());
894     }
895   if (transpose_D)
896     {
897       AssertDimension(D.n(), A.n());
898       AssertDimension(D.m(), n());
899     }
900   else
901     {
902       AssertDimension(D.m(), A.n());
903       AssertDimension(D.n(), n());
904     }
905 
906   // For all entries of the product
907   // AD
908   for (size_type i = 0; i < A.m(); ++i)
909     for (size_type j = 0; j < n(); ++j)
910       {
911         // Compute the entry
912         number ADij = 0.;
913         if (transpose_D)
914           for (size_type k = 0; k < A.n(); ++k)
915             ADij += A(i, k) * D(j, k);
916         else
917           for (size_type k = 0; k < A.n(); ++k)
918             ADij += A(i, k) * D(k, j);
919         // And add it to this after
920         // multiplying with the right
921         // factor from B
922         if (transpose_B)
923           for (size_type k = 0; k < m(); ++k)
924             this->operator()(k, j) += scaling * ADij * B(i, k);
925         else
926           for (size_type k = 0; k < m(); ++k)
927             this->operator()(k, j) += scaling * ADij * B(k, i);
928       }
929 }
930 
931 
932 template <typename number>
933 template <typename number2>
934 number2
matrix_norm_square(const Vector<number2> & v)935 FullMatrix<number>::matrix_norm_square(const Vector<number2> &v) const
936 {
937   Assert(!this->empty(), ExcEmptyMatrix());
938 
939   Assert(m() == v.size(), ExcDimensionMismatch(m(), v.size()));
940   Assert(n() == v.size(), ExcDimensionMismatch(n(), v.size()));
941 
942   number2         sum     = 0.;
943   const size_type n_rows  = m();
944   const number *  val_ptr = this->values.data();
945 
946   for (size_type row = 0; row < n_rows; ++row)
947     {
948       number2             s              = 0.;
949       const number *const val_end_of_row = val_ptr + n_rows;
950       const number2 *     v_ptr          = v.begin();
951       while (val_ptr != val_end_of_row)
952         s += number2(*val_ptr++) * number2(*v_ptr++);
953 
954       sum += s * numbers::NumberTraits<number2>::conjugate(v(row));
955     }
956 
957   return sum;
958 }
959 
960 
961 template <typename number>
962 template <typename number2>
963 number2
matrix_scalar_product(const Vector<number2> & u,const Vector<number2> & v)964 FullMatrix<number>::matrix_scalar_product(const Vector<number2> &u,
965                                           const Vector<number2> &v) const
966 {
967   Assert(!this->empty(), ExcEmptyMatrix());
968 
969   Assert(m() == u.size(), ExcDimensionMismatch(m(), u.size()));
970   Assert(n() == v.size(), ExcDimensionMismatch(n(), v.size()));
971 
972   number2         sum     = 0.;
973   const size_type n_rows  = m();
974   const size_type n_cols  = n();
975   const number *  val_ptr = this->values.data();
976 
977   for (size_type row = 0; row < n_rows; ++row)
978     {
979       number2             s              = number2(0.);
980       const number *const val_end_of_row = val_ptr + n_cols;
981       const number2 *     v_ptr          = v.begin();
982       while (val_ptr != val_end_of_row)
983         s += number2(*val_ptr++) * number2(*v_ptr++);
984 
985       sum += s * u(row);
986     }
987 
988   return sum;
989 }
990 
991 
992 
993 template <typename number>
994 void
symmetrize()995 FullMatrix<number>::symmetrize()
996 {
997   Assert(m() == n(), ExcNotQuadratic());
998 
999   const size_type N = m();
1000   for (size_type i = 0; i < N; ++i)
1001     for (size_type j = i + 1; j < N; ++j)
1002       {
1003         const number t = ((*this)(i, j) + (*this)(j, i)) / number(2.);
1004         (*this)(i, j) = (*this)(j, i) = t;
1005       };
1006 }
1007 
1008 
1009 template <typename number>
1010 typename FullMatrix<number>::real_type
l1_norm()1011 FullMatrix<number>::l1_norm() const
1012 {
1013   Assert(!this->empty(), ExcEmptyMatrix());
1014 
1015   real_type       sum = 0, max = 0;
1016   const size_type n_rows = m(), n_cols = n();
1017 
1018   for (size_type col = 0; col < n_cols; ++col)
1019     {
1020       sum = 0;
1021       for (size_type row = 0; row < n_rows; ++row)
1022         sum += std::abs((*this)(row, col));
1023       if (sum > max)
1024         max = sum;
1025     }
1026   return max;
1027 }
1028 
1029 
1030 
1031 template <typename number>
1032 typename FullMatrix<number>::real_type
linfty_norm()1033 FullMatrix<number>::linfty_norm() const
1034 {
1035   Assert(!this->empty(), ExcEmptyMatrix());
1036 
1037   real_type       sum = 0, max = 0;
1038   const size_type n_rows = m(), n_cols = n();
1039 
1040   for (size_type row = 0; row < n_rows; ++row)
1041     {
1042       sum = 0;
1043       for (size_type col = 0; col < n_cols; ++col)
1044         sum += std::abs((*this)(row, col));
1045       if (sum > max)
1046         max = sum;
1047     }
1048   return max;
1049 }
1050 
1051 
1052 
1053 template <typename number>
1054 template <typename number2>
1055 void
add(const number a,const FullMatrix<number2> & A)1056 FullMatrix<number>::add(const number a, const FullMatrix<number2> &A)
1057 {
1058   Assert(!this->empty(), ExcEmptyMatrix());
1059 
1060   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
1061   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
1062 
1063   for (size_type i = 0; i < m(); ++i)
1064     for (size_type j = 0; j < n(); ++j)
1065       (*this)(i, j) += a * number(A(i, j));
1066 }
1067 
1068 
1069 template <typename number>
1070 template <typename number2>
1071 void
add(const number a,const FullMatrix<number2> & A,const number b,const FullMatrix<number2> & B)1072 FullMatrix<number>::add(const number               a,
1073                         const FullMatrix<number2> &A,
1074                         const number               b,
1075                         const FullMatrix<number2> &B)
1076 {
1077   Assert(!this->empty(), ExcEmptyMatrix());
1078 
1079   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
1080   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
1081   Assert(m() == B.m(), ExcDimensionMismatch(m(), B.m()));
1082   Assert(n() == B.n(), ExcDimensionMismatch(n(), B.n()));
1083 
1084   for (size_type i = 0; i < m(); ++i)
1085     for (size_type j = 0; j < n(); ++j)
1086       (*this)(i, j) += a * number(A(i, j)) + b * number(B(i, j));
1087 }
1088 
1089 
1090 
1091 template <typename number>
1092 template <typename number2>
1093 void
add(const number a,const FullMatrix<number2> & A,const number b,const FullMatrix<number2> & B,const number c,const FullMatrix<number2> & C)1094 FullMatrix<number>::add(const number               a,
1095                         const FullMatrix<number2> &A,
1096                         const number               b,
1097                         const FullMatrix<number2> &B,
1098                         const number               c,
1099                         const FullMatrix<number2> &C)
1100 {
1101   Assert(!this->empty(), ExcEmptyMatrix());
1102 
1103   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
1104   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
1105   Assert(m() == B.m(), ExcDimensionMismatch(m(), B.m()));
1106   Assert(n() == B.n(), ExcDimensionMismatch(n(), B.n()));
1107   Assert(m() == C.m(), ExcDimensionMismatch(m(), C.m()));
1108   Assert(n() == C.n(), ExcDimensionMismatch(n(), C.n()));
1109 
1110 
1111   for (size_type i = 0; i < m(); ++i)
1112     for (size_type j = 0; j < n(); ++j)
1113       (*this)(i, j) +=
1114         a * number(A(i, j)) + b * number(B(i, j)) + c * number(C(i, j));
1115 }
1116 
1117 
1118 
1119 template <typename number>
1120 template <typename number2>
1121 void
add(const FullMatrix<number2> & src,const number factor,const size_type dst_offset_i,const size_type dst_offset_j,const size_type src_offset_i,const size_type src_offset_j)1122 FullMatrix<number>::add(const FullMatrix<number2> &src,
1123                         const number               factor,
1124                         const size_type            dst_offset_i,
1125                         const size_type            dst_offset_j,
1126                         const size_type            src_offset_i,
1127                         const size_type            src_offset_j)
1128 {
1129   AssertIndexRange(dst_offset_i, m());
1130   AssertIndexRange(dst_offset_j, n());
1131   AssertIndexRange(src_offset_i, src.m());
1132   AssertIndexRange(src_offset_j, src.n());
1133 
1134   // Compute maximal size of copied block
1135   const size_type rows = std::min(m() - dst_offset_i, src.m() - src_offset_i);
1136   const size_type cols = std::min(n() - dst_offset_j, src.n() - src_offset_j);
1137 
1138   for (size_type i = 0; i < rows; ++i)
1139     for (size_type j = 0; j < cols; ++j)
1140       (*this)(dst_offset_i + i, dst_offset_j + j) +=
1141         factor * number(src(src_offset_i + i, src_offset_j + j));
1142 }
1143 
1144 
1145 
1146 template <typename number>
1147 template <typename number2>
1148 void
Tadd(const FullMatrix<number2> & src,const number factor,const size_type dst_offset_i,const size_type dst_offset_j,const size_type src_offset_i,const size_type src_offset_j)1149 FullMatrix<number>::Tadd(const FullMatrix<number2> &src,
1150                          const number               factor,
1151                          const size_type            dst_offset_i,
1152                          const size_type            dst_offset_j,
1153                          const size_type            src_offset_i,
1154                          const size_type            src_offset_j)
1155 {
1156   AssertIndexRange(dst_offset_i, m());
1157   AssertIndexRange(dst_offset_j, n());
1158   AssertIndexRange(src_offset_i, src.n());
1159   AssertIndexRange(src_offset_j, src.m());
1160 
1161   // Compute maximal size of copied block
1162   const size_type rows = std::min(m() - dst_offset_i, src.n() - src_offset_j);
1163   const size_type cols = std::min(n() - dst_offset_j, src.m() - src_offset_i);
1164 
1165 
1166   for (size_type i = 0; i < rows; ++i)
1167     for (size_type j = 0; j < cols; ++j)
1168       (*this)(dst_offset_i + i, dst_offset_j + j) +=
1169         factor * number(src(src_offset_i + j, src_offset_j + i));
1170 }
1171 
1172 
1173 
1174 template <typename number>
1175 template <typename number2>
1176 void
Tadd(const number a,const FullMatrix<number2> & A)1177 FullMatrix<number>::Tadd(const number a, const FullMatrix<number2> &A)
1178 {
1179   Assert(!this->empty(), ExcEmptyMatrix());
1180 
1181   Assert(m() == n(), ExcNotQuadratic());
1182   Assert(m() == A.m(), ExcDimensionMismatch(m(), A.m()));
1183   Assert(n() == A.n(), ExcDimensionMismatch(n(), A.n()));
1184 
1185   for (size_type i = 0; i < n(); ++i)
1186     for (size_type j = 0; j < m(); ++j)
1187       (*this)(i, j) += a * number(A(j, i));
1188 }
1189 
1190 
1191 template <typename number>
1192 bool
1193 FullMatrix<number>::operator==(const FullMatrix<number> &M) const
1194 {
1195   // simply pass down to the base class
1196   return Table<2, number>::operator==(M);
1197 }
1198 
1199 
1200 namespace internal
1201 {
1202   // LAPACKFullMatrix is not implemented for
1203   // complex numbers or long doubles
1204   template <typename number, typename = void>
1205   struct Determinant
1206   {
1207     static number
valueDeterminant1208     value(const FullMatrix<number> &)
1209     {
1210       AssertThrow(false, ExcNotImplemented());
1211       return 0.0;
1212     }
1213   };
1214 
1215 
1216   // LAPACKFullMatrix is only implemented for
1217   // floats and doubles
1218   template <typename number>
1219   struct Determinant<
1220     number,
1221     typename std::enable_if<std::is_same<number, float>::value ||
1222                             std::is_same<number, double>::value>::type>
1223   {
1224 #ifdef DEAL_II_WITH_LAPACK
1225     static number
1226     value(const FullMatrix<number> &A)
1227     {
1228       using s_type = typename LAPACKFullMatrix<number>::size_type;
1229       AssertIndexRange(A.m() - 1, std::numeric_limits<s_type>::max());
1230       AssertIndexRange(A.n() - 1, std::numeric_limits<s_type>::max());
1231       LAPACKFullMatrix<number> lp_A(static_cast<s_type>(A.m()),
1232                                     static_cast<s_type>(A.n()));
1233       lp_A = A;
1234       lp_A.compute_lu_factorization();
1235       return lp_A.determinant();
1236     }
1237 #else
1238     static number
1239     value(const FullMatrix<number> &)
1240     {
1241       AssertThrow(false, ExcNeedsLAPACK());
1242       return 0.0;
1243     }
1244 #endif
1245   };
1246 
1247 } // namespace internal
1248 
1249 
1250 template <typename number>
1251 number
1252 FullMatrix<number>::determinant() const
1253 {
1254   Assert(!this->empty(), ExcEmptyMatrix());
1255 
1256   Assert(this->n_cols() == this->n_rows(),
1257          ExcDimensionMismatch(this->n_cols(), this->n_rows()));
1258 
1259   switch (this->n_cols())
1260     {
1261       case 1:
1262         return (*this)(0, 0);
1263       case 2:
1264         return (*this)(0, 0) * (*this)(1, 1) - (*this)(1, 0) * (*this)(0, 1);
1265       case 3:
1266         return ((*this)(0, 0) * (*this)(1, 1) * (*this)(2, 2) -
1267                 (*this)(0, 0) * (*this)(1, 2) * (*this)(2, 1) -
1268                 (*this)(1, 0) * (*this)(0, 1) * (*this)(2, 2) +
1269                 (*this)(1, 0) * (*this)(0, 2) * (*this)(2, 1) +
1270                 (*this)(2, 0) * (*this)(0, 1) * (*this)(1, 2) -
1271                 (*this)(2, 0) * (*this)(0, 2) * (*this)(1, 1));
1272       default:
1273         return internal::Determinant<number>::value(*this);
1274     };
1275 }
1276 
1277 
1278 
1279 template <typename number>
1280 number
1281 FullMatrix<number>::trace() const
1282 {
1283   Assert(!this->empty(), ExcEmptyMatrix());
1284 
1285   Assert(this->n_cols() == this->n_rows(),
1286          ExcDimensionMismatch(this->n_cols(), this->n_rows()));
1287 
1288   number tr = 0;
1289   for (size_type i = 0; i < this->n_rows(); ++i)
1290     tr += (*this)(i, i);
1291 
1292   return tr;
1293 }
1294 
1295 
1296 
1297 template <typename number>
1298 typename FullMatrix<number>::real_type
1299 FullMatrix<number>::frobenius_norm() const
1300 {
1301   Assert(!this->empty(), ExcEmptyMatrix());
1302 
1303   real_type s = 0.;
1304   for (size_type i = 0; i < this->n_rows() * this->n_cols(); ++i)
1305     s += numbers::NumberTraits<number>::abs_square(this->values[i]);
1306   return std::sqrt(s);
1307 }
1308 
1309 
1310 
1311 template <typename number>
1312 typename FullMatrix<number>::real_type
1313 FullMatrix<number>::relative_symmetry_norm2() const
1314 {
1315   Assert(!this->empty(), ExcEmptyMatrix());
1316 
1317   real_type s = 0.;
1318   real_type a = 0.;
1319   for (size_type i = 0; i < this->n_rows(); ++i)
1320     for (size_type j = 0; j < this->n_cols(); ++j)
1321       {
1322         const number x_ij = (*this)(i, j);
1323         const number x_ji = (*this)(j, i);
1324 
1325         a += numbers::NumberTraits<number>::abs_square(x_ij - x_ji);
1326         s += numbers::NumberTraits<number>::abs_square(x_ij);
1327       }
1328 
1329   if (s != 0.)
1330     return std::sqrt(a) / std::sqrt(s);
1331   return 0;
1332 }
1333 
1334 
1335 
1336 template <typename number>
1337 template <typename number2>
1338 void
1339 FullMatrix<number>::invert(const FullMatrix<number2> &M)
1340 {
1341   Assert(!this->empty(), ExcEmptyMatrix());
1342 
1343   Assert(this->n_cols() == this->n_rows(), ExcNotQuadratic());
1344   Assert(this->n_cols() == M.n_cols(),
1345          ExcDimensionMismatch(this->n_cols(), M.n_cols()));
1346   Assert(this->n_rows() == M.n_rows(),
1347          ExcDimensionMismatch(this->n_rows(), M.n_rows()));
1348 
1349   if (PointerComparison::equal(&M, this))
1350     {
1351       // avoid overwriting source
1352       // by destination matrix:
1353       const FullMatrix<number> M2 = *this;
1354       invert(M2);
1355     }
1356   else
1357     switch (this->n_cols())
1358       {
1359         case 1:
1360           (*this)(0, 0) = number2(1.0) / M(0, 0);
1361           return;
1362         case 2:
1363           // this is Maple output,
1364           // thus a bit unstructured
1365           {
1366             const number2 t4 =
1367               number2(1.0) / (M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0));
1368             (*this)(0, 0) = M(1, 1) * t4;
1369             (*this)(0, 1) = -M(0, 1) * t4;
1370             (*this)(1, 0) = -M(1, 0) * t4;
1371             (*this)(1, 1) = M(0, 0) * t4;
1372             return;
1373           };
1374 
1375         case 3:
1376           {
1377             const number2 t4 = M(0, 0) * M(1, 1), t6 = M(0, 0) * M(1, 2),
1378                           t8 = M(0, 1) * M(1, 0), t00 = M(0, 2) * M(1, 0),
1379                           t01 = M(0, 1) * M(2, 0), t04 = M(0, 2) * M(2, 0),
1380                           t07 = number2(1.0) /
1381                                 (t4 * M(2, 2) - t6 * M(2, 1) - t8 * M(2, 2) +
1382                                  t00 * M(2, 1) + t01 * M(1, 2) - t04 * M(1, 1));
1383             (*this)(0, 0) = (M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1)) * t07;
1384             (*this)(0, 1) = -(M(0, 1) * M(2, 2) - M(0, 2) * M(2, 1)) * t07;
1385             (*this)(0, 2) = -(-M(0, 1) * M(1, 2) + M(0, 2) * M(1, 1)) * t07;
1386             (*this)(1, 0) = -(M(1, 0) * M(2, 2) - M(1, 2) * M(2, 0)) * t07;
1387             (*this)(1, 1) = (M(0, 0) * M(2, 2) - t04) * t07;
1388             (*this)(1, 2) = -(t6 - t00) * t07;
1389             (*this)(2, 0) = -(-M(1, 0) * M(2, 1) + M(1, 1) * M(2, 0)) * t07;
1390             (*this)(2, 1) = -(M(0, 0) * M(2, 1) - t01) * t07;
1391             (*this)(2, 2) = (t4 - t8) * t07;
1392             return;
1393           };
1394 
1395         case 4:
1396           {
1397             // with (linalg);
1398             // a:=matrix(4,4);
1399             // evalm(a);
1400             // ai:=inverse(a);
1401             // readlib(C);
1402             // C(ai,optimized,filename=x4);
1403 
1404             const number2 t14 = M(0, 0) * M(1, 1);
1405             const number2 t15 = M(2, 2) * M(3, 3);
1406             const number2 t17 = M(2, 3) * M(3, 2);
1407             const number2 t19 = M(0, 0) * M(2, 1);
1408             const number2 t20 = M(1, 2) * M(3, 3);
1409             const number2 t22 = M(1, 3) * M(3, 2);
1410             const number2 t24 = M(0, 0) * M(3, 1);
1411             const number2 t25 = M(1, 2) * M(2, 3);
1412             const number2 t27 = M(1, 3) * M(2, 2);
1413             const number2 t29 = M(1, 0) * M(0, 1);
1414             const number2 t32 = M(1, 0) * M(2, 1);
1415             const number2 t33 = M(0, 2) * M(3, 3);
1416             const number2 t35 = M(0, 3) * M(3, 2);
1417             const number2 t37 = M(1, 0) * M(3, 1);
1418             const number2 t38 = M(0, 2) * M(2, 3);
1419             const number2 t40 = M(0, 3) * M(2, 2);
1420             const number2 t42 = t14 * t15 - t14 * t17 - t19 * t20 + t19 * t22 +
1421                                 t24 * t25 - t24 * t27 - t29 * t15 + t29 * t17 +
1422                                 t32 * t33 - t32 * t35 - t37 * t38 + t37 * t40;
1423             const number2 t43 = M(2, 0) * M(0, 1);
1424             const number2 t46 = M(2, 0) * M(1, 1);
1425             const number2 t49 = M(2, 0) * M(3, 1);
1426             const number2 t50 = M(0, 2) * M(1, 3);
1427             const number2 t52 = M(0, 3) * M(1, 2);
1428             const number2 t54 = M(3, 0) * M(0, 1);
1429             const number2 t57 = M(3, 0) * M(1, 1);
1430             const number2 t60 = M(3, 0) * M(2, 1);
1431             const number2 t63 = t43 * t20 - t43 * t22 - t46 * t33 + t46 * t35 +
1432                                 t49 * t50 - t49 * t52 - t54 * t25 + t54 * t27 +
1433                                 t57 * t38 - t57 * t40 - t60 * t50 + t60 * t52;
1434             const number2 t65  = number2(1.) / (t42 + t63);
1435             const number2 t71  = M(0, 2) * M(2, 1);
1436             const number2 t73  = M(0, 3) * M(2, 1);
1437             const number2 t75  = M(0, 2) * M(3, 1);
1438             const number2 t77  = M(0, 3) * M(3, 1);
1439             const number2 t81  = M(0, 1) * M(1, 2);
1440             const number2 t83  = M(0, 1) * M(1, 3);
1441             const number2 t85  = M(0, 2) * M(1, 1);
1442             const number2 t87  = M(0, 3) * M(1, 1);
1443             const number2 t101 = M(1, 0) * M(2, 2);
1444             const number2 t103 = M(1, 0) * M(2, 3);
1445             const number2 t105 = M(2, 0) * M(1, 2);
1446             const number2 t107 = M(2, 0) * M(1, 3);
1447             const number2 t109 = M(3, 0) * M(1, 2);
1448             const number2 t111 = M(3, 0) * M(1, 3);
1449             const number2 t115 = M(0, 0) * M(2, 2);
1450             const number2 t117 = M(0, 0) * M(2, 3);
1451             const number2 t119 = M(2, 0) * M(0, 2);
1452             const number2 t121 = M(2, 0) * M(0, 3);
1453             const number2 t123 = M(3, 0) * M(0, 2);
1454             const number2 t125 = M(3, 0) * M(0, 3);
1455             const number2 t129 = M(0, 0) * M(1, 2);
1456             const number2 t131 = M(0, 0) * M(1, 3);
1457             const number2 t133 = M(1, 0) * M(0, 2);
1458             const number2 t135 = M(1, 0) * M(0, 3);
1459             (*this)(0, 0) =
1460               (M(1, 1) * M(2, 2) * M(3, 3) - M(1, 1) * M(2, 3) * M(3, 2) -
1461                M(2, 1) * M(1, 2) * M(3, 3) + M(2, 1) * M(1, 3) * M(3, 2) +
1462                M(3, 1) * M(1, 2) * M(2, 3) - M(3, 1) * M(1, 3) * M(2, 2)) *
1463               t65;
1464             (*this)(0, 1) =
1465               -(M(0, 1) * M(2, 2) * M(3, 3) - M(0, 1) * M(2, 3) * M(3, 2) -
1466                 t71 * M(3, 3) + t73 * M(3, 2) + t75 * M(2, 3) - t77 * M(2, 2)) *
1467               t65;
1468             (*this)(0, 2) = (t81 * M(3, 3) - t83 * M(3, 2) - t85 * M(3, 3) +
1469                              t87 * M(3, 2) + t75 * M(1, 3) - t77 * M(1, 2)) *
1470                             t65;
1471             (*this)(0, 3) = -(t81 * M(2, 3) - t83 * M(2, 2) - t85 * M(2, 3) +
1472                               t87 * M(2, 2) + t71 * M(1, 3) - t73 * M(1, 2)) *
1473                             t65;
1474             (*this)(1, 0) =
1475               -(t101 * M(3, 3) - t103 * M(3, 2) - t105 * M(3, 3) +
1476                 t107 * M(3, 2) + t109 * M(2, 3) - t111 * M(2, 2)) *
1477               t65;
1478             (*this)(1, 1) = (t115 * M(3, 3) - t117 * M(3, 2) - t119 * M(3, 3) +
1479                              t121 * M(3, 2) + t123 * M(2, 3) - t125 * M(2, 2)) *
1480                             t65;
1481             (*this)(1, 2) =
1482               -(t129 * M(3, 3) - t131 * M(3, 2) - t133 * M(3, 3) +
1483                 t135 * M(3, 2) + t123 * M(1, 3) - t125 * M(1, 2)) *
1484               t65;
1485             (*this)(1, 3) = (t129 * M(2, 3) - t131 * M(2, 2) - t133 * M(2, 3) +
1486                              t135 * M(2, 2) + t119 * M(1, 3) - t121 * M(1, 2)) *
1487                             t65;
1488             (*this)(2, 0) = (t32 * M(3, 3) - t103 * M(3, 1) - t46 * M(3, 3) +
1489                              t107 * M(3, 1) + t57 * M(2, 3) - t111 * M(2, 1)) *
1490                             t65;
1491             (*this)(2, 1) = -(t19 * M(3, 3) - t117 * M(3, 1) - t43 * M(3, 3) +
1492                               t121 * M(3, 1) + t54 * M(2, 3) - t125 * M(2, 1)) *
1493                             t65;
1494             (*this)(2, 2) = (t14 * M(3, 3) - t131 * M(3, 1) - t29 * M(3, 3) +
1495                              t135 * M(3, 1) + t54 * M(1, 3) - t125 * M(1, 1)) *
1496                             t65;
1497             (*this)(2, 3) = -(t14 * M(2, 3) - t131 * M(2, 1) - t29 * M(2, 3) +
1498                               t135 * M(2, 1) + t43 * M(1, 3) - t121 * M(1, 1)) *
1499                             t65;
1500             (*this)(3, 0) = -(t32 * M(3, 2) - t101 * M(3, 1) - t46 * M(3, 2) +
1501                               t105 * M(3, 1) + t57 * M(2, 2) - t109 * M(2, 1)) *
1502                             t65;
1503             (*this)(3, 1) = (t19 * M(3, 2) - t115 * M(3, 1) - t43 * M(3, 2) +
1504                              t119 * M(3, 1) + t54 * M(2, 2) - t123 * M(2, 1)) *
1505                             t65;
1506             (*this)(3, 2) = -(t14 * M(3, 2) - t129 * M(3, 1) - t29 * M(3, 2) +
1507                               t133 * M(3, 1) + t54 * M(1, 2) - t123 * M(1, 1)) *
1508                             t65;
1509             (*this)(3, 3) = (t14 * M(2, 2) - t129 * M(2, 1) - t29 * M(2, 2) +
1510                              t133 * M(2, 1) + t43 * M(1, 2) - t119 * M(1, 1)) *
1511                             t65;
1512 
1513             break;
1514           }
1515 
1516 
1517         default:
1518           // if no inversion is
1519           // hardcoded, fall back
1520           // to use the
1521           // Gauss-Jordan algorithm
1522           *this = M;
1523           gauss_jordan();
1524       };
1525 }
1526 
1527 
1528 template <typename number>
1529 template <typename number2>
1530 void
1531 FullMatrix<number>::cholesky(const FullMatrix<number2> &A)
1532 {
1533   Assert(!A.empty(), ExcEmptyMatrix());
1534   Assert(A.n() == A.m(), ExcNotQuadratic());
1535   // Matrix must be symmetric.
1536   Assert(A.relative_symmetry_norm2() < 1.0e-10,
1537          ExcMessage("A must be symmetric."));
1538 
1539   if (PointerComparison::equal(&A, this))
1540     {
1541       // avoid overwriting source
1542       // by destination matrix:
1543       const FullMatrix<number> A2 = *this;
1544       cholesky(A2);
1545     }
1546   else
1547     {
1548       /* reinit *this to 0 */
1549       this->reinit(A.m(), A.n());
1550 
1551       for (size_type i = 0; i < this->n_cols(); ++i)
1552         {
1553           double SLik2 = 0.0;
1554           for (size_type j = 0; j < i; ++j)
1555             {
1556               double SLikLjk = 0.0;
1557               for (size_type k = 0; k < j; ++k)
1558                 {
1559                   SLikLjk += (*this)(i, k) * (*this)(j, k);
1560                 };
1561               (*this)(i, j) = (1. / (*this)(j, j)) * (A(i, j) - SLikLjk);
1562               SLik2 += (*this)(i, j) * (*this)(i, j);
1563             }
1564           AssertThrow(A(i, i) - SLik2 >= 0, ExcMatrixNotPositiveDefinite());
1565 
1566           (*this)(i, i) = std::sqrt(A(i, i) - SLik2);
1567         }
1568     }
1569 }
1570 
1571 
1572 template <typename number>
1573 template <typename number2>
1574 void
1575 FullMatrix<number>::outer_product(const Vector<number2> &V,
1576                                   const Vector<number2> &W)
1577 {
1578   Assert(V.size() == W.size(),
1579          ExcMessage("Vectors V, W must be the same size."));
1580   this->reinit(V.size(), V.size());
1581 
1582   for (size_type i = 0; i < this->n(); ++i)
1583     {
1584       for (size_type j = 0; j < this->n(); ++j)
1585         {
1586           (*this)(i, j) = V(i) * W(j);
1587         }
1588     }
1589 }
1590 
1591 
1592 template <typename number>
1593 template <typename number2>
1594 void
1595 FullMatrix<number>::left_invert(const FullMatrix<number2> &A)
1596 {
1597   Assert(!A.empty(), ExcEmptyMatrix());
1598 
1599   // If the matrix is square, simply do a
1600   // standard inversion
1601   if (A.m() == A.n())
1602     {
1603       FullMatrix<number2> left_inv(A.n(), A.m());
1604       left_inv.invert(A);
1605       *this = std::move(left_inv);
1606       return;
1607     }
1608 
1609   Assert(A.m() > A.n(), ExcDimensionMismatch(A.m(), A.n()));
1610   Assert(this->m() == A.n(), ExcDimensionMismatch(this->m(), A.n()));
1611   Assert(this->n() == A.m(), ExcDimensionMismatch(this->n(), A.m()));
1612 
1613   FullMatrix<number2> A_t(A.n(), A.m());
1614   FullMatrix<number2> A_t_times_A(A.n(), A.n());
1615   FullMatrix<number2> A_t_times_A_inv(A.n(), A.n());
1616   FullMatrix<number2> left_inv(A.n(), A.m());
1617 
1618   A_t.Tadd(A, 1);
1619   A_t.mmult(A_t_times_A, A);
1620   if (number(A_t_times_A.determinant()) == number(0))
1621     Assert(false, ExcSingular()) else
1622     {
1623       A_t_times_A_inv.invert(A_t_times_A);
1624       A_t_times_A_inv.mmult(left_inv, A_t);
1625 
1626       *this = left_inv;
1627     }
1628 }
1629 
1630 template <typename number>
1631 template <typename number2>
1632 void
1633 FullMatrix<number>::right_invert(const FullMatrix<number2> &A)
1634 {
1635   Assert(!A.empty(), ExcEmptyMatrix());
1636 
1637   // If the matrix is square, simply do a
1638   // standard inversion
1639   if (A.m() == A.n())
1640     {
1641       FullMatrix<number2> right_inv(A.n(), A.m());
1642       right_inv.invert(A);
1643       *this = std::move(right_inv);
1644       return;
1645     }
1646 
1647   Assert(A.n() > A.m(), ExcDimensionMismatch(A.n(), A.m()));
1648   Assert(this->m() == A.n(), ExcDimensionMismatch(this->m(), A.n()));
1649   Assert(this->n() == A.m(), ExcDimensionMismatch(this->n(), A.m()));
1650 
1651   FullMatrix<number> A_t(A.n(), A.m());
1652   FullMatrix<number> A_times_A_t(A.m(), A.m());
1653   FullMatrix<number> A_times_A_t_inv(A.m(), A.m());
1654   FullMatrix<number> right_inv(A.n(), A.m());
1655 
1656   A_t.Tadd(A, 1);
1657   A.mmult(A_times_A_t, A_t);
1658   if (number(A_times_A_t.determinant()) == number(0))
1659     Assert(false, ExcSingular()) else
1660     {
1661       A_times_A_t_inv.invert(A_times_A_t);
1662       A_t.mmult(right_inv, A_times_A_t_inv);
1663 
1664       *this = right_inv;
1665     }
1666 }
1667 
1668 
1669 template <typename number>
1670 template <int dim>
1671 void
1672 FullMatrix<number>::copy_from(const Tensor<2, dim> &T,
1673                               const unsigned int    src_r_i,
1674                               const unsigned int    src_r_j,
1675                               const unsigned int    src_c_i,
1676                               const unsigned int    src_c_j,
1677                               const size_type       dst_r,
1678                               const size_type       dst_c)
1679 {
1680   Assert(!this->empty(), ExcEmptyMatrix());
1681   AssertIndexRange(src_r_j - src_r_i, this->m() - dst_r);
1682   AssertIndexRange(src_c_j - src_c_i, this->n() - dst_c);
1683   AssertIndexRange(src_r_j, dim);
1684   AssertIndexRange(src_c_j, dim);
1685   AssertIndexRange(src_r_i, src_r_j + 1);
1686   AssertIndexRange(src_c_i, src_c_j + 1);
1687 
1688   for (size_type i = 0; i < src_r_j - src_r_i + 1; ++i)
1689     for (size_type j = 0; j < src_c_j - src_c_i + 1; ++j)
1690       {
1691         const unsigned int src_r_index = static_cast<unsigned int>(i + src_r_i);
1692         const unsigned int src_c_index = static_cast<unsigned int>(j + src_c_i);
1693         (*this)(i + dst_r, j + dst_c)  = number(T[src_r_index][src_c_index]);
1694       }
1695 }
1696 
1697 
1698 template <typename number>
1699 template <int dim>
1700 void FullMatrix<number>::copy_to(Tensor<2, dim> &   T,
1701                                  const size_type    src_r_i,
1702                                  const size_type    src_r_j,
1703                                  const size_type    src_c_i,
1704                                  const size_type    src_c_j,
1705                                  const unsigned int dst_r,
1706                                  const unsigned int dst_c) const
1707 {
1708   Assert(!this->empty(), ExcEmptyMatrix());
1709   AssertIndexRange(src_r_j - src_r_i, dim - dst_r);
1710   AssertIndexRange(src_c_j - src_c_i, dim - dst_c);
1711   AssertIndexRange(src_r_j, this->m());
1712   AssertIndexRange(src_r_j, this->n());
1713   AssertIndexRange(src_r_i, src_r_j + 1);
1714   AssertIndexRange(src_c_j, src_c_j + 1);
1715 
1716   for (size_type i = 0; i < src_r_j - src_r_i + 1; ++i)
1717     for (size_type j = 0; j < src_c_j - src_c_i + 1; ++j)
1718       {
1719         const unsigned int dst_r_index = static_cast<unsigned int>(i + dst_r);
1720         const unsigned int dst_c_index = static_cast<unsigned int>(j + dst_c);
1721         T[dst_r_index][dst_c_index] = double((*this)(i + src_r_i, j + src_c_i));
1722       }
1723 }
1724 
1725 
1726 
1727 template <typename number>
1728 template <typename somenumber>
1729 void
1730 FullMatrix<number>::precondition_Jacobi(Vector<somenumber> &      dst,
1731                                         const Vector<somenumber> &src,
1732                                         const number              om) const
1733 {
1734   Assert(m() == n(), ExcNotQuadratic());
1735   Assert(dst.size() == n(), ExcDimensionMismatch(dst.size(), n()));
1736   Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
1737 
1738   const std::size_t n       = src.size();
1739   somenumber *      dst_ptr = dst.begin();
1740   const somenumber *src_ptr = src.begin();
1741 
1742   for (size_type i = 0; i < n; ++i, ++dst_ptr, ++src_ptr)
1743     *dst_ptr = somenumber(om) * *src_ptr / somenumber((*this)(i, i));
1744 }
1745 
1746 
1747 
1748 template <typename number>
1749 void
1750 FullMatrix<number>::print_formatted(std::ostream &     out,
1751                                     const unsigned int precision,
1752                                     const bool         scientific,
1753                                     const unsigned int width_,
1754                                     const char *       zero_string,
1755                                     const double       denominator,
1756                                     const double       threshold) const
1757 {
1758   unsigned int width = width_;
1759 
1760   Assert((!this->empty()) || (this->n_cols() + this->n_rows() == 0),
1761          ExcInternalError());
1762 
1763   // set output format, but store old
1764   // state
1765   std::ios::fmtflags old_flags     = out.flags();
1766   std::streamsize    old_precision = out.precision(precision);
1767 
1768   if (scientific)
1769     {
1770       out.setf(std::ios::scientific, std::ios::floatfield);
1771       if (!width)
1772         width = precision + 7;
1773     }
1774   else
1775     {
1776       out.setf(std::ios::fixed, std::ios::floatfield);
1777       if (!width)
1778         width = precision + 2;
1779     }
1780 
1781   for (size_type i = 0; i < m(); ++i)
1782     {
1783       for (size_type j = 0; j < n(); ++j)
1784         // we might have complex numbers, so use abs also to check for nan
1785         // since there is no isnan on complex numbers
1786         if (std::isnan(std::abs((*this)(i, j))))
1787           out << std::setw(width) << (*this)(i, j) << ' ';
1788         else if (std::abs((*this)(i, j)) > threshold)
1789           out << std::setw(width) << (*this)(i, j) * number(denominator) << ' ';
1790         else
1791           out << std::setw(width) << zero_string << ' ';
1792       out << std::endl;
1793     };
1794 
1795   AssertThrow(out, ExcIO());
1796   // reset output format
1797   out.flags(old_flags);
1798   out.precision(old_precision);
1799 }
1800 
1801 
1802 template <typename number>
1803 void
1804 FullMatrix<number>::gauss_jordan()
1805 {
1806   Assert(!this->empty(), ExcEmptyMatrix());
1807   Assert(this->n_cols() == this->n_rows(), ExcNotQuadratic());
1808 
1809   // see if we can use Lapack algorithms
1810   // for this and if the type for 'number'
1811   // works for us (it is usually not
1812   // efficient to use Lapack for very small
1813   // matrices):
1814 #ifdef DEAL_II_WITH_LAPACK
1815   if (std::is_same<number, double>::value || std::is_same<number, float>::value)
1816     if (this->n_cols() > 15 && static_cast<types::blas_int>(this->n_cols()) <=
1817                                  std::numeric_limits<types::blas_int>::max())
1818       {
1819         // In case we have the LAPACK functions
1820         // getrf and getri detected by CMake,
1821         // we use these algorithms for inversion
1822         // since they provide better performance
1823         // than the deal.II native functions.
1824         //
1825         // Note that BLAS/LAPACK stores matrix
1826         // elements column-wise (i.e., all values in
1827         // one column, then all in the next, etc.),
1828         // whereas the FullMatrix stores them
1829         // row-wise.
1830         // We ignore that difference, and give our
1831         // row-wise data to LAPACK,
1832         // let LAPACK build the inverse of the
1833         // transpose matrix, and read the result as
1834         // if it were row-wise again. In other words,
1835         // we just got ((A^T)^{-1})^T, which is
1836         // A^{-1}.
1837 
1838         const types::blas_int nn = static_cast<types::blas_int>(this->n());
1839 
1840         // workspace for permutations
1841         std::vector<types::blas_int> ipiv(nn);
1842         types::blas_int              info;
1843 
1844         // Use the LAPACK function getrf for
1845         // calculating the LU factorization.
1846         getrf(&nn, &nn, this->values.data(), &nn, ipiv.data(), &info);
1847 
1848         Assert(info >= 0, ExcInternalError());
1849         Assert(info == 0, LACExceptions::ExcSingular());
1850 
1851         // scratch array
1852         std::vector<number> inv_work(nn);
1853 
1854         // Use the LAPACK function getri for
1855         // calculating the actual inverse using
1856         // the LU factorization.
1857         getri(&nn,
1858               this->values.data(),
1859               &nn,
1860               ipiv.data(),
1861               inv_work.data(),
1862               &nn,
1863               &info);
1864 
1865         Assert(info >= 0, ExcInternalError());
1866         Assert(info == 0, LACExceptions::ExcSingular());
1867 
1868         return;
1869       }
1870 
1871 #endif
1872 
1873   // otherwise do it by hand. use the
1874   // Gauss-Jordan-Algorithm from
1875   // Stoer & Bulirsch I (4th Edition)
1876   // p. 153
1877   const size_type N = n();
1878 
1879   // first get an estimate of the
1880   // size of the elements of this
1881   // matrix, for later checks whether
1882   // the pivot element is large
1883   // enough, or whether we have to
1884   // fear that the matrix is not
1885   // regular
1886   double diagonal_sum = 0;
1887   for (size_type i = 0; i < N; ++i)
1888     diagonal_sum += std::abs((*this)(i, i));
1889   const double typical_diagonal_element = diagonal_sum / N;
1890   (void)typical_diagonal_element;
1891 
1892   // initialize the array that holds
1893   // the permutations that we find
1894   // during pivot search
1895   std::vector<size_type> p(N);
1896   for (size_type i = 0; i < N; ++i)
1897     p[i] = i;
1898 
1899   for (size_type j = 0; j < N; ++j)
1900     {
1901       // pivot search: search that
1902       // part of the line on and
1903       // right of the diagonal for
1904       // the largest element
1905       real_type max = std::abs((*this)(j, j));
1906       size_type r   = j;
1907       for (size_type i = j + 1; i < N; ++i)
1908         {
1909           if (std::abs((*this)(i, j)) > max)
1910             {
1911               max = std::abs((*this)(i, j));
1912               r   = i;
1913             }
1914         }
1915       // check whether the pivot is
1916       // too small
1917       Assert(max > 1.e-16 * typical_diagonal_element, ExcNotRegular(max));
1918 
1919       // row interchange
1920       if (r > j)
1921         {
1922           for (size_type k = 0; k < N; ++k)
1923             std::swap((*this)(j, k), (*this)(r, k));
1924 
1925           std::swap(p[j], p[r]);
1926         }
1927 
1928       // transformation
1929       const number hr = number(1.) / (*this)(j, j);
1930       (*this)(j, j)   = hr;
1931       for (size_type k = 0; k < N; ++k)
1932         {
1933           if (k == j)
1934             continue;
1935           for (size_type i = 0; i < N; ++i)
1936             {
1937               if (i == j)
1938                 continue;
1939               (*this)(i, k) -= (*this)(i, j) * (*this)(j, k) * hr;
1940             }
1941         }
1942       for (size_type i = 0; i < N; ++i)
1943         {
1944           (*this)(i, j) *= hr;
1945           (*this)(j, i) *= -hr;
1946         }
1947       (*this)(j, j) = hr;
1948     }
1949   // column interchange
1950   std::vector<number> hv(N);
1951   for (size_type i = 0; i < N; ++i)
1952     {
1953       for (size_type k = 0; k < N; ++k)
1954         hv[p[k]] = (*this)(i, k);
1955       for (size_type k = 0; k < N; ++k)
1956         (*this)(i, k) = hv[k];
1957     }
1958 }
1959 
1960 
1961 
1962 template <typename number>
1963 std::size_t
1964 FullMatrix<number>::memory_consumption() const
1965 {
1966   return (sizeof(*this) - sizeof(Table<2, number>) +
1967           Table<2, number>::memory_consumption());
1968 }
1969 
1970 
1971 DEAL_II_NAMESPACE_CLOSE
1972 
1973 #endif
1974