Jpp test-rotations-new
the software that should make you happy
Loading...
Searching...
No Matches
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
16namespace JMATH {}
17namespace JPP { using namespace JMATH; }
18
19namespace 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) :
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
TPaveText * p1
Exceptions.
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
Exception for division by zero.
Exception for accessing an index in a collection that is outside of its range.
Auxiliary classes and methods for mathematical operations.
Definition JEigen3D.hh:88
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Definition root.py:1
Basic NxN matrix.
Definition JMatrixND.hh:36
size_t size() const
Get dimension of matrix.
Definition JMatrixND.hh:202
void set(const JMatrixND_t &A)
Set matrix.
Definition JMatrixND.hh:155
void swap(JMatrixND_t &A)
Swap matrices.
Definition JMatrixND.hh:168
NxN matrix.
Definition JMatrixND.hh:352
JMatrixND_t & getInstance()
Get work space.
Definition JMatrixND.hh:361
void rswap(size_t r1, size_t r2)
Definition JMatrixND.hh:873
N x N symmetric matrix.
Definition JMatrixNS.hh:30
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
void solve(JVectorND_t &u)
Get solution of equation A x = b.
Definition JMatrixNS.hh:308
JMatrixNS(const size_t size)
Constructor (identity matrix).
Definition JMatrixNS.hh:44
std::vector< int > P
permutation matrix
Definition JMatrixNS.hh:486
JMatrixNS(const JMatrixND &A)
Contructor.
Definition JMatrixNS.hh:54
void invert()
Invert matrix according LDU decomposition.
Definition JMatrixNS.hh:75
JMatrixNS & operator=(const JMatrixNS &A)
Assignment operator.
Definition JMatrixNS.hh:64