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