dune-geometry 2.12-git
Loading...
Searching...
No Matches
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
12
13namespace Dune {
14namespace Impl {
15
16// FieldMatrixHelper
17// -----------------
18
19template< class ct >
20struct FieldMatrixHelper
21{
22 using ctype = ct;
23
25 template< int m, int n, int p >
26 static void ATBT ( const FieldMatrix< ctype, m, n > &A, const FieldMatrix< ctype, p, m > &B, FieldMatrix< ctype, n, p > &ret )
27 {
28 for( int i = 0; i < n; ++i )
29 {
30 for( int j = 0; j < p; ++j )
31 {
32 ret[ i ][ j ] = ctype( 0 );
33 for( int k = 0; k < m; ++k )
34 ret[ i ][ j ] += A[ k ][ i ] * B[ j ][ k ];
35 }
36 }
37 }
38
40 template< int m, int n >
41 static void ATA_L ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, n > &ret )
42 {
43 for( int i = 0; i < n; ++i )
44 {
45 for( int j = 0; j <= i; ++j )
46 {
47 ret[ i ][ j ] = ctype( 0 );
48 for( int k = 0; k < m; ++k )
49 ret[ i ][ j ] += A[ k ][ i ] * A[ k ][ j ];
50 }
51 }
52 }
53
55 template< int m, int n >
56 static void AAT_L ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, m, m > &ret )
57 {
58 for( int i = 0; i < m; ++i )
59 {
60 for( int j = 0; j <= i; ++j )
61 {
62 ctype &retij = ret[ i ][ j ];
63 retij = A[ i ][ 0 ] * A[ j ][ 0 ];
64 for( int k = 1; k < n; ++k )
65 retij += A[ i ][ k ] * A[ j ][ k ];
66 }
67 }
68 }
69
71 template< int m, int n >
72 static void AAT ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, m, m > &ret )
73 {
74 for( int i = 0; i < m; ++i )
75 {
76 for( int j = 0; j < i; ++j )
77 {
78 ret[ i ][ j ] = ctype( 0 );
79 for( int k = 0; k < n; ++k )
80 ret[ i ][ j ] += A[ i ][ k ] * A[ j ][ k ];
81 ret[ j ][ i ] = ret[ i ][ j ];
82 }
83 ret[ i ][ i ] = ctype( 0 );
84 for( int k = 0; k < n; ++k )
85 ret[ i ][ i ] += A[ i ][ k ] * A[ i ][ k ];
86 }
87 }
88
90 // [[ expects: L is lower triangular ]]
91 template< int n >
92 static void Lx ( const FieldMatrix< ctype, n, n > &L, const FieldVector< ctype, n > &x, FieldVector< ctype, n > &ret )
93 {
94 for( int i = 0; i < n; ++i )
95 {
96 ret[ i ] = ctype( 0 );
97 for( int j = 0; j <= i; ++j )
98 ret[ i ] += L[ i ][ j ] * x[ j ];
99 }
100 }
101
103 // [[ expects: L is lower triangular ]]
104 template< int n >
105 static void LTx ( const FieldMatrix< ctype, n, n > &L, const FieldVector< ctype, n > &x, FieldVector< ctype, n > &ret )
106 {
107 for( int i = 0; i < n; ++i )
108 {
109 ret[ i ] = ctype( 0 );
110 for( int j = i; j < n; ++j )
111 ret[ i ] += L[ j ][ i ] * x[ j ];
112 }
113 }
114
116 // [[ expects: L is lower triangular ]]
117 template< int n >
118 static void LTL ( const FieldMatrix< ctype, n, n > &L, FieldMatrix< ctype, n, n > &ret )
119 {
120 for( int i = 0; i < n; ++i )
121 {
122 for( int j = 0; j < i; ++j )
123 {
124 ret[ i ][ j ] = ctype( 0 );
125 for( int k = i; k < n; ++k )
126 ret[ i ][ j ] += L[ k ][ i ] * L[ k ][ j ];
127 ret[ j ][ i ] = ret[ i ][ j ];
128 }
129 ret[ i ][ i ] = ctype( 0 );
130 for( int k = i; k < n; ++k )
131 ret[ i ][ i ] += L[ k ][ i ] * L[ k ][ i ];
132 }
133 }
134
136 // [[ expects: L is lower triangular ]]
137 template< int n >
138 static void LLT ( const FieldMatrix< ctype, n, n > &L, FieldMatrix< ctype, n, n > &ret )
139 {
140 for( int i = 0; i < n; ++i )
141 {
142 for( int j = 0; j < i; ++j )
143 {
144 ret[ i ][ j ] = ctype( 0 );
145 for( int k = 0; k <= j; ++k )
146 ret[ i ][ j ] += L[ i ][ k ] * L[ j ][ k ];
147 ret[ j ][ i ] = ret[ i ][ j ];
148 }
149 ret[ i ][ i ] = ctype( 0 );
150 for( int k = 0; k <= i; ++k )
151 ret[ i ][ i ] += L[ i ][ k ] * L[ i ][ k ];
152 }
153 }
154
157 // [[ expects: A is spd ]]
158 template< int n >
159 static bool cholesky_L ( const FieldMatrix< ctype, n, n > &A, FieldMatrix< ctype, n, n > &ret, const bool checkSingular = false )
160 {
161 using std::sqrt;
162 for( int i = 0; i < n; ++i )
163 {
164 ctype &rii = ret[ i ][ i ];
165
166 ctype xDiag = A[ i ][ i ];
167 for( int j = 0; j < i; ++j )
168 xDiag -= ret[ i ][ j ] * ret[ i ][ j ];
169
170 // in some cases A can be singular, e.g. when checking local for
171 // outside points during checkInside
172 if( checkSingular && ! ( xDiag > ctype( 0 )) )
173 return false ;
174
175 // otherwise this should be true always
176 assert( xDiag > ctype( 0 ) );
177 rii = sqrt( xDiag );
178
179 ctype invrii = ctype( 1 ) / rii;
180 for( int k = i+1; k < n; ++k )
181 {
182 ctype x = A[ k ][ i ];
183 for( int j = 0; j < i; ++j )
184 x -= ret[ i ][ j ] * ret[ k ][ j ];
185 ret[ k ][ i ] = invrii * x;
186 }
187 }
188
189 // return true for meaning A is non-singular
190 return true;
191 }
192
194 // [[ expects: L is lower triangular ]]
195 template< int n >
196 static ctype detL ( const FieldMatrix< ctype, n, n > &L )
197 {
198 ctype det( 1 );
199 for( int i = 0; i < n; ++i )
200 det *= L[ i ][ i ];
201 return det;
202 }
203
205 // [[ expects: L is lower triangular ]]
206 template< int n >
207 static ctype invL ( FieldMatrix< ctype, n, n > &L )
208 {
209 ctype det( 1 );
210 for( int i = 0; i < n; ++i )
211 {
212 ctype &lii = L[ i ][ i ];
213 det *= lii;
214 lii = ctype( 1 ) / lii;
215 for( int j = 0; j < i; ++j )
216 {
217 ctype &lij = L[ i ][ j ];
218 ctype x = lij * L[ j ][ j ];
219 for( int k = j+1; k < i; ++k )
220 x += L[ i ][ k ] * L[ k ][ j ];
221 lij = (-lii) * x;
222 }
223 }
224 return det;
225 }
226
228 // [[ expects: L is lower triangular ]]
229 template< int n >
230 static void invLx ( FieldMatrix< ctype, n, n > &L, FieldVector< ctype, n > &x )
231 {
232 for( int i = 0; i < n; ++i )
233 {
234 for( int j = 0; j < i; ++j )
235 x[ i ] -= L[ i ][ j ] * x[ j ];
236 x[ i ] /= L[ i ][ i ];
237 }
238 }
239
241 // [[ expects: L is lower triangular ]]
242 template< int n >
243 static void invLTx ( FieldMatrix< ctype, n, n > &L, FieldVector< ctype, n > &x )
244 {
245 for( int i = n; i > 0; --i )
246 {
247 for( int j = i; j < n; ++j )
248 x[ i-1 ] -= L[ j ][ i-1 ] * x[ j ];
249 x[ i-1 ] /= L[ i-1 ][ i-1 ];
250 }
251 }
252
254 // [[ expects: A is spd ]]
255 template< int n >
256 static ctype spdDetA ( const FieldMatrix< ctype, n, n > &A )
257 {
258 FieldMatrix< ctype, n, n > L;
259 cholesky_L( A, L );
260 return detL( L );
261 }
262
264 // [[ expects: A is spd ]]
265 template< int n >
266 static ctype spdInvA ( FieldMatrix< ctype, n, n > &A )
267 {
268 FieldMatrix< ctype, n, n > L;
269 cholesky_L( A, L );
270 const ctype det = invL( L );
271 LTL( L, A );
272 return det;
273 }
274
276 // [[ expects: A is spd ]]
277 template< int n >
278 static bool spdInvAx ( FieldMatrix< ctype, n, n > &A, FieldVector< ctype, n > &x, const bool checkSingular = false )
279 {
280 FieldMatrix< ctype, n, n > L;
281 const bool invertible = cholesky_L( A, L, checkSingular );
282 if( ! invertible ) return invertible ;
283 invLx( L, x );
284 invLTx( L, x );
285 return invertible;
286 }
287
289 template< int m, int n >
290 static ctype detATA ( const FieldMatrix< ctype, m, n > &A )
291 {
292 if constexpr( m >= n )
293 {
294 FieldMatrix< ctype, n, n > ata;
295 ATA_L( A, ata );
296 return spdDetA( ata );
297 }
298 else
299 return ctype( 0 );
300 }
301
307 template< int m, int n >
308 static ctype sqrtDetAAT ( const FieldMatrix< ctype, m, n > &A )
309 {
310 using std::abs;
311 using std::sqrt;
312 // These special cases are here not only for speed reasons:
313 // The general implementation aborts if the matrix is almost singular,
314 // and the special implementation provide a stable way to handle that case.
315 if constexpr( (n == 2) && (m == 2) )
316 {
317 // Special implementation for 2x2 matrices: faster and more stable
318 return abs( A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ] );
319 }
320 else if constexpr( (n == 3) && (m == 3) )
321 {
322 // Special implementation for 3x3 matrices
323 const ctype v0 = A[ 0 ][ 1 ] * A[ 1 ][ 2 ] - A[ 1 ][ 1 ] * A[ 0 ][ 2 ];
324 const ctype v1 = A[ 0 ][ 2 ] * A[ 1 ][ 0 ] - A[ 1 ][ 2 ] * A[ 0 ][ 0 ];
325 const ctype v2 = A[ 0 ][ 0 ] * A[ 1 ][ 1 ] - A[ 1 ][ 0 ] * A[ 0 ][ 1 ];
326 return abs( v0 * A[ 2 ][ 0 ] + v1 * A[ 2 ][ 1 ] + v2 * A[ 2 ][ 2 ] );
327 }
328 else if constexpr( (n == 3) && (m == 2) )
329 {
330 // Special implementation for 2x3 matrices
331 const ctype v0 = A[ 0 ][ 0 ] * A[ 1 ][ 1 ] - A[ 0 ][ 1 ] * A[ 1 ][ 0 ];
332 const ctype v1 = A[ 0 ][ 0 ] * A[ 1 ][ 2 ] - A[ 1 ][ 0 ] * A[ 0 ][ 2 ];
333 const ctype v2 = A[ 0 ][ 1 ] * A[ 1 ][ 2 ] - A[ 0 ][ 2 ] * A[ 1 ][ 1 ];
334 return sqrt( v0*v0 + v1*v1 + v2*v2);
335 }
336 else if constexpr( n >= m )
337 {
338 // General case
339 FieldMatrix< ctype, m, m > aat;
340 AAT_L( A, aat );
341 return spdDetA( aat );
342 }
343 else
344 return ctype( 0 );
345 }
346
348 // => A^{-1}_L A = I
349 template< int m, int n >
350 static ctype leftInvA ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, m > &ret )
351 {
352 using std::abs;
353 if constexpr( (n == 2) && (m == 2) )
354 {
355 const ctype det = (A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ]);
356 const ctype detInv = ctype( 1 ) / det;
357 ret[ 0 ][ 0 ] = A[ 1 ][ 1 ] * detInv;
358 ret[ 1 ][ 1 ] = A[ 0 ][ 0 ] * detInv;
359 ret[ 1 ][ 0 ] = -A[ 1 ][ 0 ] * detInv;
360 ret[ 0 ][ 1 ] = -A[ 0 ][ 1 ] * detInv;
361 return abs( det );
362 }
363 else
364 {
365 FieldMatrix< ctype, n, n > ata;
366 ATA_L( A, ata );
367 const ctype det = spdInvA( ata );
368 ATBT( ata, A, ret );
369 return det;
370 }
371 }
372
374 template< int m, int n >
375 static bool leftInvAx ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, m > &x, FieldVector< ctype, n > &y )
376 {
377 static_assert((m >= n), "Matrix has no left inverse.");
378 FieldMatrix< ctype, n, n > ata;
379 A.mtv(x, y);
380 ATA_L( A, ata );
381 return spdInvAx( ata, y, true );
382 }
383
385 template< int m, int n >
386 static ctype rightInvA ( const FieldMatrix< ctype, m, n > &A, FieldMatrix< ctype, n, m > &ret )
387 {
388 static_assert((n >= m), "Matrix has no right inverse.");
389 using std::abs;
390 if constexpr( (n == 2) && (m == 2) )
391 {
392 const ctype det = (A[ 0 ][ 0 ]*A[ 1 ][ 1 ] - A[ 1 ][ 0 ]*A[ 0 ][ 1 ]);
393 const ctype detInv = ctype( 1 ) / det;
394 ret[ 0 ][ 0 ] = A[ 1 ][ 1 ] * detInv;
395 ret[ 1 ][ 1 ] = A[ 0 ][ 0 ] * detInv;
396 ret[ 1 ][ 0 ] = -A[ 1 ][ 0 ] * detInv;
397 ret[ 0 ][ 1 ] = -A[ 0 ][ 1 ] * detInv;
398 return abs( det );
399 }
400 else
401 {
402 FieldMatrix< ctype, m , m > aat;
403 AAT_L( A, aat );
404 const ctype det = spdInvA( aat );
405 ATBT( A , aat , ret );
406 return det;
407 }
408 }
409
411 template< int m, int n >
412 static bool xTRightInvA ( const FieldMatrix< ctype, m, n > &A, const FieldVector< ctype, n > &x, FieldVector< ctype, m > &y )
413 {
414 static_assert((n >= m), "Matrix has no right inverse.");
415 FieldMatrix< ctype, m, m > aat;
416 A.mv(x, y);
417 AAT_L( A, aat );
418 // check whether aat is singular and return true if non-singular
419 return spdInvAx( aat, y, true );
420 }
421};
422
423} // namespace Impl
424} // namespace Dune
425
426#endif // DUNE_GEOMETRY_UTILITY_DEFAULTMATRIXHELPER_HH
constexpr T abs(T t)
T sqrt(T... args)