dune-geometry  2.11
defaultmatrixhelper.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_GEOMETRY_UTILITY_DEFAULTMATRIXHELPER_HH
6 #define DUNE_GEOMETRY_UTILITY_DEFAULTMATRIXHELPER_HH
7 
8 #include <cmath>
9 
10 #include <dune/common/fmatrix.hh>
11 #include <dune/common/fvector.hh>
12 
13 namespace Dune {
14 namespace Impl {
15 
16 // FieldMatrixHelper
17 // -----------------
18 
19 template< class ct >
20 struct FieldMatrixHelper
21 {
22  using ctype = ct;
23 
25  template< int m, int n >
26  [[ deprecated("Use A.mv(x,y) instead.") ]]
27  static void Ax ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, n > &x, FieldVector< ctype, m > &ret )
28  {
29  A.mv(x,ret);
30  }
31 
33  template< int m, int n >
34  [[ deprecated("Use A.mtv(x,y) instead.") ]]
35  static void ATx ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, m > &x, FieldVector< ctype, n > &ret )
36  {
37  A.mtv(x,ret);
38  }
39 
41  template< int m, int n, int p >
42  [[ deprecated("Use FMatrixHelp::multMatrix(A,B,ret)") ]]
43  static void AB ( const FieldMatrix< ctype, m, n > &A, const FieldMatrix< ctype, n, p > &B, FieldMatrix< ctype, m, p > &ret )
44  {
45  FMatrixHelp::multMatrix(A,B,ret);
46  }
47 
49  template< int m, int n, int p >
50  static void ATBT ( const FieldMatrix< ctype, m, n > &A, const FieldMatrix< ctype, p, m > &B, FieldMatrix< ctype, n, p > &ret )
51  {
52  for( int i = 0; i < n; ++i )
53  {
54  for( int j = 0; j < p; ++j )
55  {
56  ret[ i ][ j ] = ctype( 0 );
57  for( int k = 0; k < m; ++k )
58  ret[ i ][ j ] += A[ k ][ i ] * B[ j ][ k ];
59  }
60  }
61  }
62 
64  template< int m, int n >
65  static void ATA_L ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, n > &ret )
66  {
67  for( int i = 0; i < n; ++i )
68  {
69  for( int j = 0; j <= i; ++j )
70  {
71  ret[ i ][ j ] = ctype( 0 );
72  for( int k = 0; k < m; ++k )
73  ret[ i ][ j ] += A[ k ][ i ] * A[ k ][ j ];
74  }
75  }
76  }
77 
79  template< int m, int n >
80  [[ deprecated("Use FMatrixHelp::multTransposedMatrix(A,ret)") ]]
81  static void ATA ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, n > &ret )
82  {
83  return FMatrixHelp::multTransposedMatrix(A,ret);
84  }
85 
87  template< int m, int n >
88  static void AAT_L ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, m, m > &ret )
89  {
90  for( int i = 0; i < m; ++i )
91  {
92  for( int j = 0; j <= i; ++j )
93  {
94  ctype &retij = ret[ i ][ j ];
95  retij = A[ i ][ 0 ] * A[ j ][ 0 ];
96  for( int k = 1; k < n; ++k )
97  retij += A[ i ][ k ] * A[ j ][ k ];
98  }
99  }
100  }
101 
103  template< int m, int n >
104  static void AAT ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, m, m > &ret )
105  {
106  for( int i = 0; i < m; ++i )
107  {
108  for( int j = 0; j < i; ++j )
109  {
110  ret[ i ][ j ] = ctype( 0 );
111  for( int k = 0; k < n; ++k )
112  ret[ i ][ j ] += A[ i ][ k ] * A[ j ][ k ];
113  ret[ j ][ i ] = ret[ i ][ j ];
114  }
115  ret[ i ][ i ] = ctype( 0 );
116  for( int k = 0; k < n; ++k )
117  ret[ i ][ i ] += A[ i ][ k ] * A[ i ][ k ];
118  }
119  }
120 
122  // [[ expects: L is lower triangular ]]
123  template< int n >
124  static void Lx ( const FieldMatrix< ctype, n, n > &L, const FieldVector< ctype, n > &x, FieldVector< ctype, n > &ret )
125  {
126  for( int i = 0; i < n; ++i )
127  {
128  ret[ i ] = ctype( 0 );
129  for( int j = 0; j <= i; ++j )
130  ret[ i ] += L[ i ][ j ] * x[ j ];
131  }
132  }
133 
135  // [[ expects: L is lower triangular ]]
136  template< int n >
137  static void LTx ( const FieldMatrix< ctype, n, n > &L, const FieldVector< ctype, n > &x, FieldVector< ctype, n > &ret )
138  {
139  for( int i = 0; i < n; ++i )
140  {
141  ret[ i ] = ctype( 0 );
142  for( int j = i; j < n; ++j )
143  ret[ i ] += L[ j ][ i ] * x[ j ];
144  }
145  }
146 
148  // [[ expects: L is lower triangular ]]
149  template< int n >
150  static void LTL ( const FieldMatrix< ctype, n, n > &L, FieldMatrix< ctype, n, n > &ret )
151  {
152  for( int i = 0; i < n; ++i )
153  {
154  for( int j = 0; j < i; ++j )
155  {
156  ret[ i ][ j ] = ctype( 0 );
157  for( int k = i; k < n; ++k )
158  ret[ i ][ j ] += L[ k ][ i ] * L[ k ][ j ];
159  ret[ j ][ i ] = ret[ i ][ j ];
160  }
161  ret[ i ][ i ] = ctype( 0 );
162  for( int k = i; k < n; ++k )
163  ret[ i ][ i ] += L[ k ][ i ] * L[ k ][ i ];
164  }
165  }
166 
168  // [[ expects: L is lower triangular ]]
169  template< int n >
170  static void LLT ( const FieldMatrix< ctype, n, n > &L, FieldMatrix< ctype, n, n > &ret )
171  {
172  for( int i = 0; i < n; ++i )
173  {
174  for( int j = 0; j < i; ++j )
175  {
176  ret[ i ][ j ] = ctype( 0 );
177  for( int k = 0; k <= j; ++k )
178  ret[ i ][ j ] += L[ i ][ k ] * L[ j ][ k ];
179  ret[ j ][ i ] = ret[ i ][ j ];
180  }
181  ret[ i ][ i ] = ctype( 0 );
182  for( int k = 0; k <= i; ++k )
183  ret[ i ][ i ] += L[ i ][ k ] * L[ i ][ k ];
184  }
185  }
186 
189  // [[ expects: A is spd ]]
190  template< int n >
191  static bool cholesky_L ( const FieldMatrix< ctype, n, n > &A, FieldMatrix< ctype, n, n > &ret, const bool checkSingular = false )
192  {
193  using std::sqrt;
194  for( int i = 0; i < n; ++i )
195  {
196  ctype &rii = ret[ i ][ i ];
197 
198  ctype xDiag = A[ i ][ i ];
199  for( int j = 0; j < i; ++j )
200  xDiag -= ret[ i ][ j ] * ret[ i ][ j ];
201 
202  // in some cases A can be singular, e.g. when checking local for
203  // outside points during checkInside
204  if( checkSingular && ! ( xDiag > ctype( 0 )) )
205  return false ;
206 
207  // otherwise this should be true always
208  assert( xDiag > ctype( 0 ) );
209  rii = sqrt( xDiag );
210 
211  ctype invrii = ctype( 1 ) / rii;
212  for( int k = i+1; k < n; ++k )
213  {
214  ctype x = A[ k ][ i ];
215  for( int j = 0; j < i; ++j )
216  x -= ret[ i ][ j ] * ret[ k ][ j ];
217  ret[ k ][ i ] = invrii * x;
218  }
219  }
220 
221  // return true for meaning A is non-singular
222  return true;
223  }
224 
226  // [[ expects: L is lower triangular ]]
227  template< int n >
228  static ctype detL ( const FieldMatrix< ctype, n, n > &L )
229  {
230  ctype det( 1 );
231  for( int i = 0; i < n; ++i )
232  det *= L[ i ][ i ];
233  return det;
234  }
235 
237  // [[ expects: L is lower triangular ]]
238  template< int n >
239  static ctype invL ( FieldMatrix< ctype, n, n > &L )
240  {
241  ctype det( 1 );
242  for( int i = 0; i < n; ++i )
243  {
244  ctype &lii = L[ i ][ i ];
245  det *= lii;
246  lii = ctype( 1 ) / lii;
247  for( int j = 0; j < i; ++j )
248  {
249  ctype &lij = L[ i ][ j ];
250  ctype x = lij * L[ j ][ j ];
251  for( int k = j+1; k < i; ++k )
252  x += L[ i ][ k ] * L[ k ][ j ];
253  lij = (-lii) * x;
254  }
255  }
256  return det;
257  }
258 
260  // [[ expects: L is lower triangular ]]
261  template< int n >
262  static void invLx ( FieldMatrix< ctype, n, n > &L, FieldVector< ctype, n > &x )
263  {
264  for( int i = 0; i < n; ++i )
265  {
266  for( int j = 0; j < i; ++j )
267  x[ i ] -= L[ i ][ j ] * x[ j ];
268  x[ i ] /= L[ i ][ i ];
269  }
270  }
271 
273  // [[ expects: L is lower triangular ]]
274  template< int n >
275  static void invLTx ( FieldMatrix< ctype, n, n > &L, FieldVector< ctype, n > &x )
276  {
277  for( int i = n; i > 0; --i )
278  {
279  for( int j = i; j < n; ++j )
280  x[ i-1 ] -= L[ j ][ i-1 ] * x[ j ];
281  x[ i-1 ] /= L[ i-1 ][ i-1 ];
282  }
283  }
284 
286  // [[ expects: A is spd ]]
287  template< int n >
288  static ctype spdDetA ( const FieldMatrix< ctype, n, n > &A )
289  {
290  FieldMatrix< ctype, n, n > L;
291  cholesky_L( A, L );
292  return detL( L );
293  }
294 
296  // [[ expects: A is spd ]]
297  template< int n >
298  static ctype spdInvA ( FieldMatrix< ctype, n, n > &A )
299  {
300  FieldMatrix< ctype, n, n > L;
301  cholesky_L( A, L );
302  const ctype det = invL( L );
303  LTL( L, A );
304  return det;
305  }
306 
308  // [[ expects: A is spd ]]
309  template< int n >
310  static bool spdInvAx ( FieldMatrix< ctype, n, n > &A, FieldVector< ctype, n > &x, const bool checkSingular = false )
311  {
312  FieldMatrix< ctype, n, n > L;
313  const bool invertible = cholesky_L( A, L, checkSingular );
314  if( ! invertible ) return invertible ;
315  invLx( L, x );
316  invLTx( L, x );
317  return invertible;
318  }
319 
321  template< int m, int n >
322  static ctype detATA ( const FieldMatrix< ctype, m, n > &A )
323  {
324  if constexpr( m >= n )
325  {
326  FieldMatrix< ctype, n, n > ata;
327  ATA_L( A, ata );
328  return spdDetA( ata );
329  }
330  else
331  return ctype( 0 );
332  }
333 
339  template< int m, int n >
340  static ctype sqrtDetAAT ( const FieldMatrix< ctype, m, n > &A )
341  {
342  using std::abs;
343  using std::sqrt;
344  // These special cases are here not only for speed reasons:
345  // The general implementation aborts if the matrix is almost singular,
346  // and the special implementation provide a stable way to handle that case.
347  if constexpr( (n == 2) && (m == 2) )
348  {
349  // Special implementation for 2x2 matrices: faster and more stable
350  return abs( A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ] );
351  }
352  else if constexpr( (n == 3) && (m == 3) )
353  {
354  // Special implementation for 3x3 matrices
355  const ctype v0 = A[ 0 ][ 1 ] * A[ 1 ][ 2 ] - A[ 1 ][ 1 ] * A[ 0 ][ 2 ];
356  const ctype v1 = A[ 0 ][ 2 ] * A[ 1 ][ 0 ] - A[ 1 ][ 2 ] * A[ 0 ][ 0 ];
357  const ctype v2 = A[ 0 ][ 0 ] * A[ 1 ][ 1 ] - A[ 1 ][ 0 ] * A[ 0 ][ 1 ];
358  return abs( v0 * A[ 2 ][ 0 ] + v1 * A[ 2 ][ 1 ] + v2 * A[ 2 ][ 2 ] );
359  }
360  else if constexpr( (n == 3) && (m == 2) )
361  {
362  // Special implementation for 2x3 matrices
363  const ctype v0 = A[ 0 ][ 0 ] * A[ 1 ][ 1 ] - A[ 0 ][ 1 ] * A[ 1 ][ 0 ];
364  const ctype v1 = A[ 0 ][ 0 ] * A[ 1 ][ 2 ] - A[ 1 ][ 0 ] * A[ 0 ][ 2 ];
365  const ctype v2 = A[ 0 ][ 1 ] * A[ 1 ][ 2 ] - A[ 0 ][ 2 ] * A[ 1 ][ 1 ];
366  return sqrt( v0*v0 + v1*v1 + v2*v2);
367  }
368  else if constexpr( n >= m )
369  {
370  // General case
371  FieldMatrix< ctype, m, m > aat;
372  AAT_L( A, aat );
373  return spdDetA( aat );
374  }
375  else
376  return ctype( 0 );
377  }
378 
380  // => A^{-1}_L A = I
381  template< int m, int n >
382  static ctype leftInvA ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, m > &ret )
383  {
384  using std::abs;
385  if constexpr( (n == 2) && (m == 2) )
386  {
387  const ctype det = (A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ]);
388  const ctype detInv = ctype( 1 ) / det;
389  ret[ 0 ][ 0 ] = A[ 1 ][ 1 ] * detInv;
390  ret[ 1 ][ 1 ] = A[ 0 ][ 0 ] * detInv;
391  ret[ 1 ][ 0 ] = -A[ 1 ][ 0 ] * detInv;
392  ret[ 0 ][ 1 ] = -A[ 0 ][ 1 ] * detInv;
393  return abs( det );
394  }
395  else
396  {
397  FieldMatrix< ctype, n, n > ata;
398  ATA_L( A, ata );
399  const ctype det = spdInvA( ata );
400  ATBT( ata, A, ret );
401  return det;
402  }
403  }
404 
406  template< int m, int n >
407  static bool leftInvAx ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, m > &x, FieldVector< ctype, n > &y )
408  {
409  static_assert((m >= n), "Matrix has no left inverse.");
410  FieldMatrix< ctype, n, n > ata;
411  A.mtv(x, y);
412  ATA_L( A, ata );
413  return spdInvAx( ata, y, true );
414  }
415 
417  template< int m, int n >
418  static ctype rightInvA ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, m > &ret )
419  {
420  static_assert((n >= m), "Matrix has no right inverse.");
421  using std::abs;
422  if constexpr( (n == 2) && (m == 2) )
423  {
424  const ctype det = (A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ]);
425  const ctype detInv = ctype( 1 ) / det;
426  ret[ 0 ][ 0 ] = A[ 1 ][ 1 ] * detInv;
427  ret[ 1 ][ 1 ] = A[ 0 ][ 0 ] * detInv;
428  ret[ 1 ][ 0 ] = -A[ 1 ][ 0 ] * detInv;
429  ret[ 0 ][ 1 ] = -A[ 0 ][ 1 ] * detInv;
430  return abs( det );
431  }
432  else
433  {
434  FieldMatrix< ctype, m , m > aat;
435  AAT_L( A, aat );
436  const ctype det = spdInvA( aat );
437  ATBT( A , aat , ret );
438  return det;
439  }
440  }
441 
443  template< int m, int n >
444  static bool xTRightInvA ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, n > &x, FieldVector< ctype, m > &y )
445  {
446  static_assert((n >= m), "Matrix has no right inverse.");
447  FieldMatrix< ctype, m, m > aat;
448  A.mv(x, y);
449  AAT_L( A, aat );
450  // check whether aat is singular and return true if non-singular
451  return spdInvAx( aat, y, true );
452  }
453 };
454 
455 } // namespace Impl
456 } // namespace Dune
457 
458 #endif // DUNE_GEOMETRY_UTILITY_DEFAULTMATRIXHELPER_HH
Definition: affinegeometry.hh:21