Loading [MathJax]/extensions/tex2jax.js
Logo ROOT  
Reference Guide
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
invertMatrix.C File Reference

Detailed Description

View in nbviewer Open in SWAN This macro shows several ways to invert a matrix .

Each method is a trade-off between accuracy of the inversion and speed. Which method to chose depends on "how well-behaved" the matrix is. This is best checked through a call to Condition(), available in each decomposition class. A second possibility (less preferred) would be to check the determinant

USAGE

This macro can be executed with Cling or ACLIC

  • via the interpretor, do
    root > .x invertMatrix.C
  • via ACLIC
    root > gSystem->Load("libMatrix");
    root > .x invertMatrix.C+
    R__EXTERN TSystem * gSystem
    Definition: TSystem.h:556
    virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
    Load a shared library.
    Definition: TSystem.cxx:1850
--------------------------------------------------------
Inversion results for a (6,6) matrix
For each inversion procedure we check the maximum size
of the off-diagonal elements of Inv(A) * A
--------------------------------------------------------
1. Use .InvertFast(&det)
Maximum off-diagonal = 8.31175e-05
Determinant = 5.3673e-18
2. Use .Invert(&det)
Maximum off-diagonal = 1.74623e-10
Determinant = 5.3673e-18
3. Use TDecompLU
Maximum off-diagonal = 1.74623e-10
Determinant = 5.3673e-18
4. Use TDecompSVD on non-square matrix
Maximum off-diagonal = 5.45697e-12
Determinant = 1.34646e-11
#include <iostream>
#include "TMath.h"
#include "TMatrixD.h"
#include "TMatrixDLazy.h"
#include "TVectorD.h"
#include "TDecompLU.h"
#include "TDecompSVD.h"
void invertMatrix(Int_t msize=6)
{
if (msize < 2 || msize > 10) {
std::cout << "2 <= msize <= 10" <<std::endl;
return;
}
std::cout << "--------------------------------------------------------" <<std::endl;
std::cout << "Inversion results for a ("<<msize<<","<<msize<<") matrix" <<std::endl;
std::cout << "For each inversion procedure we check the maximum size " <<std::endl;
std::cout << "of the off-diagonal elements of Inv(A) * A " <<std::endl;
std::cout << "--------------------------------------------------------" <<std::endl;
TMatrixD H_square = THilbertMatrixD(msize,msize);
// ### 1. InvertFast(Double_t *det=0)
// It is identical to Invert() for sizes > 6 x 6 but for smaller sizes, the
// inversion is performed according to Cramer's rule by explicitly calculating
// all Jacobi's sub-determinants . For instance for a 6 x 6 matrix this means:
// \# of 5 x 5 determinant : 36
// \# of 4 x 4 determinant : 75
// \# of 3 x 3 determinant : 80
// \# of 2 x 2 determinant : 45 (see TMatrixD/FCramerInv.cxx)
//
// The only "quality" control in this process is to check whether the 6 x 6
// determinant is unequal 0 . But speed gains are significant compared to Invert() ,
// up to an order of magnitude for sizes <= 4 x 4
//
// The inversion is done "in place", so the original matrix will be overwritten
// If a pointer to a Double_t is supplied the determinant is calculated
//
std::cout << "1. Use .InvertFast(&det)" <<std::endl;
if (msize > 6)
std::cout << " for ("<<msize<<","<<msize<<") this is identical to .Invert(&det)" <<std::endl;
Double_t det1;
TMatrixD H1 = H_square;
H1.InvertFast(&det1);
// Get the maximum off-diagonal matrix value . One way to do this is to set the
// diagonal to zero .
TMatrixD U1(H1,TMatrixD::kMult,H_square);
TMatrixDDiag diag1(U1); diag1 = 0.0;
const Double_t U1_max_offdiag = (U1.Abs()).Max();
std::cout << " Maximum off-diagonal = " << U1_max_offdiag << std::endl;
std::cout << " Determinant = " << det1 << std::endl;
// ### 2. Invert(Double_t *det=0)
// Again the inversion is performed in place .
// It consists out of a sequence of calls to the decomposition classes . For instance
// for the general dense matrix TMatrixD the LU decomposition is invoked:
// - The matrix is decomposed using a scheme according to Crout which involves
// "implicit partial pivoting", see for instance Num. Recip. (we have also available
// a decomposition scheme that does not the scaling and is therefore even slightly
// faster but less stable)
// With each decomposition, a tolerance has to be specified . If this tolerance
// requirement is not met, the matrix is regarded as being singular. The value
// passed to this decomposition, is the data member fTol of the matrix . Its
// default value is DBL_EPSILON, which is defined as the smallest number so that
// 1+DBL_EPSILON > 1
// - The last step is a standard forward/backward substitution .
//
// It is important to realize that both InvertFast() and Invert() are "one-shot" deals , speed
// comes at a price . If something goes wrong because the matrix is (near) singular, you have
// overwritten your original matrix and no factorization is available anymore to get more
// information like condition number or change the tolerance number .
//
// All other calls in the matrix classes involving inversion like the ones with the "smart"
// constructors (kInverted,kInvMult...) use this inversion method .
//
std::cout << "2. Use .Invert(&det)" << std::endl;
Double_t det2;
TMatrixD H2 = H_square;
H2.Invert(&det2);
TMatrixD U2(H2,TMatrixD::kMult,H_square);
TMatrixDDiag diag2(U2); diag2 = 0.0;
const Double_t U2_max_offdiag = (U2.Abs()).Max();
std::cout << " Maximum off-diagonal = " << U2_max_offdiag << std::endl;
std::cout << " Determinant = " << det2 << std::endl;
// ### 3. Inversion through LU decomposition
// The (default) algorithms used are similar to 2. (Not identical because in 2, the whole
// calculation is done "in-place". Here the original matrix is copied (so more memory
// management => slower) and several operations can be performed without having to repeat
// the decomposition step .
// Inverting a matrix is nothing else than solving a set of equations where the rhs is given
// by the unit matrix, so the steps to take are identical to those solving a linear equation :
//
std::cout << "3. Use TDecompLU" << std::endl;
TMatrixD H3 = H_square;
TDecompLU lu(H_square);
// Any operation that requires a decomposition will trigger it . The class keeps
// an internal state so that following operations will not perform the decomposition again
// unless the matrix is changed through SetMatrix(..)
// One might want to proceed more cautiously by invoking first Decompose() and check its
// return value before proceeding....
lu.Invert(H3);
Double_t d1_lu; Double_t d2_lu;
lu.Det(d1_lu,d2_lu);
Double_t det3 = d1_lu*TMath::Power(2.,d2_lu);
TMatrixD U3(H3,TMatrixD::kMult,H_square);
TMatrixDDiag diag3(U3); diag3 = 0.0;
const Double_t U3_max_offdiag = (U3.Abs()).Max();
std::cout << " Maximum off-diagonal = " << U3_max_offdiag << std::endl;
std::cout << " Determinant = " << det3 << std::endl;
// ### 4. Inversion through SVD decomposition
// For SVD and QRH, the (n x m) matrix does only have to fulfill n >=m . In case n > m
// a pseudo-inverse is calculated
std::cout << "4. Use TDecompSVD on non-square matrix" << std::endl;
TMatrixD H_nsquare = THilbertMatrixD(msize,msize-1);
TDecompSVD svd(H_nsquare);
TMatrixD H4 = svd.Invert();
Double_t d1_svd; Double_t d2_svd;
svd.Det(d1_svd,d2_svd);
Double_t det4 = d1_svd*TMath::Power(2.,d2_svd);
TMatrixD U4(H4,TMatrixD::kMult,H_nsquare);
TMatrixDDiag diag4(U4); diag4 = 0.0;
const Double_t U4_max_offdiag = (U4.Abs()).Max();
std::cout << " Maximum off-diagonal = " << U4_max_offdiag << std::endl;
std::cout << " Determinant = " << det4 << std::endl;
}
int Int_t
Definition: RtypesCore.h:43
double Double_t
Definition: RtypesCore.h:57
THilbertMatrixT< Double_t > THilbertMatrixD
Definition: TMatrixDLazy.h:35
LU Decomposition class.
Definition: TDecompLU.h:24
Single Value Decomposition class.
Definition: TDecompSVD.h:24
TMatrixT< Element > & Invert(Double_t *det=0)
Invert the matrix and calculate its determinant.
Definition: TMatrixT.cxx:1399
TMatrixT< Element > & InvertFast(Double_t *det=0)
Invert the matrix and calculate its determinant, however upto (6x6) a fast Cramer inversion is used .
Definition: TMatrixT.cxx:1413
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:725
Author
Eddy Offermann

Definition in file invertMatrix.C.