preCICE v3.2.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MathHelper.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Core>
4
5namespace precice::utils {
13inline Eigen::MatrixXd invertLowerTriangularBlockwise(const Eigen::MatrixXd &L)
14{
15 const int n = L.rows();
16
17 // We copy over Eigen's block size heuristic to set the block size
18 int blockSize = static_cast<int>(n / 8);
19 blockSize = (blockSize / 16) * 16;
20 blockSize = std::min(std::max(blockSize, 8), 128);
21
22 // Handle small matrices by setting blockSize to n if it's zero
23 if (blockSize == 0) {
24 blockSize = n;
25 }
26 const int numBlocks = static_cast<int>((n + blockSize - 1) / blockSize);
27
28 // Initialize the inverse matrix as a identity (enables inPlaceSolve)
29 // TODO: maybe consider to return by reference, as Eigen doesn't recommend to return by value
30 Eigen::MatrixXd L_inv = Eigen::MatrixXd::Identity(n, n);
31
32 // Now we iterate over all blocks...
33 for (int i = 0; i < numBlocks; ++i) {
34 int i_start = i * blockSize;
35 int i_end = std::min(i_start + blockSize, n);
36 int i_blockSize = i_end - i_start;
37
38 // Step 1: Invert the diagonal block
39 L.block(i_start, i_start, i_blockSize, i_blockSize)
40 .triangularView<Eigen::Lower>()
41 .solveInPlace(L_inv.block(i_start, i_start, i_blockSize, i_blockSize));
42
43 // Step 2: Compute off-diagonal blocks
44 for (int j = 0; j < i; ++j) {
45 int j_start = j * blockSize;
46 int j_end = std::min(j_start + blockSize, n);
47 int j_blockSize = j_end - j_start;
48
49 // computation for the off-diagonal block using the block Lij and Ljj (from L_inv)
50 Eigen::MatrixXd offDiagBlock = L.block(i_start, j_start, i_blockSize, j_blockSize) * L_inv.block(j_start, j_start, j_blockSize, j_blockSize)
51 .triangularView<Eigen::Lower>();
52 // Accumulate the sum of L_ik * L_inv(k, j) for k = j+1 to i-1
53 for (int k = j + 1; k < i; ++k) {
54 int k_start = k * blockSize;
55 int k_end = std::min(k_start + blockSize, n);
56 int k_blockSize = k_end - k_start;
57
58 // Update offDiagBlock with L_ik + L_inv_kj
59 offDiagBlock += L.block(i_start, k_start, i_blockSize, k_blockSize) * L_inv.block(k_start, j_start, k_blockSize, j_blockSize);
60 }
61
62 // Fill in the off-diagonal block into the matrix
63 // Note that, although L_inv is on both sides, there source and destination are different in memory
64 L_inv.block(i_start, j_start, i_blockSize, j_blockSize) = -L_inv.block(i_start, i_start, i_blockSize, i_blockSize) * offDiagBlock;
65 }
66 }
67 return L_inv;
68}
69} // namespace precice::utils
T max(T... args)
T min(T... args)
contains precice-related utilities.
Eigen::MatrixXd invertLowerTriangularBlockwise(const Eigen::MatrixXd &L)
Implements an iterative block scheme to determine the inverse of a lower triangular matrix which is m...