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