Jpp  18.6.0-rc.1
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JMatrixNS.hh
Go to the documentation of this file.
1 #ifndef __JMATH__JMATRIXNS__
2 #define __JMATH__JMATRIXNS__
3 
4 #include <vector>
5 #include <utility>
6 
7 #include "JMath/JMatrixND.hh"
8 #include "JMath/JVectorND.hh"
9 #include "JLang/JException.hh"
10 
11 
12 /**
13  * \author mdejong
14  */
15 
16 namespace JMATH {}
17 namespace JPP { using namespace JMATH; }
18 
19 namespace JMATH {
20 
23 
24 
25  /**
26  * N x N symmetric matrix
27  */
28  struct JMatrixNS :
29  public JMatrixND
30  {
31  /**
32  * Default constructor.
33  */
35  JMatrixND()
36  {}
37 
38 
39  /**
40  * Constructor (identity matrix).
41  *
42  * \param size dimension
43  */
44  JMatrixNS(const size_t size) :
45  JMatrixND(size)
46  {}
47 
48 
49  /**
50  * Contructor.
51  *
52  * \param A matrix
53  */
54  JMatrixNS(const JMatrixND& A) :
55  JMatrixND(A)
56  {}
57 
58 
59  /**
60  * Assignment operator.
61  *
62  * \param A matrix
63  */
65  {
66  this->set(A);
67 
68  return *this;
69  }
70 
71 
72  /**
73  * Invert matrix according LDU decomposition.
74  */
75  void invert()
76  {
77  using namespace std;
78 
79  size_t i, row, col, root;
80 
81  double* p0;
82  double* p1;
83  double* p2;
84  double* p3;
85 
86  const double* c0;
87 
88  double v0;
89  double v1;
90  double v2;
91  double v3;
92 
93  double w0;
94 
95  P.resize(this->size());
96 
97  // LDU decomposition
98 
99  for (root = 0; root != this->size(); ++root) {
100 
101  double value = (*this)(root, root);
102  size_t pivot = root;
103 
104  for (row = root; ++row != this->size(); ) {
105  if (fabs((*this)(row, root)) > fabs(value)) {
106  value = (*this)(row, root);
107  pivot = row;
108  }
109  }
110 
111  if (value == 0.0) {
112  THROW(JDivisionByZero, "LDU decomposition zero pivot at " << root);
113  }
114 
115  if (pivot != root) {
116  this->rswap(root, pivot);
117  }
118 
119  P[root] = pivot;
120 
121  for (row = root + 1; row + 4 <= this->size(); row += 4) { // process rows by four
122 
123  p0 = (*this)[row + 0] + root;
124  p1 = (*this)[row + 1] + root;
125  p2 = (*this)[row + 2] + root;
126  p3 = (*this)[row + 3] + root;
127 
128  v0 = (*p0++ /= value);
129  v1 = (*p1++ /= value);
130  v2 = (*p2++ /= value);
131  v3 = (*p3++ /= value);
132 
133  c0 = (*this)[root] + root + 1;
134 
135  for (i = root + 1; i + 4 <= this->size(); i += 4, p0 += 4, p1 += 4, p2 += 4, p3 += 4, c0 += 4) {
136  p0[0] -= v0 * c0[0]; p0[1] -= v0 * c0[1]; p0[2] -= v0 * c0[2]; p0[3] -= v0 * c0[3];
137  p1[0] -= v1 * c0[0]; p1[1] -= v1 * c0[1]; p1[2] -= v1 * c0[2]; p1[3] -= v1 * c0[3];
138  p2[0] -= v2 * c0[0]; p2[1] -= v2 * c0[1]; p2[2] -= v2 * c0[2]; p2[3] -= v2 * c0[3];
139  p3[0] -= v3 * c0[0]; p3[1] -= v3 * c0[1]; p3[2] -= v3 * c0[2]; p3[3] -= v3 * c0[3];
140  }
141 
142  for ( ; i != this->size(); ++i, ++p0, ++p1, ++p2, ++p3, ++c0) {
143  *p0 -= v0 * (*c0);
144  *p1 -= v1 * (*c0);
145  *p2 -= v2 * (*c0);
146  *p3 -= v3 * (*c0);
147  }
148  }
149 
150  for ( ; row != this->size(); ++row) { // remaining rows
151 
152  p0 = (*this)[row + 0] + root;
153 
154  v0 = (*p0++ /= value);
155 
156  c0 = (*this)[root] + root + 1;
157 
158  for (i = root + 1; i + 4 <= this->size(); i += 4, p0 += 4, c0 += 4) {
159  *p0 -= v0 * c0[0]; p0[1] -= v0 * c0[1]; p0[2] -= v0 * c0[2]; p0[3] -= v0 * c0[3];
160  }
161 
162  for ( ; i != this->size(); ++i, ++p0, ++c0) {
163  *p0 -= v0 * (*c0);
164  }
165  }
166  }
167 
168 
170 
171  A.reset();
172 
173  for (i = 0; i != this->size(); ++i) {
174  A(i,i) = 1.0;
175  }
176 
177 
178  // forward substitution
179 
180  col = 0;
181 
182  for ( ; col + 4 <= this->size(); col += 4) {
183 
184  for (row = 0; row != this->size(); ++row) {
185 
186  p0 = A[col + 0];
187  p1 = A[col + 1];
188  p2 = A[col + 2];
189  p3 = A[col + 3];
190 
191  i = P[row];
192 
193  v0 = p0[i];
194  v1 = p1[i];
195  v2 = p2[i];
196  v3 = p3[i];
197 
198  p0[i] = p0[row];
199  p1[i] = p1[row];
200  p2[i] = p2[row];
201  p3[i] = p3[row];
202 
203  for (i = 0, c0 = (*this)[row]; i != row; ++c0, ++p0, ++p1, ++p2, ++p3, ++i) {
204  v0 -= (*c0) * (*p0);
205  v1 -= (*c0) * (*p1);
206  v2 -= (*c0) * (*p2);
207  v3 -= (*c0) * (*p3);
208  }
209 
210  A[col + 0][row] = v0;
211  A[col + 1][row] = v1;
212  A[col + 2][row] = v2;
213  A[col + 3][row] = v3;
214  }
215  }
216 
217  for ( ; col != this->size(); ++col) {
218 
219  for (row = 0; row != this->size(); ++row) {
220 
221  p0 = A[col];
222 
223  i = P[row];
224 
225  v0 = p0[i];
226 
227  p0[i] = p0[row];
228 
229  for (i = 0, c0 = (*this)[row] + i; i != row; ++c0, ++p0, ++i) {
230  v0 -= (*c0) * (*p0);
231  }
232 
233  A[col][row] = v0;
234  }
235  }
236 
237  // backward substitution
238 
239  col = 0;
240 
241  for ( ; col + 4 <= this->size(); col += 4) {
242 
243  for (int row = this->size() - 1; row >= 0; --row) {
244 
245  p0 = A[col + 0] + row;
246  p1 = A[col + 1] + row;
247  p2 = A[col + 2] + row;
248  p3 = A[col + 3] + row;
249 
250  v0 = *p0;
251  v1 = *p1;
252  v2 = *p2;
253  v3 = *p3;
254 
255  ++p0;
256  ++p1;
257  ++p2;
258  ++p3;
259 
260  for (i = row + 1, c0 = (*this)[row] + i; i != this->size(); ++c0, ++p0, ++p1, ++p2, ++p3, ++i) {
261  v0 -= (*c0) * (*p0);
262  v1 -= (*c0) * (*p1);
263  v2 -= (*c0) * (*p2);
264  v3 -= (*c0) * (*p3);
265  }
266 
267  w0 = 1.0 / (*this)[row][row];
268 
269  A[col + 0][row] = v0 * w0;
270  A[col + 1][row] = v1 * w0;
271  A[col + 2][row] = v2 * w0;
272  A[col + 3][row] = v3 * w0;
273  }
274  }
275 
276  for ( ; col != this->size(); ++col) {
277 
278  for (int row = this->size() - 1; row >= 0; --row) {
279 
280  p0 = A[col] + row;
281 
282  v0 = *p0;
283 
284  ++p0;
285 
286  for (i = row + 1, c0 = (*this)[row] + i; i != this->size(); ++c0, ++p0, ++i) {
287  v0 -= (*c0) * (*p0);
288  }
289 
290  w0 = 1.0 / (*this)[row][row];
291 
292  A[col][row] = v0 * w0;
293  }
294  }
295 
296  A.transpose();
297 
298  this->swap(A);
299  }
300 
301 
302  /**
303  * Get solution of equation <tt>A x = b</tt>.
304  *
305  * \param u column vector; b on input, x on output(I/O)
306  */
307  template<class JVectorND_t>
308  void solve(JVectorND_t& u)
309  {
310  using namespace std;
311 
312  size_t i, row, root;
313 
314  double* p0;
315  double* p1;
316  double* p2;
317  double* p3;
318 
319  const double* c0;
320 
321  double v0;
322  double v1;
323  double v2;
324  double v3;
325 
326  P.resize(this->size());
327 
328  // LDU decomposition
329 
330  for (root = 0; root != this->size(); ++root) {
331 
332  double value = (*this)(root, root);
333  size_t pivot = root;
334 
335  for (row = root; ++row != this->size(); ) {
336  if (fabs((*this)(row, root)) > fabs(value)) {
337  value = (*this)(row, root);
338  pivot = row;
339  }
340  }
341 
342  if (value == 0.0) {
343  THROW(JDivisionByZero, "LDU decomposition zero pivot at " << root);
344  }
345 
346  if (pivot != root) {
347  this->rswap(root, pivot);
348  }
349 
350  P[root] = pivot;
351 
352  for (row = root + 1; row + 4 <= this->size(); row += 4) { // process rows by four
353 
354  p0 = (*this)[row + 0] + root;
355  p1 = (*this)[row + 1] + root;
356  p2 = (*this)[row + 2] + root;
357  p3 = (*this)[row + 3] + root;
358 
359  v0 = (*p0++ /= value);
360  v1 = (*p1++ /= value);
361  v2 = (*p2++ /= value);
362  v3 = (*p3++ /= value);
363 
364  c0 = (*this)[root] + root + 1;
365 
366  for (i = root + 1; i + 4 <= this->size(); i += 4, p0 += 4, p1 += 4, p2 += 4, p3 += 4, c0 += 4) {
367  p0[0] -= v0 * c0[0]; p0[1] -= v0 * c0[1]; p0[2] -= v0 * c0[2]; p0[3] -= v0 * c0[3];
368  p1[0] -= v1 * c0[0]; p1[1] -= v1 * c0[1]; p1[2] -= v1 * c0[2]; p1[3] -= v1 * c0[3];
369  p2[0] -= v2 * c0[0]; p2[1] -= v2 * c0[1]; p2[2] -= v2 * c0[2]; p2[3] -= v2 * c0[3];
370  p3[0] -= v3 * c0[0]; p3[1] -= v3 * c0[1]; p3[2] -= v3 * c0[2]; p3[3] -= v3 * c0[3];
371  }
372 
373  for ( ; i != this->size(); ++i, ++p0, ++p1, ++p2, ++p3, ++c0) {
374  *p0 -= v0 * (*c0);
375  *p1 -= v1 * (*c0);
376  *p2 -= v2 * (*c0);
377  *p3 -= v3 * (*c0);
378  }
379  }
380 
381  for ( ; row != this->size(); ++row) { // remaining rows
382 
383  p0 = (*this)[row + 0] + root;
384 
385  v0 = (*p0++ /= value);
386 
387  c0 = (*this)[root] + root + 1;
388 
389  for (i = root + 1; i + 4 <= this->size(); i += 4, p0 += 4, c0 += 4) {
390  *p0 -= v0 * c0[0]; p0[1] -= v0 * c0[1]; p0[2] -= v0 * c0[2]; p0[3] -= v0 * c0[3];
391  }
392 
393  for ( ; i != this->size(); ++i, ++p0, ++c0) {
394  *p0 -= v0 * (*c0);
395  }
396  }
397  }
398 
399  // forward substitution
400 
401  for (row = 0; row != this->size(); ++row) {
402 
403  i = P[row];
404  v0 = u[i];
405  u[i] = u[row];
406 
407  for (i = 0, c0 = (*this)[row] + i; i != row; ++c0, ++i) {
408  v0 -= *c0 * u[i];
409  }
410 
411  u[row] = v0;
412  }
413 
414  // backward substitution
415 
416  for (int row = this->size() - 1; row >= 0; --row) {
417 
418  v0 = u[row];
419 
420  for (i = row + 1, c0 = (*this)[row] + i; i < this->size(); ++c0, ++i) {
421  v0 -= *c0 * u[i];
422  }
423 
424  u[row] = v0 / (*this)[row][row];
425  }
426  }
427 
428 
429  /**
430  * Update inverted matrix at given diagonal element.
431  *
432  * If A is the original matrix and A' is such that for each <tt>(i,j) != (k,k)</tt>:
433  * <pre>
434  * A'[i][j] = A[i][j]
435  * A'[k][k] = A[k][k] + value
436  * </pre>
437  * then <tt>JMatrixNS::update(k, value)</tt> will modify the already inverted matrix
438  * of A such that it will be the inverse of A'.
439  *
440  * See also <a href="https://arxiv.org/abs/1708.07622"> arXiv</a>.\n
441  * This algorithm can be considered a special case of the Sherman–Morrison formula.
442  *
443  * \param k index of diagonal element
444  * \param value value to add
445  */
446  void update(const size_t k, const double value)
447  {
448  if (k >= this->size()) {
449  THROW(JIndexOutOfRange, "JMatrixNS::update(): index out of range " << k);
450  }
451 
452  size_t i, row;
453  double* col;
454 
455  const double del = (*this)(k,k);
456  const double din = 1.0 / (1.0 + value * del);
457 
458  double* root = (*this)[k];
459 
460  for (row = 0; row != this->size(); ++row) {
461 
462  if (row != k) {
463 
464  const double val = (*this)(row, k);
465 
466  for (i = 0, col = (*this)[row]; i != this->size(); ++i, ++col) {
467  if (i != k) {
468  (*col) -= val * root[i] * value * din;
469  }
470  }
471 
472  (*this)(row, k) *= din;
473  }
474  }
475 
476  for (i = 0, col = root; i != this->size(); ++i, ++col) {
477  if (i != k) {
478  (*col) *= din;
479  }
480  }
481 
482  root[k] = del * din;
483  }
484 
485  private:
486  std::vector<int> P; //!< permutation matrix
487  };
488 }
489 
490 #endif
Exceptions.
then fatal No hydrophone data file $HYDROPHONE_TXT fi sort gr k
TPaveText * p1
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
Definition: JException.hh:712
JMatrixNS(const JMatrixND &A)
Contructor.
Definition: JMatrixNS.hh:54
JMatrixND_t & getInstance()
Get work space.
Definition: JMatrixND.hh:361
void update(const size_t k, const double value)
Update inverted matrix at given diagonal element.
Definition: JMatrixNS.hh:446
JMatrixNS()
Default constructor.
Definition: JMatrixNS.hh:34
std::vector< int > P
permutation matrix
Definition: JMatrixNS.hh:486
do JPlot2D f $WORKDIR canberra[${EMITTER}\] root
NxN matrix.
Definition: JMatrixND.hh:348
void set(const JMatrixND_t &A)
Set matrix.
Definition: JMatrixND.hh:155
JMatrixNS & operator=(const JMatrixNS &A)
Assignment operator.
Definition: JMatrixNS.hh:64
N x N symmetric matrix.
Definition: JMatrixNS.hh:28
void rswap(size_t r1, size_t r2)
Definition: JMatrixND.hh:873
void invert()
Invert matrix according LDU decomposition.
Definition: JMatrixNS.hh:75
size_t size() const
Get dimension of matrix.
Definition: JMatrixND.hh:202
p2
Definition: module-Z:fit.sh:74
Exception for division by zero.
Definition: JException.hh:286
void solve(JVectorND_t &u)
Get solution of equation A x = b.
Definition: JMatrixNS.hh:308
void swap(JMatrixND_t &A)
Swap matrices.
Definition: JMatrixND.hh:168
Exception for accessing an index in a collection that is outside of its range.
Definition: JException.hh:106
double u[N+1]
Definition: JPolint.hh:865
source $JPP_DIR setenv csh $JPP_DIR &dev null eval JShellParser o a A
JMatrixNS(const size_t size)
Constructor (identity matrix).
Definition: JMatrixNS.hh:44
p3
Definition: module-Z:fit.sh:74
Basic NxN matrix.
Definition: JMatrixND.hh:36