openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
dense_mat.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
11 #ifndef DENSE_MAT_H
12 #define DENSE_MAT_H
13 
14 #include <utility>
15 #include <assert.h>
16 
17 #include "SF_vector.h"
18 
19 namespace SF {
20 
26 template<class S>
27 class dmat
28 {
29  private:
30  S* _data;
31  short _rows;
32  short _cols;
33  short* _ps;
34 
35  public:
37  dmat() : _data(nullptr), _rows(0), _cols(0), _ps(nullptr)
38  {}
40  dmat(const short irows, const short icols) : _data(nullptr), _rows(0), _cols(0), _ps(nullptr)
41  {
42  set_size(irows, icols);
43  }
45  dmat(const dmat<S> & m) : _data(nullptr), _rows(0), _cols(0), _ps(nullptr)
46  {
47  this->assign(m);
48  }
51  {
52  if(_data)
53  delete [] _data;
54  if(_ps)
55  delete [] _ps;
56  }
58  inline void set_size(const short irows, const short icols)
59  {
60  if(irows*icols > _rows*_cols) {
61  if(_data) delete [] _data;
62  _data = new S[irows*icols];
63  }
64  _rows = irows;
65  _cols = icols;
66  }
67 
68  inline dmat<S>& operator= (dmat<S>&& m)
69  {
70  std::swap(_data, m._data);
71  std::swap(_rows, m._rows);
72  std::swap(_cols, m._cols);
73  return *this;
74  }
75 
76  inline dmat<S>& operator= (const dmat<S>& m)
77  {
78  this->set_size(m._rows, m._cols);
79  for(int idx=0; idx < _rows*_cols; idx++)
80  _data[idx] = m._data[idx];
81 
82  return *this;
83  }
85  inline const S* operator[] (short ridx) const
86  {
87  return (_data +(ridx*_cols));
88  }
90  inline S* operator[] (short ridx)
91  {
92  return (_data +(ridx*_cols));
93  }
94 
95  inline void operator+= (const dmat<S>& m)
96  {
97  if ((_rows == 0)||(_cols == 0)) assign(m._rows, m._cols, S());
98  assert (_rows == m._rows && _cols == m._cols);
99  for(int i=0; i<_rows*_cols; i++) _data[i] += m._data[i];
100  }
101 
102  inline void operator-= (const dmat<S>& m)
103  {
104  if ((_rows == 0)||(_cols == 0)) assign(m._rows, m._cols, S());
105  assert (_rows == m._rows && _cols == m._cols);
106  for(int i=0; i<_rows*_cols; i++) _data[i] -= m._data[i];
107  }
108 
109  inline void operator*= (const S s)
110  {
111  for(int i=0; i<_rows*_cols; i++) _data[i] *= s;
112  }
113 
114  inline void operator/= (const S s)
115  {
116  for(int i=0; i<_rows*_cols; i++) _data[i] /= s;
117  }
118 
120  inline void assign(const dmat<S> & m)
121  {
122  set_size(m.rows(), m.cols());
123  const S* ele = m[0];
124 
125  for(short i=0; i<_rows*_cols; i++) _data[i] = ele[i];
126  }
128  inline void assign(const S v)
129  {
130  for(short i=0; i<_rows*_cols; i++) _data[i] = v;
131  }
133  inline void assign(const S *v)
134  {
135  for(short i=0; i<_rows*_cols; i++) _data[i] = v[i];
136  }
137 
139  inline void assign(const short irows, const short icols, const S v)
140  {
141  this->set_size(irows, icols);
142  this->assign(v);
143  }
145  inline void assign(const short irows, const short icols, const S *v)
146  {
147  this->set_size(irows, icols);
148  this->assign(v);
149  }
150 
152  inline void diag(const S v)
153  {
154  for(short i=0; i<_rows; i++)
155  _data[i*_cols+i] = v;
156  }
157 
158  inline short rows() const
159  {
160  return _rows;
161  }
162  inline short cols() const
163  {
164  return _cols;
165  }
167  inline void mult(const dmat<S> & in, dmat<S> & out) const
168  {
169  out.set_size(_rows, in.cols());
170  out.assign(S(0));
171 
172  for(short i=0; i<_rows; i++) {
173  for(short j=0; j<in.cols(); j++) {
174  for(short k=0; k<_cols; k++)
175  out[i][j] += _data[i*_cols+k] * in[k][j];
176  }
177  }
178  }
180  inline double double_cont(const dmat<S> & in) const
181  {
182  double out = 0.;
183 
184  for(short i=0; i<_rows; i++) {
185  for(short j=0; j<in.cols(); j++) {
186  out += _data[i*_cols+j] * in[i][j];
187  }
188  }
189  return out;
190  }
191 
193  inline void mult(const S* in, S* out)
194  {
195  for(short i=0; i<_rows; i++) {
196  out[i] = S(0);
197  for(short j=0; j<_cols; j++)
198  out[i] += _data[i*_cols+j] * in[j];
199  }
200  }
201 
202  // A^T * in
203  inline void mult_transp(const S* in, S* out)
204  {
205  for(short i=0; i<_rows; i++) {
206  out[i] = S(0);
207  for(short j=0; j<_cols; j++)
208  out[i] += _data[j*_cols+i] * in[j];
209  }
210  }
211 
212  inline void transpose()
213  {
214  if(_cols == _rows) {
215  // for quadratic matrices we dont need to resize
216  // therefore we swap the entries in-place
217  for(short i=0; i<_rows; i++) {
218  for(short j=i+1; j<_cols; j++)
219  {
220  S up = _data[i*_cols+j];
221  S lo = _data[j*_cols+i];
222  _data[j*_cols+i] = up;
223  _data[i*_cols+j] = lo;
224  }
225  }
226  }
227  else {
228  // since we need to resize, we create a local copy
229  // and then resize and copy
230  dmat<S> t(*this);
231  set_size(t.cols(), t.rows());
232  for(short i=0; i<t.rows(); i++) {
233  for(short j=0; j<t.cols(); j++)
234  _data[j*_cols+i] = t[i][j];
235  }
236  }
237  }
238 
239  inline void disp(const char* name)
240  {
241  printf("\n%s\n", name);
242  for(short i=0; i<_rows; i++) {
243  for(short j=0; j<_cols; j++)
244  printf(" %g ", _data[i*_cols+j]);
245  printf("\n");
246  }
247  }
248 
249  inline S* data()
250  {
251  return _data;
252  }
253  inline const S* data() const
254  {
255  return _data;
256  }
257 
258  inline bool lu_decomp()
259  {
260  assert(_rows == _cols);
261  const short n = _rows;
262  dmat<S> & lu = *this;
263  _ps = new short[n];
264 
265  S* scales = new S[n];
266  S pivot, biggest, mlt, tempf;
267  short pivotindex = 0;
268  short i, j, k;
269  // double d = 1.0; // No row interchanges yet.
270 
271  // For each row.
272  for (i = 0; i < n; i++) {
273  // Find the largest element in each row for row equilibration
274  biggest = 0.0;
275  for (j = 0; j < n; j++)
276  if (biggest < (tempf = fabs(lu[i][j])))
277  biggest = tempf;
278  if (biggest != 0.0)
279  scales[i] = 1.0 / biggest;
280  else {
281  scales[i] = 0.0;
282  return false; // Zero row: singular matrix.
283  }
284  _ps[i] = i; // Initialize pivot sequence.
285  }
286 
287  // For each column.
288  for (k = 0; k < n - 1; k++) {
289  // Find the largest element in each column to pivot around.
290  biggest = 0.0;
291  for (i = k; i < n; i++) {
292  if (biggest < (tempf = fabs(lu[_ps[i]][k]) * scales[_ps[i]])) {
293  biggest = tempf;
294  pivotindex = i;
295  }
296  }
297 
298  if (biggest == 0.0)
299  return false; // Zero column: singular matrix.
300 
301  // Update pivot sequence.
302  if (pivotindex != k) {
303  j = _ps[k];
304  _ps[k] = _ps[pivotindex];
305  _ps[pivotindex] = j;
306  // d = -(d); // ...and change the parity of d.
307  }
308 
309  // Pivot, eliminating an extra variable each time
310  pivot = lu[_ps[k]][k];
311  for (i = k + 1; i < n; i++) {
312  lu[_ps[i]][k] = mlt = lu[_ps[i]][k] / pivot;
313 
314  if (mlt != 0.0) {
315  for (j = k + 1; j < n; j++)
316  lu[_ps[i]][j] -= mlt * lu[_ps[k]][j];
317  }
318  }
319  }
320 
321  delete [] scales;
322 
323  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
324  return lu[_ps[n - 1]][n - 1] != 0.0;
325  }
326 
327  void lu_solve(S* rhs)
328  {
329  short i, j;
330  const short n = _rows;
331  dmat<S> & lu = *this;
332 
333  S *X = new S[n], dot_prod;
334 
335  for (i = 0; i < n; i++) X[i] = 0.0;
336 
337  // Vector reduction using U triangular matrix.
338  for (i = 0; i < n; i++) {
339  dot_prod = 0.0;
340  for (j = 0; j < i; j++) dot_prod += lu[_ps[i]][j] * X[j];
341  X[i] = rhs[_ps[i]] - dot_prod;
342  }
343 
344  // Back substitution, in L triangular matrix.
345  for (i = n - 1; i >= 0; i--) {
346  dot_prod = 0.0;
347  for (j = i + 1; j < n; j++) dot_prod += lu[_ps[i]][j] * X[j];
348  X[i] = (X[i] - dot_prod) / lu[_ps[i]][i];
349  }
350 
351  for (i = 0; i < n; i++) rhs[i] = X[i];
352 
353  delete [] X;
354  }
355 };
356 
357 template<class S>
358 dmat<S> operator* (const dmat<S> & a, const dmat<S> & b)
359 {
360  dmat<S> r;
361  a.mult(b, r);
362  return r;
363 }
364 
365 template<class S>
366 S* operator* (const dmat<S> & a, const S* v)
367 {
368  S* r = new S[a.rows()];
369  a.mult(v, r);
370  return r;
371 }
372 
373 template<class S>
374 dmat<S> operator* (const dmat<S> & a, const S v)
375 {
376  dmat<S> r(a);
377  r *= v;
378  return r;
379 }
380 
381 template<class S>
382 dmat<S> operator* (const S v, const dmat<S> & a)
383 {
384  dmat<S> r(a);
385  r *= v;
386  return r;
387 }
388 
389 template<class S>
390 dmat<S> operator/ (const dmat<S> & a, const S v)
391 {
392  dmat<S> r(a);
393  r /= v;
394  return r;
395 }
396 
397 template<class S>
398 dmat<S> operator+ (const dmat<S> & a, const dmat<S> & b)
399 {
400  dmat<S> r(a);
401  r += b;
402  return r;
403 }
404 
405 template<class S>
406 dmat<S> operator- (const dmat<S> & a, const dmat<S> & b)
407 {
408  dmat<S> r(a);
409  r -= b;
410  return r;
411 }
412 
413 template<class S>
415 {
416  dmat<S> r(a);
417  r.transpose();
418  return r;
419 }
420 
422 template<class S>
423 double double_cont(const dmat<S>& A, const dmat<S>& B)
424 {
425  double out = 0.;
426 
427  for(short i=0; i<A.rows(); i++) {
428  for(short j=0; j<B.cols(); j++) {
429  out += A[i][j] * B[i][j];
430  }
431  }
432  return out;
433 }
434 
435 
436 template<class S>
437 void invert_3x3(S* ele, S & det)
438 {
439  // save block entries in temp variables
440  S e0 = ele[0], e1 = ele[1], e2 = ele[2], e3 = ele[3];
441  S e4 = ele[4], e5 = ele[5], e6 = ele[6], e7 = ele[7], e8 = ele[8];
442  // compute determinant
443  det = e0*e4*e8 + e1*e5*e6 + e2*e3*e7 - e2*e4*e6 - e1*e3*e8 - e0*e5*e7;
444  S idet = 1.0 / det;
445 
446  // invert block
447  ele[0] = (e4*e8 - e5*e7) * idet;
448  ele[1] = (e2*e7 - e1*e8) * idet;
449  ele[2] = (e1*e5 - e2*e4) * idet;
450  ele[3] = (e5*e6 - e3*e8) * idet;
451  ele[4] = (e0*e8 - e2*e6) * idet;
452  ele[5] = (e2*e3 - e0*e5) * idet;
453  ele[6] = (e3*e7 - e4*e6) * idet;
454  ele[7] = (e1*e6 - e0*e7) * idet;
455  ele[8] = (e0*e4 - e1*e3) * idet;
456 }
457 
458 template<class S>
459 void invert_3x3(dmat<S> & m, S & det)
460 {
461  assert(m.rows() == 3 && m.cols() == 3);
462 
463  S* ele = m.data();
464  invert_3x3(ele, det);
465 }
466 
467 template<class S>
469 {
470  assert(m.rows() == 3 && m.cols() == 3);
471  dmat<S> r(m);
472 
473  S* ele = r.data();
474  double det;
475 
476  invert_3x3(ele, det);
477 
478  return r;
479 }
480 
481 template<class S>
482 S det_3x3(const dmat<S> & m)
483 {
484  const S* ele = m[0];
485  // save block entries in temp variables
486  S e0 = ele[0], e1 = ele[1], e2 = ele[2], e3 = ele[3];
487  S e4 = ele[4], e5 = ele[5], e6 = ele[6], e7 = ele[7], e8 = ele[8];
488  // compute determinant
489  return e0*e4*e8 + e1*e5*e6 + e2*e3*e7 - e2*e4*e6 - e1*e3*e8 - e0*e5*e7;
490 }
491 
492 template<class S>
494 {
495  assert(m.rows() == 2 && m.cols() == 2);
496  dmat<S> r(m);
497 
498  // save block entries in temp variables
499  S* ele = r[0];
500  double det;
501  invert_2x2(ele, det);
502  return r;
503 }
504 
505 template<class S>
506 void invert_2x2(S* ele, S & det)
507 {
508  // save block entries in temp variables
509  S e0 = ele[0], e1 = ele[1], e2 = ele[2], e3 = ele[3];
510  // compute determinant
511  det = e0*e3 - e1*e2;
512  S idet = 1.0 / det;
513 
514  // invert block
515  ele[0] = e3 * idet;
516  ele[1] = -e1 * idet;
517  ele[2] = -e2 * idet;
518  ele[3] = e0 * idet;
519 }
520 
521 template<class S>
522 void invert_2x2(dmat<S> & m, S & det)
523 {
524  assert(m.rows() == 2 && m.cols() == 2);
525 
526  // save block entries in temp variables
527  S* ele = m[0];
528  invert_2x2(ele, det);
529 }
530 
531 template<class S, class V>
532 void array_to_tensors(const vector<S> & arr, vector<dmat<V> > & m)
533 {
534  m.resize(arr.size()/9);
535  for(size_t i=0; i<m.size(); i++)
536  {
537  m[i].assign(3, 3, &arr[i*9]);
538  }
539 }
540 
541 template<class S, class V>
542 void tensors_to_array(const vector<dmat<S> > & m, vector<V> & arr)
543 {
544  arr.resize(m.size()*9);
545  for(size_t i=0; i<m.size(); i++)
546  {
547 
548  arr[i*9+0] = m[i][0][0]; arr[i*9+1] = m[i][0][1]; arr[i*9+2] = m[i][0][2];
549  arr[i*9+3] = m[i][1][0]; arr[i*9+4] = m[i][1][1]; arr[i*9+5] = m[i][1][2];
550  arr[i*9+6] = m[i][2][0]; arr[i*9+7] = m[i][2][1]; arr[i*9+8] = m[i][2][2];
551  }
552 }
553 
554 }
555 
556 #endif
The vector class and related algorithms.
Dense matrix class.
Definition: dense_mat.hpp:28
void assign(const short irows, const short icols, const S *v)
resize and set all entries to a value
Definition: dense_mat.hpp:145
dmat(const short irows, const short icols)
constructor that initializes the dimensions
Definition: dense_mat.hpp:40
void operator-=(const dmat< S > &m)
Definition: dense_mat.hpp:102
dmat< S > & operator=(dmat< S > &&m)
Definition: dense_mat.hpp:68
void diag(const S v)
set all diagonal entries to a value
Definition: dense_mat.hpp:152
void assign(const dmat< S > &m)
copy a mtrix.
Definition: dense_mat.hpp:120
void assign(const S v)
set all entries to a value
Definition: dense_mat.hpp:128
void lu_solve(S *rhs)
Definition: dense_mat.hpp:327
short cols() const
Definition: dense_mat.hpp:162
dmat(const dmat< S > &m)
constructor that deep-copies a given dmat
Definition: dense_mat.hpp:45
double double_cont(const dmat< S > &in) const
mat-mat double contraction
Definition: dense_mat.hpp:180
void transpose()
Definition: dense_mat.hpp:212
const S * data() const
Definition: dense_mat.hpp:253
void set_size(const short irows, const short icols)
set the matrix dimensions
Definition: dense_mat.hpp:58
~dmat()
destructor
Definition: dense_mat.hpp:50
void assign(const S *v)
set all entries to a value
Definition: dense_mat.hpp:133
S * data()
Definition: dense_mat.hpp:249
bool lu_decomp()
Definition: dense_mat.hpp:258
void assign(const short irows, const short icols, const S v)
resize and set all entries to a value
Definition: dense_mat.hpp:139
dmat()
empty constructor
Definition: dense_mat.hpp:37
void operator/=(const S s)
Definition: dense_mat.hpp:114
void operator+=(const dmat< S > &m)
Definition: dense_mat.hpp:95
void disp(const char *name)
Definition: dense_mat.hpp:239
void mult(const S *in, S *out)
mat-vec multiplication
Definition: dense_mat.hpp:193
short rows() const
Definition: dense_mat.hpp:158
void operator*=(const S s)
Definition: dense_mat.hpp:109
const S * operator[](short ridx) const
[] operator returns the pointer to the beginning of a given row
Definition: dense_mat.hpp:85
void mult_transp(const S *in, S *out)
Definition: dense_mat.hpp:203
void mult(const dmat< S > &in, dmat< S > &out) const
mat-mat multiplication
Definition: dense_mat.hpp:167
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:194
Definition: dense_mat.hpp:19
void invert_3x3(S *ele, S &det)
Definition: dense_mat.hpp:437
dmat< S > operator-(const dmat< S > &a, const dmat< S > &b)
Definition: dense_mat.hpp:406
dmat< S > operator/(const dmat< S > &a, const S v)
Definition: dense_mat.hpp:390
double double_cont(const dmat< S > &A, const dmat< S > &B)
mat-mat double contraction A:B
Definition: dense_mat.hpp:423
dmat< S > invert_2x2(const dmat< S > &m)
Definition: dense_mat.hpp:493
dmat< S > operator*(const dmat< S > &a, const dmat< S > &b)
Definition: dense_mat.hpp:358
dmat< S > transpose(const dmat< S > &a)
Definition: dense_mat.hpp:414
void tensors_to_array(const vector< dmat< S > > &m, vector< V > &arr)
Definition: dense_mat.hpp:542
dmat< S > operator+(const dmat< S > &a, const dmat< S > &b)
Definition: dense_mat.hpp:398
void array_to_tensors(const vector< S > &arr, vector< dmat< V > > &m)
Definition: dense_mat.hpp:532
S det_3x3(const dmat< S > &m)
Definition: dense_mat.hpp:482
@ X
Definition: kdpart.hpp:49