#include <SymMatrixInverter.h>
Public Types | |
typedef T::value_type | F |
Public Member Functions | |
bool | operator() (T &m, int N) const |
Definition at line 21 of file SymMatrixInverter.h.
typedef T::value_type Gaudi::Math::SymMatrixInverter::inverterForAllN< T >::F |
Definition at line 23 of file SymMatrixInverter.h.
bool Gaudi::Math::SymMatrixInverter::inverterForAllN< T >::operator() | ( | T & | m, | |
int | N | |||
) | const [inline] |
Definition at line 24 of file SymMatrixInverter.h.
00025 { 00026 // perform variant cholesky decomposition of matrix: M = L O L^T 00027 // L is lower triangular matrix with positive eigenvalues, thus same 00028 // use as in proper cholesky decomposition 00029 // O is diagonal, elements are either +1 or -1, to account for potential 00030 // negative eigenvalues of M (name is o because it contains "ones") 00031 // only thing that can go wrong: trying to divide by zero on diagonale 00032 // (matrix is singular in this case) 00033 00034 // we only need N * (N + 1) / 2 elements to store L 00035 // element L(i,j) is at array position (i * (i + 1)) / 2 + j 00036 F l[(N * (N + 1)) / 2]; 00037 // sign on diagonale 00038 F o[N]; 00039 00040 // quirk: we need to invert L later anyway, so we can invert elements 00041 // on diagonale straight away (we only ever need their reciprocals!) 00042 00043 // cache starting address of rows of L for speed reasons 00044 F *base1 = &l[0]; 00045 for (int i = 0; i < N; base1 += ++i) { 00046 F tmpdiag = F(0); // for element on diagonale 00047 // calculate off-diagonal elements 00048 F *base2 = &l[0]; 00049 for (int j = 0; j < i; base2 += ++j) { 00050 F tmp = m(i, j); 00051 for (int k = j; k--; ) 00052 tmp -= base1[k] * base2[k] * o[k]; 00053 base1[j] = tmp *= base2[j] * o[j]; 00054 // keep track of contribution to element on diagonale 00055 tmpdiag -= tmp * tmp * o[j]; 00056 } 00057 // keep truncation error small 00058 tmpdiag = m(i, i) + tmpdiag; 00059 // save sign to have L positive definite 00060 if (tmpdiag < F(0)) { 00061 tmpdiag = -tmpdiag; 00062 o[i] = F(-1); 00063 } else { 00064 // tmpdiag has right sign 00065 o[i] = F(1); 00066 } 00067 if (tmpdiag == F(0)) return false; 00068 else base1[i] = std::sqrt(F(1) / tmpdiag); 00069 } 00070 00071 // ok, next step: invert off-diagonal part of matrix L 00072 base1 = &l[1]; 00073 for (int i = 1; i < N; base1 += ++i) { 00074 for (int j = 0; j < i; ++j) { 00075 F tmp = F(0); 00076 F *base2 = &l[(i * (i - 1)) / 2]; 00077 for (int k = i; k-- > j; base2 -= k) 00078 tmp -= base1[k] * base2[j]; 00079 base1[j] = tmp * base1[i]; 00080 } 00081 } 00082 00083 // Li = L^(-1) formed, now calculate M^(-1) = Li^T O Li 00084 for (int i = N; i--; ) { 00085 for (int j = i + 1; j--; ) { 00086 F tmp = F(0); 00087 base1 = &l[(N * (N - 1)) / 2]; 00088 for (int k = N; k-- > i; base1 -= k) 00089 tmp += base1[i] * base1[j] * o[k]; 00090 m(i,j) = tmp; 00091 } 00092 } 00093 00094 return true; 00095 }