Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CholeskyDecomp.h
Go to the documentation of this file.
1// @(#)root/smatrix:$Id$
2// Author: M. Schiller 2009
3
4#ifndef ROOT_Math_CholeskyDecomp
5#define ROOT_Math_CholeskyDecomp
6
7/** @file
8 * header file containing the templated implementation of matrix inversion
9 * routines for use with ROOT's SMatrix classes (symmetric positive
10 * definite case)
11 *
12 * @author Manuel Schiller
13 * @date Aug 29 2008
14 * initial release inside LHCb
15 * @date May 7 2009
16 * factored code to provide a nice Cholesky decomposition class, along
17 * with separate methods for solving a single linear system and to
18 * obtain the inverse matrix from the decomposition
19 * @date July 15th 2013
20 * provide a version of that class which works if the dimension of the
21 * problem is only known at run time
22 * @date September 30th 2013
23 * provide routines to access the result of the decomposition L and its
24 * inverse
25 * @date January 20th 2024
26 * CholeskyDecompGenDim allowed copying and moving, but did not provide copy
27 * and move constructors or assignment operators, resulting in incorrect
28 * code and potential memory corruption, if somebody tried to copy/move a
29 * CholeskyDecompGenDim instance. Since we're in a C++17 world now, use the
30 * excellent movable std::vector<F> to get rid of explicit memory management
31 * in CholeskyDecompGenDim, and thus provide correct code for copy/move
32 * construction and assignment. Moreover, the provided releaseWorkspace
33 * method allows reuse of the allocated vector inside a CholeskyDecompGenDim
34 * to reduce the cost of repeated matrix decomposition.
35 */
36
37#include <cmath>
38#include <vector>
39#include <algorithm>
40
41namespace ROOT {
42
43namespace Math {
44
45/// helpers for CholeskyDecomp
46namespace CholeskyDecompHelpers {
47// forward decls
48template <class F, class M>
50template <class F, unsigned N, class M>
51struct _decomposer;
52template <class F, class M>
53struct _inverterGenDim;
54template <class F, unsigned N, class M>
55struct _inverter;
56template <class F, class V>
57struct _solverGenDim;
58template <class F, unsigned N, class V>
59struct _solver;
60template <typename G>
62} // namespace CholeskyDecompHelpers
63
64/// class to compute the Cholesky decomposition of a matrix
65/** class to compute the Cholesky decomposition of a symmetric
66 * positive definite matrix
67 *
68 * provides routines to check if the decomposition succeeded (i.e. if
69 * matrix is positive definite and non-singular), to solve a linear
70 * system for the given matrix and to obtain its inverse
71 *
72 * the actual functionality is implemented in templated helper
73 * classes which have specializations for dimensions N = 1 to 6
74 * to achieve a gain in speed for common matrix sizes
75 *
76 * usage example:
77 * @code
78 * // let m be a symmetric positive definite SMatrix (use type float
79 * // for internal computations, matrix size is 4x4)
80 * CholeskyDecomp<float, 4> decomp(m);
81 * // check if the decomposition succeeded
82 * if (!decomp) {
83 * std::cerr << "decomposition failed!" << std::endl;
84 * } else {
85 * // let rhs be a vector; we seek a vector x such that m * x = rhs
86 * decomp.Solve(rhs);
87 * // rhs now contains the solution we are looking for
88 *
89 * // obtain the inverse of m, put it into m itself
90 * decomp.Invert(m);
91 * }
92 * @endcode
93 */
94template <class F, unsigned N>
96private:
97 /// lower triangular matrix L
98 /** lower triangular matrix L, packed storage, with diagonal
99 * elements pre-inverted */
100 F fL[N * (N + 1) / 2];
101 /// flag indicating a successful decomposition
102 bool fOk;
103
104public:
105 /// perform a Cholesky decomposition
106 /** perform a Cholesky decomposition of a symmetric positive
107 * definite matrix m
108 *
109 * this is the constructor to uses with an SMatrix (and objects
110 * that behave like an SMatrix in terms of using
111 * operator()(int i, int j) for access to elements)
112 */
113 template <class M>
119
120 /// perform a Cholesky decomposition
121 /** perform a Cholesky decomposition of a symmetric positive
122 * definite matrix m
123 *
124 * this is the constructor to use in special applications where
125 * plain arrays are used
126 *
127 * NOTE: the matrix is given in packed representation, matrix
128 * element m(i,j) (j <= i) is supposed to be in array element
129 * (i * (i + 1)) / 2 + j
130 */
131 template <typename G>
138
139 /// returns true if decomposition was successful
140 /** @returns true if decomposition was successful */
141 bool ok() const { return fOk; }
142 /// returns true if decomposition was successful
143 /** @returns true if decomposition was successful */
144 operator bool() const { return fOk; }
145
146 /** @brief solves a linear system for the given right hand side
147 *
148 * Note that you can use both SVector classes and plain arrays for
149 * rhs. (Make sure that the sizes match!). It will work with any vector
150 * implementing the operator [i]
151 *
152 * @returns if the decomposition was successful
153 */
154 template <class V>
155 bool Solve(V &rhs) const
156 {
158 if (fOk)
160 return fOk;
161 }
162
163 /** @brief place the inverse into m
164 *
165 * This is the method to use with an SMatrix.
166 *
167 * @returns if the decomposition was successful
168 */
169 template <class M>
170 bool Invert(M &m) const
171 {
173 if (fOk)
175 return fOk;
176 }
177
178 /** @brief place the inverse into m
179 *
180 * This is the method to use with a plain array.
181 *
182 * @returns if the decomposition was successful
183 *
184 * NOTE: the matrix is given in packed representation, matrix
185 * element m(i,j) (j <= i) is supposed to be in array element
186 * (i * (i + 1)) / 2 + j
187 */
188 template <typename G>
199
200 /** @brief obtain the decomposed matrix L
201 *
202 * This is the method to use with a plain array.
203 *
204 * @returns if the decomposition was successful
205 */
206 template <class M>
207 bool getL(M &m) const
208 {
209 if (!fOk)
210 return false;
211 for (unsigned i = 0; i < N; ++i) {
212 // zero upper half of matrix
213 for (unsigned j = i + 1; j < N; ++j)
214 m(i, j) = F(0);
215 // copy the rest
216 for (unsigned j = 0; j <= i; ++j)
217 m(i, j) = fL[i * (i + 1) / 2 + j];
218 // adjust the diagonal - we save 1/L(i, i) in that position, so
219 // convert to what caller expects
220 m(i, i) = F(1) / m(i, i);
221 }
222 return true;
223 }
224
225 /** @brief obtain the decomposed matrix L
226 *
227 * @returns if the decomposition was successful
228 *
229 * NOTE: the matrix is given in packed representation, matrix
230 * element m(i,j) (j <= i) is supposed to be in array element
231 * (i * (i + 1)) / 2 + j
232 */
233 template <typename G>
234 bool getL(G *m) const
235 {
236 if (!fOk)
237 return false;
238 // copy L
239 for (unsigned i = 0; i < (N * (N + 1)) / 2; ++i)
240 m[i] = fL[i];
241 // adjust diagonal - we save 1/L(i, i) in that position, so convert to
242 // what caller expects
243 for (unsigned i = 0; i < N; ++i)
244 m[(i * (i + 1)) / 2 + i] = F(1) / fL[(i * (i + 1)) / 2 + i];
245 return true;
246 }
247
248 /** @brief obtain the inverse of the decomposed matrix L
249 *
250 * This is the method to use with a plain array.
251 *
252 * @returns if the decomposition was successful
253 */
254 template <class M>
255 bool getLi(M &m) const
256 {
257 if (!fOk)
258 return false;
259 for (unsigned i = 0; i < N; ++i) {
260 // zero lower half of matrix
261 for (unsigned j = i + 1; j < N; ++j)
262 m(j, i) = F(0);
263 // copy the rest
264 for (unsigned j = 0; j <= i; ++j)
265 m(j, i) = fL[i * (i + 1) / 2 + j];
266 }
267 // invert the off-diagonal part of what we just copied
268 for (unsigned i = 1; i < N; ++i) {
269 for (unsigned j = 0; j < i; ++j) {
270 typename M::value_type tmp = F(0);
271 for (unsigned k = i; k-- > j;)
272 tmp -= m(k, i) * m(j, k);
273 m(j, i) = tmp * m(i, i);
274 }
275 }
276 return true;
277 }
278
279 /** @brief obtain the inverse of the decomposed matrix L
280 *
281 * @returns if the decomposition was successful
282 *
283 * NOTE: the matrix is given in packed representation, matrix
284 * element m(j,i) (j <= i) is supposed to be in array element
285 * (i * (i + 1)) / 2 + j
286 */
287 template <typename G>
288 bool getLi(G *m) const
289 {
290 if (!fOk)
291 return false;
292 // copy L
293 for (unsigned i = 0; i < (N * (N + 1)) / 2; ++i)
294 m[i] = fL[i];
295 // invert the off-diagonal part of what we just copied
296 G *base1 = &m[1];
297 for (unsigned i = 1; i < N; base1 += ++i) {
298 for (unsigned j = 0; j < i; ++j) {
299 G tmp = F(0);
300 const G *base2 = &m[(i * (i - 1)) / 2];
301 for (unsigned k = i; k-- > j; base2 -= k)
302 tmp -= base1[k] * base2[j];
303 base1[j] = tmp * base1[i];
304 }
305 }
306 return true;
307 }
308};
309
310/// class to compute the Cholesky decomposition of a matrix
311/** class to compute the Cholesky decomposition of a symmetric
312 * positive definite matrix when the dimensionality of the problem is not known
313 * at compile time
314 *
315 * provides routines to check if the decomposition succeeded (i.e. if
316 * matrix is positive definite and non-singular), to solve a linear
317 * system for the given matrix and to obtain its inverse
318 *
319 * the actual functionality is implemented in templated helper
320 * classes which have specializations for dimensions N = 1 to 6
321 * to achieve a gain in speed for common matrix sizes
322 *
323 * usage example:
324 * @code
325 * // let m be a symmetric positive definite SMatrix (use type float
326 * // for internal computations, matrix size is 4x4)
327 * CholeskyDecompGenDim<float> decomp(4, m);
328 * // check if the decomposition succeeded
329 * if (!decomp) {
330 * std::cerr << "decomposition failed!" << std::endl;
331 * } else {
332 * // let rhs be a vector; we seek a vector x such that m * x = rhs
333 * decomp.Solve(rhs);
334 * // rhs now contains the solution we are looking for
335 *
336 * // obtain the inverse of m, put it into m itself
337 * decomp.Invert(m);
338 * }
339 * @endcode
340 */
341template <class F>
343private:
344 /** @brief dimensionality
345 * dimensionality of the problem */
346 unsigned fN = 0;
347 /// lower triangular matrix L
348 /** lower triangular matrix L, packed storage, with diagonal
349 * elements pre-inverted */
350 std::vector<F> fL;
351 /// flag indicating a successful decomposition
352 bool fOk = false;
353
354public:
355 /// perform a Cholesky decomposition
356 /** perform a Cholesky decomposition of a symmetric positive
357 * definite matrix m
358 *
359 * this is the constructor to uses with an SMatrix (and objects
360 * that behave like an SMatrix in terms of using
361 * operator()(int i, int j) for access to elements)
362 *
363 * The optional wksp parameter that can be used to avoid (re-)allocations
364 * on repeated decompositions of the same size (by passing a workspace of
365 * size N * (N + 1), or reusing one returned from releaseWorkspace by a
366 * previous decomposition).
367 */
368 template <class M>
369 CholeskyDecompGenDim(unsigned N, const M &m, std::vector<F> wksp = {}) : fN(N), fL(std::move(wksp))
370 {
372 if (fL.size() < fN * (fN + 1) / 2)
373 fL.resize(fN * (fN + 1) / 2);
374 fOk = _decomposerGenDim<F, M>()(fL.data(), m, fN);
375 }
376
377 /// perform a Cholesky decomposition
378 /** perform a Cholesky decomposition of a symmetric positive
379 * definite matrix m
380 *
381 * this is the constructor to use in special applications where
382 * plain arrays are used
383 *
384 * NOTE: the matrix is given in packed representation, matrix
385 * element m(i,j) (j <= i) is supposed to be in array element
386 * (i * (i + 1)) / 2 + j
387 *
388 * The optional wksp parameter that can be used to avoid (re-)allocations
389 * on repeated decompositions of the same size (by passing a workspace of
390 * size N * (N + 1), or reusing one returned from releaseWorkspace by a
391 * previous decomposition).
392 */
393 template <typename G>
394 CholeskyDecompGenDim(unsigned N, G *m, std::vector<F> wksp = {}) : fN(N), fL(std::move(wksp))
395 {
398 if (fL.size() < fN * (fN + 1) / 2)
399 fL.resize(fN * (fN + 1) / 2);
401 }
402
403 /// release the workspace of the decomposition for reuse
404 /** release the workspace of the decomposition for reuse
405 *
406 * If you use CholeskyDecompGenDim repeatedly with the same size N, it is
407 * possible to avoid repeatedly allocating the internal workspace. The
408 * constructors take an optional wksp argument, and this routine can be
409 * called to get the workspace out of a decomposition when you are done
410 * with it.
411 *
412 * Please note that once you call releaseWorkspace, you cannot do further
413 * operations on the decomposition object (and this is indicated by having
414 * it return false when you call ok()).
415 *
416 * Here is an example snippet of (pseudo-)code which illustrates the use of
417 * releaseWorkspace for inverting the covariance matrices of a number of
418 * items (which must all be of the same size):
419 *
420 * @code
421 * std::vector<float> wksp;
422 * for (const auto& item: items) {
423 * CholeskyDecompGenDim decomp(item.cov().size(), item.cov(),
424 * std::move(wksp));
425 * if (decomp.ok()) {
426 * decomp.Invert(item.invcov());
427 * }
428 * wksp = std::move(decomp.releaseWorkspace());
429 * }
430 * @endcode
431 *
432 * In the above code snippet, only the first CholeskyDecompGenDim
433 * constructor call will allocate memory. Subsequent calls in the loop will
434 * reuse the buffer from the first iteration.
435 */
436 std::vector<F> releaseWorkspace()
437 {
438 fN = 0;
439 fOk = false;
440 return std::move(fL);
441 }
442
443 /// returns true if decomposition was successful
444 /** @returns true if decomposition was successful */
445 bool ok() const { return fOk; }
446 /// returns true if decomposition was successful
447 /** @returns true if decomposition was successful */
448 operator bool() const { return fOk; }
449
450 /** @brief solves a linear system for the given right hand side
451 *
452 * Note that you can use both SVector classes and plain arrays for
453 * rhs. (Make sure that the sizes match!). It will work with any vector
454 * implementing the operator [i]
455 *
456 * @returns if the decomposition was successful
457 */
458 template <class V>
459 bool Solve(V &rhs) const
460 {
462 if (fOk)
463 _solverGenDim<F, V>()(rhs, fL.data(), fN);
464 return fOk;
465 }
466
467 /** @brief place the inverse into m
468 *
469 * This is the method to use with an SMatrix.
470 *
471 * @returns if the decomposition was successful
472 */
473 template <class M>
474 bool Invert(M &m) const
475 {
477 if (fOk) {
478 auto wksp = fL;
479 _inverterGenDim<F, M>()(m, fN, wksp.data());
480 }
481 return fOk;
482 }
483
484 /** @brief place the inverse into m
485 *
486 * This is the method to use with a plain array.
487 *
488 * @returns if the decomposition was successful
489 *
490 * NOTE: the matrix is given in packed representation, matrix
491 * element m(i,j) (j <= i) is supposed to be in array element
492 * (i * (i + 1)) / 2 + j
493 */
494 template <typename G>
495 bool Invert(G *m) const
496 {
499 if (fOk) {
500 auto wksp = fL;
503 }
504 return fOk;
505 }
506
507 /** @brief obtain the decomposed matrix L
508 *
509 * This is the method to use with a plain array.
510 *
511 * @returns if the decomposition was successful
512 */
513 template <class M>
514 bool getL(M &m) const
515 {
516 if (!fOk)
517 return false;
518 const F *L = fL.data();
519 for (unsigned i = 0; i < fN; ++i) {
520 // zero upper half of matrix
521 for (unsigned j = i + 1; j < fN; ++j)
522 m(i, j) = F(0);
523 // copy the rest
524 for (unsigned j = 0; j <= i; ++j)
525 m(i, j) = L[i * (i + 1) / 2 + j];
526 // adjust the diagonal - we save 1/L(i, i) in that position, so
527 // convert to what caller expects
528 m(i, i) = F(1) / m(i, i);
529 }
530 return true;
531 }
532
533 /** @brief obtain the decomposed matrix L
534 *
535 * @returns if the decomposition was successful
536 *
537 * NOTE: the matrix is given in packed representation, matrix
538 * element m(i,j) (j <= i) is supposed to be in array element
539 * (i * (i + 1)) / 2 + j
540 */
541 template <typename G>
542 bool getL(G *m) const
543 {
544 if (!fOk)
545 return false;
546 const F *L = fL.data();
547 // copy L
548 for (unsigned i = 0; i < (fN * (fN + 1)) / 2; ++i)
549 m[i] = L[i];
550 // adjust diagonal - we save 1/L(i, i) in that position, so convert to
551 // what caller expects
552 for (unsigned i = 0; i < fN; ++i)
553 m[(i * (i + 1)) / 2 + i] = F(1) / L[(i * (i + 1)) / 2 + i];
554 return true;
555 }
556
557 /** @brief obtain the inverse of the decomposed matrix L
558 *
559 * This is the method to use with a plain array.
560 *
561 * @returns if the decomposition was successful
562 */
563 template <class M>
564 bool getLi(M &m) const
565 {
566 if (!fOk)
567 return false;
568 const F *L = fL.data();
569 for (unsigned i = 0; i < fN; ++i) {
570 // zero lower half of matrix
571 for (unsigned j = i + 1; j < fN; ++j)
572 m(j, i) = F(0);
573 // copy the rest
574 for (unsigned j = 0; j <= i; ++j)
575 m(j, i) = L[i * (i + 1) / 2 + j];
576 }
577 // invert the off-diagonal part of what we just copied
578 for (unsigned i = 1; i < fN; ++i) {
579 for (unsigned j = 0; j < i; ++j) {
580 typename M::value_type tmp = F(0);
581 for (unsigned k = i; k-- > j;)
582 tmp -= m(k, i) * m(j, k);
583 m(j, i) = tmp * m(i, i);
584 }
585 }
586 return true;
587 }
588
589 /** @brief obtain the inverse of the decomposed matrix L
590 *
591 * @returns if the decomposition was successful
592 *
593 * NOTE: the matrix is given in packed representation, matrix
594 * element m(j,i) (j <= i) is supposed to be in array element
595 * (i * (i + 1)) / 2 + j
596 */
597 template <typename G>
598 bool getLi(G *m) const
599 {
600 if (!fOk)
601 return false;
602 const F *L = fL.data();
603 // copy L
604 for (unsigned i = 0; i < (fN * (fN + 1)) / 2; ++i)
605 m[i] = L[i];
606 // invert the off-diagonal part of what we just copied
607 G *base1 = &m[1];
608 for (unsigned i = 1; i < fN; base1 += ++i) {
609 for (unsigned j = 0; j < i; ++j) {
610 G tmp = F(0);
611 const G *base2 = &m[(i * (i - 1)) / 2];
612 for (unsigned k = i; k-- > j; base2 -= k)
613 tmp -= base1[k] * base2[j];
614 base1[j] = tmp * base1[i];
615 }
616 }
617 return true;
618 }
619};
620
621namespace CholeskyDecompHelpers {
622/// adapter for packed arrays (to SMatrix indexing conventions)
623template <typename G>
625private:
626 G *fArr; ///< pointer to first array element
627public:
628 /// constructor
630 /// read access to elements (make sure that j <= i)
631 const G operator()(unsigned i, unsigned j) const { return fArr[((i * (i + 1)) / 2) + j]; }
632 /// write access to elements (make sure that j <= i)
633 G &operator()(unsigned i, unsigned j) { return fArr[((i * (i + 1)) / 2) + j]; }
634};
635/// struct to do a Cholesky decomposition (general dimensionality)
636template <class F, class M>
638 /// method to do the decomposition
639 /** @returns if the decomposition was successful */
640 bool operator()(F *dst, const M &src, unsigned N) const
641 {
642 // perform Cholesky decomposition of matrix: M = L L^T
643 // only thing that can go wrong: trying to take square
644 // root of negative number or zero (matrix is
645 // ill-conditioned or singular in these cases)
646
647 // element L(i,j) is at array position (i * (i+1)) / 2 + j
648
649 // quirk: we may need to invert L later anyway, so we can
650 // invert elements on diagonal straight away (we only
651 // ever need their reciprocals!)
652
653 // cache starting address of rows of L for speed reasons
654 F *base1 = &dst[0];
655 for (unsigned i = 0; i < N; base1 += ++i) {
656 F tmpdiag = F(0.0); // for element on diagonal
657 // calculate off-diagonal elements
658 F *base2 = &dst[0];
659 for (unsigned j = 0; j < i; base2 += ++j) {
660 F tmp = src(i, j);
661 for (unsigned k = j; k--;)
662 tmp -= base1[k] * base2[k];
663 base1[j] = tmp *= base2[j];
664 // keep track of contribution to element on diagonal
665 tmpdiag += tmp * tmp;
666 }
667 // keep truncation error small
668 tmpdiag = src(i, i) - tmpdiag;
669 // check if positive definite
670 if (tmpdiag <= F(0.0))
671 return false;
672 else
673 base1[i] = std::sqrt(F(1.0) / tmpdiag);
674 }
675 return true;
676 }
677};
678
679/// struct to do a Cholesky decomposition
680template <class F, unsigned N, class M>
682 /// method to do the decomposition
683 /** @returns if the decomposition was successful */
684 bool operator()(F *dst, const M &src) const { return _decomposerGenDim<F, M>()(dst, src, N); }
685};
686
687/// struct to obtain the inverse from a Cholesky decomposition (general dimensionality)
688template <class F, class M>
690 /// method to do the inversion
691 void operator()(M &dst, unsigned N, F *wksp) const
692 {
693 // invert off-diagonal part of matrix
694 F *base1 = &wksp[1];
695 for (unsigned i = 1; i < N; base1 += ++i) {
696 for (unsigned j = 0; j < i; ++j) {
697 F tmp = F(0.0);
698 const F *base2 = &wksp[(i * (i - 1)) / 2];
699 for (unsigned k = i; k-- > j; base2 -= k)
700 tmp -= base1[k] * base2[j];
701 base1[j] = tmp * base1[i];
702 }
703 }
704
705 // Li = L^(-1) formed, now calculate M^(-1) = Li^T Li
706 for (unsigned i = N; i--;) {
707 for (unsigned j = i + 1; j--;) {
708 F tmp = F(0.0);
709 base1 = &wksp[(N * (N - 1)) / 2];
710 for (unsigned k = N; k-- > i; base1 -= k)
711 tmp += base1[i] * base1[j];
712 dst(i, j) = tmp;
713 }
714 }
715 }
716};
717
718/// struct to obtain the inverse from a Cholesky decomposition
719template <class F, unsigned N, class M>
720struct _inverter {
721 /// method to do the inversion
722 void operator()(M &dst, const F *src) const
723 {
724 // make working copy
725 F wksp[N * (N + 1) / 2];
726 std::copy(src, src + ((N * (N + 1)) / 2), wksp);
727 return _inverterGenDim<F, M>()(dst, N, wksp);
728 }
729};
730
731/// struct to solve a linear system using its Cholesky decomposition (generalised dimensionality)
732template <class F, class V>
734 /// method to solve the linear system
735 void operator()(V &rhs, const F *l, unsigned N) const
736 {
737 // solve Ly = rhs
738 for (unsigned k = 0; k < N; ++k) {
739 const unsigned base = (k * (k + 1)) / 2;
740 F sum = F(0.0);
741 for (unsigned i = k; i--;)
742 sum += rhs[i] * l[base + i];
743 // elements on diagonal are pre-inverted!
744 rhs[k] = (rhs[k] - sum) * l[base + k];
745 }
746 // solve L^Tx = y
747 for (unsigned k = N; k--;) {
748 F sum = F(0.0);
749 for (unsigned i = N; --i > k;)
750 sum += rhs[i] * l[(i * (i + 1)) / 2 + k];
751 // elements on diagonal are pre-inverted!
752 rhs[k] = (rhs[k] - sum) * l[(k * (k + 1)) / 2 + k];
753 }
754 }
755};
756
757/// struct to solve a linear system using its Cholesky decomposition
758template <class F, unsigned N, class V>
759struct _solver {
760 /// method to solve the linear system
761 void operator()(V &rhs, const F *l) const { _solverGenDim<F, V>()(rhs, l, N); }
762};
763
764/// struct to do a Cholesky decomposition (specialized, N = 6)
765template <class F, class M>
766struct _decomposer<F, 6, M> {
767 /// method to do the decomposition
768 bool operator()(F *dst, const M &src) const
769 {
770 if (src(0, 0) <= F(0.0))
771 return false;
772 dst[0] = std::sqrt(F(1.0) / src(0, 0));
773 dst[1] = src(1, 0) * dst[0];
774 dst[2] = src(1, 1) - dst[1] * dst[1];
775 if (dst[2] <= F(0.0))
776 return false;
777 else
778 dst[2] = std::sqrt(F(1.0) / dst[2]);
779 dst[3] = src(2, 0) * dst[0];
780 dst[4] = (src(2, 1) - dst[1] * dst[3]) * dst[2];
781 dst[5] = src(2, 2) - (dst[3] * dst[3] + dst[4] * dst[4]);
782 if (dst[5] <= F(0.0))
783 return false;
784 else
785 dst[5] = std::sqrt(F(1.0) / dst[5]);
786 dst[6] = src(3, 0) * dst[0];
787 dst[7] = (src(3, 1) - dst[1] * dst[6]) * dst[2];
788 dst[8] = (src(3, 2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
789 dst[9] = src(3, 3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
790 if (dst[9] <= F(0.0))
791 return false;
792 else
793 dst[9] = std::sqrt(F(1.0) / dst[9]);
794 dst[10] = src(4, 0) * dst[0];
795 dst[11] = (src(4, 1) - dst[1] * dst[10]) * dst[2];
796 dst[12] = (src(4, 2) - dst[3] * dst[10] - dst[4] * dst[11]) * dst[5];
797 dst[13] = (src(4, 3) - dst[6] * dst[10] - dst[7] * dst[11] - dst[8] * dst[12]) * dst[9];
798 dst[14] = src(4, 4) - (dst[10] * dst[10] + dst[11] * dst[11] + dst[12] * dst[12] + dst[13] * dst[13]);
799 if (dst[14] <= F(0.0))
800 return false;
801 else
802 dst[14] = std::sqrt(F(1.0) / dst[14]);
803 dst[15] = src(5, 0) * dst[0];
804 dst[16] = (src(5, 1) - dst[1] * dst[15]) * dst[2];
805 dst[17] = (src(5, 2) - dst[3] * dst[15] - dst[4] * dst[16]) * dst[5];
806 dst[18] = (src(5, 3) - dst[6] * dst[15] - dst[7] * dst[16] - dst[8] * dst[17]) * dst[9];
807 dst[19] = (src(5, 4) - dst[10] * dst[15] - dst[11] * dst[16] - dst[12] * dst[17] - dst[13] * dst[18]) * dst[14];
808 dst[20] = src(5, 5) -
809 (dst[15] * dst[15] + dst[16] * dst[16] + dst[17] * dst[17] + dst[18] * dst[18] + dst[19] * dst[19]);
810 if (dst[20] <= F(0.0))
811 return false;
812 else
813 dst[20] = std::sqrt(F(1.0) / dst[20]);
814 return true;
815 }
816};
817/// struct to do a Cholesky decomposition (specialized, N = 5)
818template <class F, class M>
819struct _decomposer<F, 5, M> {
820 /// method to do the decomposition
821 bool operator()(F *dst, const M &src) const
822 {
823 if (src(0, 0) <= F(0.0))
824 return false;
825 dst[0] = std::sqrt(F(1.0) / src(0, 0));
826 dst[1] = src(1, 0) * dst[0];
827 dst[2] = src(1, 1) - dst[1] * dst[1];
828 if (dst[2] <= F(0.0))
829 return false;
830 else
831 dst[2] = std::sqrt(F(1.0) / dst[2]);
832 dst[3] = src(2, 0) * dst[0];
833 dst[4] = (src(2, 1) - dst[1] * dst[3]) * dst[2];
834 dst[5] = src(2, 2) - (dst[3] * dst[3] + dst[4] * dst[4]);
835 if (dst[5] <= F(0.0))
836 return false;
837 else
838 dst[5] = std::sqrt(F(1.0) / dst[5]);
839 dst[6] = src(3, 0) * dst[0];
840 dst[7] = (src(3, 1) - dst[1] * dst[6]) * dst[2];
841 dst[8] = (src(3, 2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
842 dst[9] = src(3, 3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
843 if (dst[9] <= F(0.0))
844 return false;
845 else
846 dst[9] = std::sqrt(F(1.0) / dst[9]);
847 dst[10] = src(4, 0) * dst[0];
848 dst[11] = (src(4, 1) - dst[1] * dst[10]) * dst[2];
849 dst[12] = (src(4, 2) - dst[3] * dst[10] - dst[4] * dst[11]) * dst[5];
850 dst[13] = (src(4, 3) - dst[6] * dst[10] - dst[7] * dst[11] - dst[8] * dst[12]) * dst[9];
851 dst[14] = src(4, 4) - (dst[10] * dst[10] + dst[11] * dst[11] + dst[12] * dst[12] + dst[13] * dst[13]);
852 if (dst[14] <= F(0.0))
853 return false;
854 else
855 dst[14] = std::sqrt(F(1.0) / dst[14]);
856 return true;
857 }
858};
859/// struct to do a Cholesky decomposition (specialized, N = 4)
860template <class F, class M>
861struct _decomposer<F, 4, M> {
862 /// method to do the decomposition
863 bool operator()(F *dst, const M &src) const
864 {
865 if (src(0, 0) <= F(0.0))
866 return false;
867 dst[0] = std::sqrt(F(1.0) / src(0, 0));
868 dst[1] = src(1, 0) * dst[0];
869 dst[2] = src(1, 1) - dst[1] * dst[1];
870 if (dst[2] <= F(0.0))
871 return false;
872 else
873 dst[2] = std::sqrt(F(1.0) / dst[2]);
874 dst[3] = src(2, 0) * dst[0];
875 dst[4] = (src(2, 1) - dst[1] * dst[3]) * dst[2];
876 dst[5] = src(2, 2) - (dst[3] * dst[3] + dst[4] * dst[4]);
877 if (dst[5] <= F(0.0))
878 return false;
879 else
880 dst[5] = std::sqrt(F(1.0) / dst[5]);
881 dst[6] = src(3, 0) * dst[0];
882 dst[7] = (src(3, 1) - dst[1] * dst[6]) * dst[2];
883 dst[8] = (src(3, 2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
884 dst[9] = src(3, 3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
885 if (dst[9] <= F(0.0))
886 return false;
887 else
888 dst[9] = std::sqrt(F(1.0) / dst[9]);
889 return true;
890 }
891};
892/// struct to do a Cholesky decomposition (specialized, N = 3)
893template <class F, class M>
894struct _decomposer<F, 3, M> {
895 /// method to do the decomposition
896 bool operator()(F *dst, const M &src) const
897 {
898 if (src(0, 0) <= F(0.0))
899 return false;
900 dst[0] = std::sqrt(F(1.0) / src(0, 0));
901 dst[1] = src(1, 0) * dst[0];
902 dst[2] = src(1, 1) - dst[1] * dst[1];
903 if (dst[2] <= F(0.0))
904 return false;
905 else
906 dst[2] = std::sqrt(F(1.0) / dst[2]);
907 dst[3] = src(2, 0) * dst[0];
908 dst[4] = (src(2, 1) - dst[1] * dst[3]) * dst[2];
909 dst[5] = src(2, 2) - (dst[3] * dst[3] + dst[4] * dst[4]);
910 if (dst[5] <= F(0.0))
911 return false;
912 else
913 dst[5] = std::sqrt(F(1.0) / dst[5]);
914 return true;
915 }
916};
917/// struct to do a Cholesky decomposition (specialized, N = 2)
918template <class F, class M>
919struct _decomposer<F, 2, M> {
920 /// method to do the decomposition
921 bool operator()(F *dst, const M &src) const
922 {
923 if (src(0, 0) <= F(0.0))
924 return false;
925 dst[0] = std::sqrt(F(1.0) / src(0, 0));
926 dst[1] = src(1, 0) * dst[0];
927 dst[2] = src(1, 1) - dst[1] * dst[1];
928 if (dst[2] <= F(0.0))
929 return false;
930 else
931 dst[2] = std::sqrt(F(1.0) / dst[2]);
932 return true;
933 }
934};
935/// struct to do a Cholesky decomposition (specialized, N = 1)
936template <class F, class M>
937struct _decomposer<F, 1, M> {
938 /// method to do the decomposition
939 bool operator()(F *dst, const M &src) const
940 {
941 if (src(0, 0) <= F(0.0))
942 return false;
943 dst[0] = std::sqrt(F(1.0) / src(0, 0));
944 return true;
945 }
946};
947/// struct to do a Cholesky decomposition (specialized, N = 0)
948template <class F, class M>
949struct _decomposer<F, 0, M> {
950private:
952 bool operator()(F *dst, const M &src) const;
953};
954
955/// struct to obtain the inverse from a Cholesky decomposition (N = 6)
956template <class F, class M>
957struct _inverter<F, 6, M> {
958 /// method to do the inversion
959 inline void operator()(M &dst, const F *src) const
960 {
961 const F li21 = -src[1] * src[0] * src[2];
962 const F li32 = -src[4] * src[2] * src[5];
963 const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
964 const F li43 = -src[8] * src[9] * src[5];
965 const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
966 const F li41 =
967 (-src[1] * src[4] * src[8] * src[2] * src[5] + src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) *
968 src[0] * src[9];
969 const F li54 = -src[13] * src[14] * src[9];
970 const F li53 = (src[13] * src[8] * src[9] - src[12]) * src[5] * src[14];
971 const F li52 = (-src[4] * src[8] * src[13] * src[5] * src[9] + src[4] * src[12] * src[5] +
972 src[7] * src[13] * src[9] - src[11]) *
973 src[2] * src[14];
974 const F li51 =
975 (src[1] * src[4] * src[8] * src[13] * src[2] * src[5] * src[9] - src[13] * src[8] * src[3] * src[9] * src[5] -
976 src[12] * src[4] * src[1] * src[2] * src[5] - src[13] * src[7] * src[1] * src[9] * src[2] +
977 src[11] * src[1] * src[2] + src[12] * src[3] * src[5] + src[13] * src[6] * src[9] - src[10]) *
978 src[0] * src[14];
979 const F li65 = -src[19] * src[20] * src[14];
980 const F li64 = (src[19] * src[13] * src[14] - src[18]) * src[9] * src[20];
981 const F li63 = (-src[8] * src[13] * src[19] * src[9] * src[14] + src[8] * src[18] * src[9] +
982 src[12] * src[19] * src[14] - src[17]) *
983 src[5] * src[20];
984 const F li62 = (src[4] * src[8] * src[13] * src[19] * src[5] * src[9] * src[14] -
985 src[18] * src[8] * src[4] * src[9] * src[5] - src[19] * src[12] * src[4] * src[14] * src[5] -
986 src[19] * src[13] * src[7] * src[14] * src[9] + src[17] * src[4] * src[5] +
987 src[18] * src[7] * src[9] + src[19] * src[11] * src[14] - src[16]) *
988 src[2] * src[20];
989 const F li61 = (-src[19] * src[13] * src[8] * src[4] * src[1] * src[2] * src[5] * src[9] * src[14] +
990 src[18] * src[8] * src[4] * src[1] * src[2] * src[5] * src[9] +
991 src[19] * src[12] * src[4] * src[1] * src[2] * src[5] * src[14] +
992 src[19] * src[13] * src[7] * src[1] * src[2] * src[9] * src[14] +
993 src[19] * src[13] * src[8] * src[3] * src[5] * src[9] * src[14] -
994 src[17] * src[4] * src[1] * src[2] * src[5] - src[18] * src[7] * src[1] * src[2] * src[9] -
995 src[19] * src[11] * src[1] * src[2] * src[14] - src[18] * src[8] * src[3] * src[5] * src[9] -
996 src[19] * src[12] * src[3] * src[5] * src[14] - src[19] * src[13] * src[6] * src[9] * src[14] +
997 src[16] * src[1] * src[2] + src[17] * src[3] * src[5] + src[18] * src[6] * src[9] +
998 src[19] * src[10] * src[14] - src[15]) *
999 src[0] * src[20];
1000
1001 dst(0, 0) = li61 * li61 + li51 * li51 + li41 * li41 + li31 * li31 + li21 * li21 + src[0] * src[0];
1002 dst(1, 0) = li61 * li62 + li51 * li52 + li41 * li42 + li31 * li32 + li21 * src[2];
1003 dst(1, 1) = li62 * li62 + li52 * li52 + li42 * li42 + li32 * li32 + src[2] * src[2];
1004 dst(2, 0) = li61 * li63 + li51 * li53 + li41 * li43 + li31 * src[5];
1005 dst(2, 1) = li62 * li63 + li52 * li53 + li42 * li43 + li32 * src[5];
1006 dst(2, 2) = li63 * li63 + li53 * li53 + li43 * li43 + src[5] * src[5];
1007 dst(3, 0) = li61 * li64 + li51 * li54 + li41 * src[9];
1008 dst(3, 1) = li62 * li64 + li52 * li54 + li42 * src[9];
1009 dst(3, 2) = li63 * li64 + li53 * li54 + li43 * src[9];
1010 dst(3, 3) = li64 * li64 + li54 * li54 + src[9] * src[9];
1011 dst(4, 0) = li61 * li65 + li51 * src[14];
1012 dst(4, 1) = li62 * li65 + li52 * src[14];
1013 dst(4, 2) = li63 * li65 + li53 * src[14];
1014 dst(4, 3) = li64 * li65 + li54 * src[14];
1015 dst(4, 4) = li65 * li65 + src[14] * src[14];
1016 dst(5, 0) = li61 * src[20];
1017 dst(5, 1) = li62 * src[20];
1018 dst(5, 2) = li63 * src[20];
1019 dst(5, 3) = li64 * src[20];
1020 dst(5, 4) = li65 * src[20];
1021 dst(5, 5) = src[20] * src[20];
1022 }
1023};
1024/// struct to obtain the inverse from a Cholesky decomposition (N = 5)
1025template <class F, class M>
1026struct _inverter<F, 5, M> {
1027 /// method to do the inversion
1028 inline void operator()(M &dst, const F *src) const
1029 {
1030 const F li21 = -src[1] * src[0] * src[2];
1031 const F li32 = -src[4] * src[2] * src[5];
1032 const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
1033 const F li43 = -src[8] * src[9] * src[5];
1034 const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
1035 const F li41 =
1036 (-src[1] * src[4] * src[8] * src[2] * src[5] + src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) *
1037 src[0] * src[9];
1038 const F li54 = -src[13] * src[14] * src[9];
1039 const F li53 = (src[13] * src[8] * src[9] - src[12]) * src[5] * src[14];
1040 const F li52 = (-src[4] * src[8] * src[13] * src[5] * src[9] + src[4] * src[12] * src[5] +
1041 src[7] * src[13] * src[9] - src[11]) *
1042 src[2] * src[14];
1043 const F li51 =
1044 (src[1] * src[4] * src[8] * src[13] * src[2] * src[5] * src[9] - src[13] * src[8] * src[3] * src[9] * src[5] -
1045 src[12] * src[4] * src[1] * src[2] * src[5] - src[13] * src[7] * src[1] * src[9] * src[2] +
1046 src[11] * src[1] * src[2] + src[12] * src[3] * src[5] + src[13] * src[6] * src[9] - src[10]) *
1047 src[0] * src[14];
1048
1049 dst(0, 0) = li51 * li51 + li41 * li41 + li31 * li31 + li21 * li21 + src[0] * src[0];
1050 dst(1, 0) = li51 * li52 + li41 * li42 + li31 * li32 + li21 * src[2];
1051 dst(1, 1) = li52 * li52 + li42 * li42 + li32 * li32 + src[2] * src[2];
1052 dst(2, 0) = li51 * li53 + li41 * li43 + li31 * src[5];
1053 dst(2, 1) = li52 * li53 + li42 * li43 + li32 * src[5];
1054 dst(2, 2) = li53 * li53 + li43 * li43 + src[5] * src[5];
1055 dst(3, 0) = li51 * li54 + li41 * src[9];
1056 dst(3, 1) = li52 * li54 + li42 * src[9];
1057 dst(3, 2) = li53 * li54 + li43 * src[9];
1058 dst(3, 3) = li54 * li54 + src[9] * src[9];
1059 dst(4, 0) = li51 * src[14];
1060 dst(4, 1) = li52 * src[14];
1061 dst(4, 2) = li53 * src[14];
1062 dst(4, 3) = li54 * src[14];
1063 dst(4, 4) = src[14] * src[14];
1064 }
1065};
1066/// struct to obtain the inverse from a Cholesky decomposition (N = 4)
1067template <class F, class M>
1068struct _inverter<F, 4, M> {
1069 /// method to do the inversion
1070 inline void operator()(M &dst, const F *src) const
1071 {
1072 const F li21 = -src[1] * src[0] * src[2];
1073 const F li32 = -src[4] * src[2] * src[5];
1074 const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
1075 const F li43 = -src[8] * src[9] * src[5];
1076 const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
1077 const F li41 =
1078 (-src[1] * src[4] * src[8] * src[2] * src[5] + src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) *
1079 src[0] * src[9];
1080
1081 dst(0, 0) = li41 * li41 + li31 * li31 + li21 * li21 + src[0] * src[0];
1082 dst(1, 0) = li41 * li42 + li31 * li32 + li21 * src[2];
1083 dst(1, 1) = li42 * li42 + li32 * li32 + src[2] * src[2];
1084 dst(2, 0) = li41 * li43 + li31 * src[5];
1085 dst(2, 1) = li42 * li43 + li32 * src[5];
1086 dst(2, 2) = li43 * li43 + src[5] * src[5];
1087 dst(3, 0) = li41 * src[9];
1088 dst(3, 1) = li42 * src[9];
1089 dst(3, 2) = li43 * src[9];
1090 dst(3, 3) = src[9] * src[9];
1091 }
1092};
1093/// struct to obtain the inverse from a Cholesky decomposition (N = 3)
1094template <class F, class M>
1095struct _inverter<F, 3, M> {
1096 /// method to do the inversion
1097 inline void operator()(M &dst, const F *src) const
1098 {
1099 const F li21 = -src[1] * src[0] * src[2];
1100 const F li32 = -src[4] * src[2] * src[5];
1101 const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
1102
1103 dst(0, 0) = li31 * li31 + li21 * li21 + src[0] * src[0];
1104 dst(1, 0) = li31 * li32 + li21 * src[2];
1105 dst(1, 1) = li32 * li32 + src[2] * src[2];
1106 dst(2, 0) = li31 * src[5];
1107 dst(2, 1) = li32 * src[5];
1108 dst(2, 2) = src[5] * src[5];
1109 }
1110};
1111/// struct to obtain the inverse from a Cholesky decomposition (N = 2)
1112template <class F, class M>
1113struct _inverter<F, 2, M> {
1114 /// method to do the inversion
1115 inline void operator()(M &dst, const F *src) const
1116 {
1117 const F li21 = -src[1] * src[0] * src[2];
1118
1119 dst(0, 0) = li21 * li21 + src[0] * src[0];
1120 dst(1, 0) = li21 * src[2];
1121 dst(1, 1) = src[2] * src[2];
1122 }
1123};
1124/// struct to obtain the inverse from a Cholesky decomposition (N = 1)
1125template <class F, class M>
1126struct _inverter<F, 1, M> {
1127 /// method to do the inversion
1128 inline void operator()(M &dst, const F *src) const { dst(0, 0) = src[0] * src[0]; }
1129};
1130/// struct to obtain the inverse from a Cholesky decomposition (N = 0)
1131template <class F, class M>
1132struct _inverter<F, 0, M> {
1133private:
1135 void operator()(M &dst, const F *src) const;
1136};
1137
1138/// struct to solve a linear system using its Cholesky decomposition (N=6)
1139template <class F, class V>
1140struct _solver<F, 6, V> {
1141 /// method to solve the linear system
1142 void operator()(V &rhs, const F *l) const
1143 {
1144 // solve Ly = rhs
1145 const F y0 = rhs[0] * l[0];
1146 const F y1 = (rhs[1] - l[1] * y0) * l[2];
1147 const F y2 = (rhs[2] - (l[3] * y0 + l[4] * y1)) * l[5];
1148 const F y3 = (rhs[3] - (l[6] * y0 + l[7] * y1 + l[8] * y2)) * l[9];
1149 const F y4 = (rhs[4] - (l[10] * y0 + l[11] * y1 + l[12] * y2 + l[13] * y3)) * l[14];
1150 const F y5 = (rhs[5] - (l[15] * y0 + l[16] * y1 + l[17] * y2 + l[18] * y3 + l[19] * y4)) * l[20];
1151 // solve L^Tx = y, and put x into rhs
1152 rhs[5] = y5 * l[20];
1153 rhs[4] = (y4 - l[19] * rhs[5]) * l[14];
1154 rhs[3] = (y3 - (l[18] * rhs[5] + l[13] * rhs[4])) * l[9];
1155 rhs[2] = (y2 - (l[17] * rhs[5] + l[12] * rhs[4] + l[8] * rhs[3])) * l[5];
1156 rhs[1] = (y1 - (l[16] * rhs[5] + l[11] * rhs[4] + l[7] * rhs[3] + l[4] * rhs[2])) * l[2];
1157 rhs[0] = (y0 - (l[15] * rhs[5] + l[10] * rhs[4] + l[6] * rhs[3] + l[3] * rhs[2] + l[1] * rhs[1])) * l[0];
1158 }
1159};
1160/// struct to solve a linear system using its Cholesky decomposition (N=5)
1161template <class F, class V>
1162struct _solver<F, 5, V> {
1163 /// method to solve the linear system
1164 void operator()(V &rhs, const F *l) const
1165 {
1166 // solve Ly = rhs
1167 const F y0 = rhs[0] * l[0];
1168 const F y1 = (rhs[1] - l[1] * y0) * l[2];
1169 const F y2 = (rhs[2] - (l[3] * y0 + l[4] * y1)) * l[5];
1170 const F y3 = (rhs[3] - (l[6] * y0 + l[7] * y1 + l[8] * y2)) * l[9];
1171 const F y4 = (rhs[4] - (l[10] * y0 + l[11] * y1 + l[12] * y2 + l[13] * y3)) * l[14];
1172 // solve L^Tx = y, and put x into rhs
1173 rhs[4] = (y4)*l[14];
1174 rhs[3] = (y3 - (l[13] * rhs[4])) * l[9];
1175 rhs[2] = (y2 - (l[12] * rhs[4] + l[8] * rhs[3])) * l[5];
1176 rhs[1] = (y1 - (l[11] * rhs[4] + l[7] * rhs[3] + l[4] * rhs[2])) * l[2];
1177 rhs[0] = (y0 - (l[10] * rhs[4] + l[6] * rhs[3] + l[3] * rhs[2] + l[1] * rhs[1])) * l[0];
1178 }
1179};
1180/// struct to solve a linear system using its Cholesky decomposition (N=4)
1181template <class F, class V>
1182struct _solver<F, 4, V> {
1183 /// method to solve the linear system
1184 void operator()(V &rhs, const F *l) const
1185 {
1186 // solve Ly = rhs
1187 const F y0 = rhs[0] * l[0];
1188 const F y1 = (rhs[1] - l[1] * y0) * l[2];
1189 const F y2 = (rhs[2] - (l[3] * y0 + l[4] * y1)) * l[5];
1190 const F y3 = (rhs[3] - (l[6] * y0 + l[7] * y1 + l[8] * y2)) * l[9];
1191 // solve L^Tx = y, and put x into rhs
1192 rhs[3] = (y3)*l[9];
1193 rhs[2] = (y2 - (l[8] * rhs[3])) * l[5];
1194 rhs[1] = (y1 - (l[7] * rhs[3] + l[4] * rhs[2])) * l[2];
1195 rhs[0] = (y0 - (l[6] * rhs[3] + l[3] * rhs[2] + l[1] * rhs[1])) * l[0];
1196 }
1197};
1198/// struct to solve a linear system using its Cholesky decomposition (N=3)
1199template <class F, class V>
1200struct _solver<F, 3, V> {
1201 /// method to solve the linear system
1202 void operator()(V &rhs, const F *l) const
1203 {
1204 // solve Ly = rhs
1205 const F y0 = rhs[0] * l[0];
1206 const F y1 = (rhs[1] - l[1] * y0) * l[2];
1207 const F y2 = (rhs[2] - (l[3] * y0 + l[4] * y1)) * l[5];
1208 // solve L^Tx = y, and put x into rhs
1209 rhs[2] = (y2)*l[5];
1210 rhs[1] = (y1 - (l[4] * rhs[2])) * l[2];
1211 rhs[0] = (y0 - (l[3] * rhs[2] + l[1] * rhs[1])) * l[0];
1212 }
1213};
1214/// struct to solve a linear system using its Cholesky decomposition (N=2)
1215template <class F, class V>
1216struct _solver<F, 2, V> {
1217 /// method to solve the linear system
1218 void operator()(V &rhs, const F *l) const
1219 {
1220 // solve Ly = rhs
1221 const F y0 = rhs[0] * l[0];
1222 const F y1 = (rhs[1] - l[1] * y0) * l[2];
1223 // solve L^Tx = y, and put x into rhs
1224 rhs[1] = (y1)*l[2];
1225 rhs[0] = (y0 - (l[1] * rhs[1])) * l[0];
1226 }
1227};
1228/// struct to solve a linear system using its Cholesky decomposition (N=1)
1229template <class F, class V>
1230struct _solver<F, 1, V> {
1231 /// method to solve the linear system
1232 void operator()(V &rhs, const F *l) const
1233 {
1234 // solve LL^T x = rhs, put y into rhs
1235 rhs[0] *= l[0] * l[0];
1236 }
1237};
1238/// struct to solve a linear system using its Cholesky decomposition (N=0)
1239template <class F, class V>
1240struct _solver<F, 0, V> {
1241private:
1243 void operator()(V &rhs, const F *l) const;
1244};
1245} // namespace CholeskyDecompHelpers
1246
1247} // namespace Math
1248
1249} // namespace ROOT
1250
1251#endif // ROOT_Math_CHOLESKYDECOMP
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char y1
class to compute the Cholesky decomposition of a matrix
bool fOk
flag indicating a successful decomposition
CholeskyDecompGenDim(unsigned N, G *m, std::vector< F > wksp={})
perform a Cholesky decomposition
bool getL(G *m) const
obtain the decomposed matrix L
bool getL(M &m) const
obtain the decomposed matrix L
std::vector< F > fL
lower triangular matrix L
bool Invert(G *m) const
place the inverse into m
std::vector< F > releaseWorkspace()
release the workspace of the decomposition for reuse
bool Invert(M &m) const
place the inverse into m
bool Solve(V &rhs) const
solves a linear system for the given right hand side
bool getLi(M &m) const
obtain the inverse of the decomposed matrix L
CholeskyDecompGenDim(unsigned N, const M &m, std::vector< F > wksp={})
perform a Cholesky decomposition
unsigned fN
dimensionality dimensionality of the problem
bool getLi(G *m) const
obtain the inverse of the decomposed matrix L
bool ok() const
returns true if decomposition was successful
adapter for packed arrays (to SMatrix indexing conventions)
G & operator()(unsigned i, unsigned j)
write access to elements (make sure that j <= i)
const G operator()(unsigned i, unsigned j) const
read access to elements (make sure that j <= i)
class to compute the Cholesky decomposition of a matrix
bool fOk
flag indicating a successful decomposition
bool ok() const
returns true if decomposition was successful
bool getL(G *m) const
obtain the decomposed matrix L
bool Invert(G *m) const
place the inverse into m
CholeskyDecomp(const M &m)
perform a Cholesky decomposition
bool getLi(G *m) const
obtain the inverse of the decomposed matrix L
bool getL(M &m) const
obtain the decomposed matrix L
bool Solve(V &rhs) const
solves a linear system for the given right hand side
F fL[N *(N+1)/2]
lower triangular matrix L
CholeskyDecomp(G *m)
perform a Cholesky decomposition
bool getLi(M &m) const
obtain the inverse of the decomposed matrix L
bool Invert(M &m) const
place the inverse into m
#define F(x, y, z)
#define G(x, y, z)
Namespace for new Math classes and functions.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
struct to do a Cholesky decomposition (general dimensionality)
bool operator()(F *dst, const M &src, unsigned N) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
struct to do a Cholesky decomposition
bool operator()(F *dst, const M &src) const
method to do the decomposition
struct to obtain the inverse from a Cholesky decomposition (general dimensionality)
void operator()(M &dst, unsigned N, F *wksp) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
void operator()(M &dst, const F *src) const
method to do the inversion
struct to obtain the inverse from a Cholesky decomposition
void operator()(M &dst, const F *src) const
method to do the inversion
struct to solve a linear system using its Cholesky decomposition (generalised dimensionality)
void operator()(V &rhs, const F *l, unsigned N) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
void operator()(V &rhs, const F *l) const
method to solve the linear system
struct to solve a linear system using its Cholesky decomposition
void operator()(V &rhs, const F *l) const
method to solve the linear system
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345