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