linear-library
Loading...
Searching...
No Matches
DecomposeLU.hpp
Go to the documentation of this file.
1#pragma once
2#include "../vector_matrix/VectorMatrix.hpp"
3#include <vector>
4#include <utility>
5#include <limits>
6#include <type_traits>
7#include <cmath>
8
9namespace LinearAlgebra{
21 template<typename T>
23 static_assert(std::is_floating_point_v<T>,
24 "T must be a floating-point type (float or double)");
25 private:
26
27 VectorMatrix<T> matrix;
28 double detP;
29 void elimination(int col);
30 void initL() {
31 int rows = matrix.getRows();
32 int cols = matrix.getColumns();
33 L = std::vector<std::vector<T>>(rows, std::vector<T>(cols, 0));
34 for (int i = 0; i < rows; i++) {
35 L[i][i] = 1;
36 }
37
38 };
39 void initP() {
40 int n = matrix.getRows();
41 P = std::vector<int>(n);
42 for(int i=0; i < n; i++){
43 P[i] = i;
44 }
45 };
46 std::vector<int> initInvP() const {
47 int n = matrix.getRows();
48 std::vector<int>invP(n,-1);
49 for (int i = 0; i < n; i++)
50 {
51 int pi = P[i];
52 if (pi < 0 || pi >= n) throw std::invalid_argument("invalid permutation");
53 invP[pi] = i;
54 }
55 return invP;
56 };
57 int pivoting(int col);
58 void forwardSubstitution(std::vector<T>& y, const std::vector<T>& b, int n) const;
59 void backwardSubstitution(std::vector<T>& x, const std::vector<T>& y, int n) const;
60 std::vector<std::vector<T>> L;
61 std::vector<std::vector<T>> U;
62 std::vector<int> P; //vector of swap
63 static constexpr T eps = std::numeric_limits<T>::epsilon() * static_cast<T>(100);
64 void decomposition();
65 public:
66
67 DecomposeLU(const VectorMatrix<T>& m) : matrix(m) {
68 detP = 1;
69 decomposition();
70 }
71
72 DecomposeLU(VectorMatrix<T>&& m) : matrix(std::move(m)) {
73 detP = 1;
74 decomposition();
75 }
76 T det() const;
77 VectorMatrix<T> inv() const;
78 const std::vector<std::vector<T>>& getU() const{ return U; }
79 const std::vector<std::vector<T>>& getL() const{ return L; }
80 const std::vector<int>& getP() const{ return P; }
81 };
82
83
84 template<typename T>
85 int DecomposeLU<T>::pivoting(int col) {
86 T pivotVal = std::abs(U[col][col]);
87 int pivot = col;
88 int rows = matrix.getRows();
89 if (col < 0 || col >= rows) {
90 throw std::runtime_error("Invalid column index");
91 }
92 for (int i = col+1; i < rows; i++) {
93 auto &Ui = U[i];
94 if(std::abs(Ui[col]) > pivotVal) {
95 pivotVal = std::abs(Ui[col]);
96 pivot = i;
97 }
98 }
99 if (pivotVal <= eps) throw std::runtime_error("Matrix is singular");
100 return pivot;
101 }
102
103
107 template<typename T>
108 void DecomposeLU<T>::elimination(int col) {
109 int rows = matrix.getRows();
110 int cols = matrix.getColumns();
111
112 if(std::abs(U[col][col]) <= eps) throw std::runtime_error("Pivot is zero");
113 T pivot = U[col][col];
114 for (int i = col+1; i < rows; i++)
115 {
116 auto &Ui = U[i];
117 T& Li_col = L[i][col];
118 Li_col=Ui[col]/pivot;
119 const auto &Ucol = U[col];
120
121 for (int j = col+1; j < cols; j++)
122 {
123 Ui[j] -= Li_col * Ucol[j];
124 }
125 Ui[col] = static_cast<T>(0);
126 }
127
128 }
129
130
131 template<typename T>
132 void DecomposeLU<T>::decomposition() {
133 if (matrix.getRows() != matrix.getColumns())
134 throw std::runtime_error("Matrix must be square for LU decomposition");
135 int n = matrix.getRows();
136 U = matrix.getMatrix();
137 initL();
138 initP();
139 int swapCount = 0;
140 for (int k = 0; k < n; ++k) {
141 int pivot = pivoting(k);
142
143 if(pivot != k) {
144 using std::swap;
145 swap(U[pivot],U[k]);
146 swap(P[pivot],P[k]);
147 if (k > 0)
148 swap_ranges(L[pivot].begin(), L[pivot].begin() + k, L[k].begin());
149 swapCount++;
150 }
151 elimination(k);
152 }
153 detP = swapCount % 2 == 0 ? 1 : -1;
154 }
155
161 template<typename T>
163 const auto& U = getU();
164 int rows = U.size();
165 T det = T(1);
166 for (int i = 0; i < rows; i++) det*=U[i][i];
167
168 return det*detP;
169 }
170
171 template<typename T>
172 void DecomposeLU<T>::forwardSubstitution(std::vector<T>& y, const std::vector<T>& b, int n) const{
173 for (int j = 0; j < n; ++j) {
174 T sum = 0;
175 auto& Lj = L[j];
176 auto& Ljj = L[j][j];
177 for (int k = 0; k < j; ++k) sum += Lj[k] * y[k];
178 y[j] = (b[j] - sum)/Ljj;
179 }
180 }
181
182 template<typename T>
183 void DecomposeLU<T>::backwardSubstitution(std::vector<T>& x, const std::vector<T>& y, int n) const{
184 for (int k = n-1; k >= 0; --k){
185 T sum = 0;
186 auto& Uk = U[k];
187 auto& Ukk = U[k][k];
188 for (int s = k+1; s < n; ++s) sum += Uk[s] * x[s];
189 x[k] = (y[k] - sum)/Ukk;
190 }
191 }
192
193 template<typename T>
195 int n = matrix.getRows();
196 std::vector<std::vector<T>> X(n, std::vector<T>(n));
197 std::vector<int> invP = initInvP();
198 std::vector<T> b(n), y(n), x(n);
199 int prev = invP[0];
200 b[prev] = T(1);
201 for(int i = 0; i < n; ++i) {
202 int curr = invP[i];
203
204 if (i > 0) {
205 b[prev] = T(0);
206 b[curr] = T(1);
207 }
208
209 forwardSubstitution(y, b, n);
210 backwardSubstitution(x, y, n);
211
212 for (int k = 0; k < n; ++k) {
213 auto& Xki = X[k][i];
214 Xki = x[k];
215 }
216
217 prev = curr;
218 }
219
220 return VectorMatrix<T>(std::move(X));
221 }
222}
LU decomposition with partial pivoting.
Definition DecomposeLU.hpp:22
const std::vector< int > & getP() const
Definition DecomposeLU.hpp:80
DecomposeLU(const VectorMatrix< T > &m)
Definition DecomposeLU.hpp:67
DecomposeLU(VectorMatrix< T > &&m)
Definition DecomposeLU.hpp:72
T det() const
Determinant matrix A Computed as: det(A) = det(P) * product(diag(U))
Definition DecomposeLU.hpp:162
VectorMatrix< T > inv() const
Definition DecomposeLU.hpp:194
const std::vector< std::vector< T > > & getU() const
Definition DecomposeLU.hpp:78
const std::vector< std::vector< T > > & getL() const
Definition DecomposeLU.hpp:79
Examples:
Definition VectorMatrix.hpp:32
int getColumns() const
return count columns
Definition VectorMatrix.hpp:110
int getRows() const
return count rows
Definition VectorMatrix.hpp:107
Definition DecomposeLU.hpp:9