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