ALFI
Advanced Library for Function Interpolation
Loading...
Searching...
No Matches
linalg.h
Go to the documentation of this file.
1#pragma once
2
3#include <iostream>
4
5#include "../config.h"
6
31 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
32 Container<Number> lup_solve(Container<Container<Number>>&& A, Container<Number>&& B, Number epsilon = std::numeric_limits<Number>::epsilon()) {
33 const auto n = B.size();
34 assert(n == A.size());
35 for (SizeT i = 0; i < n; ++i) {
36 assert(n == A[i].size());
37 Number max_a = std::abs(A[i][i]);
38 SizeT i_max = i;
39 for (SizeT k = i + 1; k < n; ++k) {
40 const auto cur = std::abs(A[k][i]);
41 if (cur > max_a) {
42 max_a = cur;
43 i_max = k;
44 }
45 }
46 if (max_a < epsilon) {
47 std::cerr << "Error in function " << __FUNCTION__ << ": Matrix A is degenerate. Returning an empty array..." << std::endl;
48 return {};
49 }
50 if (i_max != i) {
51 std::swap(A[i], A[i_max]);
52 std::swap(B[i], B[i_max]);
53 }
54 for (SizeT j = i + 1; j < n; ++j) {
55 A[j][i] /= A[i][i];
56 for (SizeT k = i + 1; k < n; ++k) {
57 A[j][k] -= A[j][i] * A[i][k];
58 }
59 }
60 }
61 Container<Number> X(n);
62 for (SizeT i = 0; i < n; ++i) {
63 X[i] = B[i];
64 for (SizeT k = 0; k < i; ++k) {
65 X[i] -= A[i][k] * X[k];
66 }
67 }
68 for (SizeT iter = 0; iter < n; ++iter) {
69 const auto i = n - 1 - iter;
70 for (SizeT k = i + 1; k < n; ++k) {
71 X[i] -= A[i][k] * X[k];
72 }
73 X[i] /= A[i][i];
74 }
75 return X;
76 }
77
100 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
101 Container<Number> tridiag_solve_unstable(
102 const Container<Number>& lower,
103 Container<Number>&& diag,
104 const Container<Number>& upper,
105 Container<Number>&& right
106 ) {
107 const auto n = right.size();
108 assert(n == lower.size());
109 assert(n == diag.size());
110 assert(n == upper.size());
111 if (n == 0) {
112 return {};
113 }
114 for (SizeT i = 0; i < n - 1; ++i) {
115 const auto m = lower[i+1] / diag[i];
116 diag[i+1] -= m * upper[i];
117 right[i+1] -= m * right[i];
118 }
119 Container<Number> X(n);
120 X[n-1] = right[n-1] / diag[n-1];
121 for (SizeT iter = 2; iter <= n; ++iter) {
122 const auto i = n - iter;
123 X[i] = (right[i] - upper[i] * X[i+1]) / diag[i];
124 }
125 return X;
126 }
127
147 template <typename Number = DefaultNumber, template <typename, typename...> class Container = DefaultContainer>
148 Container<Number> tridiag_solve(
149 Container<Number>&& lower,
150 Container<Number>&& diag,
151 Container<Number>&& upper,
152 Container<Number>&& right
153 ) {
154 const auto n = right.size();
155 assert(n == lower.size());
156 assert(n == diag.size());
157 assert(n == upper.size());
158 if (n == 0) {
159 return {};
160 }
161 if (n == 1) {
162 return {right[0]/diag[0]};
163 }
164 for (SizeT i = 0; i < n - 1; ++i) {
165 if (std::abs(diag[i]) >= std::abs(lower[i+1])) {
166 const auto m = lower[i+1] / diag[i];
167 diag[i+1] -= m * upper[i];
168 right[i+1] -= m * right[i];
169 lower[i+1] = 0;
170 } else {
171 // Swap rows i and (i+1).
172 // Eliminate the lower[i+1] element by reducing row (i+1) by row i.
173 // Use lower[i+1] as a buffer for the non-tridiagonal element (i,i+2) (hack, used below).
174 const auto m = diag[i] / lower[i+1];
175 diag[i] = lower[i+1];
176 lower[i+1] = upper[i+1];
177 upper[i+1] *= -m;
178 std::swap(upper[i], diag[i+1]);
179 diag[i+1] -= m * upper[i];
180 std::swap(right[i], right[i+1]);
181 right[i+1] -= m * right[i];
182 }
183 }
184 Container<Number> X(n);
185 X[n-1] = right[n-1] / diag[n-1];
186 X[n-2] = (right[n-2] - upper[n-2] * X[n-1]) / diag[n-2];
187 for (SizeT iter = 3; iter <= n; ++iter) {
188 const auto i = n - iter;
189 X[i] = (right[i] - upper[i] * X[i+1] - lower[i+1] * X[i+2]) / diag[i];
190 }
191 return X;
192 }
193}
Definition linalg.h:7
Container< Number > tridiag_solve(Container< Number > &&lower, Container< Number > &&diag, Container< Number > &&upper, Container< Number > &&right)
Solves a tridiagonal system of linear equations.
Definition linalg.h:148
Container< Number > lup_solve(Container< Container< Number > > &&A, Container< Number > &&B, Number epsilon=std::numeric_limits< Number >::epsilon())
Solves a system of linear equations using LUP decomposition.
Definition linalg.h:32
Container< Number > tridiag_solve_unstable(const Container< Number > &lower, Container< Number > &&diag, const Container< Number > &upper, Container< Number > &&right)
Solves a tridiagonal system of linear equations.
Definition linalg.h:101
ALFI_DEFAULT_NUMBER DefaultNumber
Definition config.h:17
ALFI_SIZE_TYPE SizeT
Definition config.h:22
ALFI_DEFAULT_CONTAINER< Number > DefaultContainer
Definition config.h:20