JUK1
StaticMatrix.hpp
Go to the documentation of this file.
1 #ifndef _MATRIX_HPP_INC_
2 #define _MATRIX_HPP_INC_
3 #include <string>
4 #include <sstream>
5 #include <iomanip>
6 #include <vector>
7 #include <concepts>
8 #include <array>
9 #include <assert.h>
10 #include <complex.h>
11 
12 template<typename T, size_t N = 1>
13 using storageType = typename std::conditional<
14  N * sizeof(T) < 20000, std::array<T, N>, std::vector<T> >::type;
15 
16 template<typename T>
17 std::complex<double>
18 operator>(const std::complex<T> & a, const std::complex<T> & b) {
19  return std::norm(a) > std::norm(b);
20 }
21 
22 template<typename T>
23 std::complex<double>
24 operator<(const std::complex<T> & a, const std::complex<T> & b) {
25  return std::norm(a) < std::norm(b);
26 }
27 
28 template<typename T>
29 std::complex<double>
30 operator>=(const std::complex<T> & a, const std::complex<T> & b) {
31  return std::norm(a) >= std::norm(b);
32 }
33 
34 template<typename T>
35 std::complex<double>
36 operator<=(const std::complex<T> & a, const std::complex<T> & b) {
37  return std::norm(a) <= std::norm(b);
38 }
39 
40 template<typename T>
41 concept arithmetic = requires(T a, T b) {
42  {a == b};
43  {a != b};
44  {a >= b};
45  {a <= b};
46  {a * b};
47  {a / b};
48  {a + b};
49  {a - b};
50 };
51 
57 template<typename T, size_t N, typename ST = storageType<T, N> >
58 requires arithmetic<T> struct StaticRow {
59  ST columns;
60 
61  static constexpr size_t sizeN = N;
62 
64  if constexpr (std::is_same<ST, std::vector<T> >::value) {
65  columns.resize(N);
66  }
67  }
68 
69  StaticRow(T initialValue) {
70  if constexpr (std::is_same<ST, std::vector<T> >::value) {
71  columns.resize(N);
72  }
73  columns.fill(initialValue);
74  }
75 
76  void fill(T value) {
77  columns.fill(value);
78  }
79 
80  T & operator[](size_t index) {
81  return columns[index];
82  }
83 
84  const T & operator[](size_t index) const {
85  return columns[index];
86  }
87 
88  T dot(StaticRow<T, N> other) {
89  T toRet = 0;
90  for (size_t i = 0; i < sizeN; i++) {
91  toRet += columns[i] * other.columns[i];
92  }
93  return toRet;
94  }
95 };
96 
97 template<typename T, size_t M>
98 struct StaticLUPair;
99 
106 template<typename T, size_t M, size_t N = M,
107  typename ST = storageType<StaticRow<T, N>, M> >
108 requires arithmetic<T> struct StaticMatrix {
109  ST rows;
110 
112  if constexpr (std::is_same<ST, std::vector<StaticRow<T, N> > >::value) {
113  rows.resize(M);
114  }
115  }
116 
117  StaticMatrix(T initialValue) {
118  if constexpr (std::is_same<ST, std::vector<T> >::value) {
119  rows.resize(M);
120  }
121  fill(initialValue);
122  }
123 
124  /*
125  StaticMatrix( const StaticMatrix< T, M, N, ST > & other ) {
126  if constexpr ( std::is_same< ST, std::vector< T > >::value ) {
127  rows.resize( M );
128  }
129  (*this) = other;
130  }
131 
132  StaticMatrix< T, M, N, ST > & operator=( const StaticMatrix< T, M, N, ST > &
133  other ) { for ( size_t m = 0; m < M; m++ ) { for ( size_t n = 0; n < N; n++ ) {
134  rows[ m
135  ][ n ] = other[ m ][ n ];
136  }
137  }
138  return *this;
139  }
140  */
141 
142  static constexpr size_t sizeM = M;
143  static constexpr size_t sizeN = N;
144 
145  void fill(T fillVal) {
146  for (auto & row : rows) {
147  row.fill(fillVal);
148  }
149  }
150 
151  StaticRow<T, N> & operator[](size_t index) {
152  return rows[index];
153  }
154 
155  StaticRow<T, N> operator[](size_t index) const {
156  return rows[index];
157  }
158 
159  void rowAddition(size_t destinationRow, size_t sourceRow, T scalingFactor) {
160  assert(0 <= destinationRow && destinationRow <= N);
161  assert(0 <= sourceRow && sourceRow <= M);
162  for (size_t i = 0; i < N; i++) {
163  rows[destinationRow][i] += scalingFactor * rows[sourceRow][i];
164  }
165  }
166 
167  void swapRows(size_t row1, size_t row2) {
168  std::swap(rows[row1], rows[row2]);
169  }
170 
173  for (size_t m = 0; m < M; m++) {
174  for (size_t n = 0; n < N; n++) {
175  toRet[n][m] = rows[m][n];
176  }
177  }
178  return toRet;
179  }
180 
181  template<size_t N2>
184  multiply(rhs, toRet);
185  return toRet;
186  }
187 
188  template<size_t N2>
190  StaticMatrix<T, M, N2> & dest) const {
191  // for simd reasons, the order of operations is slightly weird. This is to
192  // minimise row changes which may cause cache misses. This is due to the fact
193  // that in this model rows are represented contiguously in memory,
194  // so streaming instructions and local caching can be used to our advantage
195  //
196  // It is also worth stating that there is strong potential for multithreading
197  // here, and especially if paired with the Strassen Method for matrix
198  // multiplication However for small sizes, naive multiplication can be better
199  // due to less memory allocations
200 
201  for (size_t m = 0; m < M; m++) {
202  for (size_t k = 0; k < N; k++) {
203  for (size_t n = 0; n2 < N2; n2++) {
204  destination[m][n] += rows[m][k] * rows[k][n];
205  }
206  }
207  }
208  }
209 
212  add(rhs, toRet);
213  return toRet;
214  }
215 
216  void add(const StaticMatrix<T, M, N> & rhs, StaticMatrix<T, M, N> & dest) const {
217  for (size_t m = 0; m < M; m++) {
218  for (size_t n = 0; n < N; n++) {
219  dest[m][n] = rows[m][n] + rhs[m][n];
220  }
221  }
222  }
223 
226  add(rhs, toRet);
227  return toRet;
228  }
229 
230  void
232  for (size_t m = 0; m < M; m++) {
233  for (size_t n = 0; n < N; n++) {
234  dest[m][n] = rows[m][n] - dest[m][n]
235  }
236  }
237  }
238 
239  std::string toString() const {
240  std::stringstream toRet;
241  for (const auto & row : rows) {
242  for (const auto & val : row.columns) {
243  toRet << std::setw(5) << std::setprecision(2) << val << " ";
244  }
245 
246  toRet << std::endl;
247  }
248 
249  return toRet.str();
250  }
251 
253  static_assert(N == M, "StaticMatrix must be a square");
254 
256  luPair(toRet);
257  return toRet;
258  }
259 
260  void luPair(StaticLUPair<T, M> & dest) const {
261  static_assert(N == M, "StaticMatrix must be a square");
262 
263  dest.u = *this;
264  dest.l.fill(0.0);
265  for (size_t n = 0; n < N; n++) {
266  dest.l[n][n] = 1.0;
267  dest.p[n] = n;
268  }
269 
270  for (size_t r = 0; r < M - 1; r++) {
271  // find largest in column
272  size_t largestRow = r;
273  auto maxV = abs(dest.u[r][r]);
274  for (size_t r2 = r + 1; r2 < M; r2++) {
275  if (abs(dest.u[r2][r]) > maxV) {
276  maxV = abs(dest.u[r2][r]);
277  largestRow = r2;
278  }
279  }
280 
281  // swap rows in U and indices in p
282  dest.u.swapRows(r, largestRow);
283  std::swap(dest.p[r], dest.p[largestRow]);
284  // swap subdiagonal entries in L
285  for (size_t n = 0; n < r; n++) {
286  std::swap(dest.l[r][n], dest.l[largestRow][n]);
287  }
288 
289  // Gaussian elimination
290  for (size_t m = r + 1; m < M; m++) {
291  // TODO: potential for multithreading here
292  // need to take into account how many processors there are
293  // https://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency
294  T multiplier = dest.u[m][r] / dest.u[r][r];
295  dest.u.rowAddition(m, r, -multiplier);
296  dest.l[m][r] = multiplier;
297  }
298  // std::cout << "After Gaussian\n " << dest.toString();
299  }
300  }
301 
303  auto lu = luPair();
304  StaticMatrix<T, M, 1> scratchSpace;
306  leftDivide(rhs, lu, scratchSpace, toRet);
307  return toRet;
308  }
309 
311  StaticMatrix<T, M, 1> & scratchSpace,
312  StaticMatrix<T, M, 1> & dest) const {
313  for (size_t i = 0; i < M; i++) {
314  dest[i] = rhs[lu.p[i]];
315  }
316 
317  // scratchSpace: solve LY = Pb for y using substitution
318  for (size_t m = 0; m < M; m++) {
319  T val = dest[m][0];
320  for (size_t n = 0; n < m; n++) {
321  val -= scratchSpace[n][0] * lu.l[m][n];
322  }
323  scratchSpace[m][0] = val / lu.l[m][m];
324  }
325 
326  // stage2: solve Ux = Y for x using substitution
327  for (size_t m = 0; m < M; m++) {
328  T val = scratchSpace[M - m - 1][0];
329  for (size_t n = 0; n < m; n++) {
330  val -= dest[M - n - 1][0] * lu.u[M - m - 1][N - n - 1];
331  }
332  dest[M - m - 1][0] = val / lu.u[M - m - 1][M - m - 1];
333  }
334  }
335 };
336 
341 template<typename T, size_t M>
342 struct StaticLUPair {
345  std::array<size_t, M> p;
346 
347  std::string toString() {
348  std::stringstream toRet;
349  toRet << " U\n" << u.toString();
350  toRet << " L\n" << l.toString();
351  toRet << " p\n";
352  for (size_t i = 0; i < p.size(); i++) {
353  toRet << std::setw(5) << p[i] << " ";
354  }
355  toRet << std::endl;
356  return toRet.str();
357  }
358 };
359 // --------------------------------------------------------------------------
360 // Implementation
361 // --------------------------------------------------------------------------
362 
363 
364 #endif
PURPOSE j m
Definition: QPpassive.m:21
std::complex< double > operator>(const std::complex< T > &a, const std::complex< T > &b)
std::complex< double > operator<(const std::complex< T > &a, const std::complex< T > &b)
typename std::conditional< N *sizeof(T)< 20000, std::array< T, N >, std::vector< T > >::type storageType
concept arithmetic
std::complex< double > operator>=(const std::complex< T > &a, const std::complex< T > &b)
std::complex< double > operator<=(const std::complex< T > &a, const std::complex< T > &b)
Find a complex rational model for freq domain data for a
for i
b
Definition: getResidues.m:47
for k
Definition: interch.m:15
end if abs(real(dotprod))>rstoerst rstoerst
requires(std::is_arithmetic< ValType >::value &&NumVars >=0) struct DiffVar
A compile-time sized L U and pivot grouping.
StaticMatrix< T, M, M > u
std::string toString()
std::array< size_t, M > p
StaticMatrix< T, M, M > l
A compile-time sized matrix.
static constexpr size_t sizeM
void add(const StaticMatrix< T, M, N > &rhs, StaticMatrix< T, M, N > &dest) const
void leftDivide(const StaticMatrix< T, M, 1 > &rhs, const StaticLUPair< T, M > &lu, StaticMatrix< T, M, 1 > &scratchSpace, StaticMatrix< T, M, 1 > &dest) const
void rowAddition(size_t destinationRow, size_t sourceRow, T scalingFactor)
StaticMatrix< T, M, N2 > multiply(const StaticMatrix< T, N, N2 > &rhs) const
void subtract(const StaticMatrix< T, N, N > &rhs, StaticMatrix< T, M, N > &dest) const
StaticLUPair< T, M > luPair() const
std::string toString() const
static constexpr size_t sizeN
StaticMatrix< T, M, N > add(const StaticMatrix< T, M, N > &rhs) const
void fill(T fillVal)
void swapRows(size_t row1, size_t row2)
void luPair(StaticLUPair< T, M > &dest) const
StaticMatrix< T, N, M > transpose()
StaticMatrix< T, M, 1 > leftDivide(const StaticMatrix< T, M, 1 > &rhs) const
StaticRow< T, N > operator[](size_t index) const
StaticMatrix< T, M, N > subtract(const StaticMatrix< T, N, N > &rhs) const
StaticRow< T, N > & operator[](size_t index)
void multiply(const StaticMatrix< T, N, N2 > &rhs, StaticMatrix< T, M, N2 > &dest) const
StaticMatrix(T initialValue)
A compile-time sized matrix row.
void fill(T value)
T dot(StaticRow< T, N > other)
static constexpr size_t sizeN
const T & operator[](size_t index) const
StaticRow(T initialValue)
T & operator[](size_t index)