{ "cells": [ { "cell_type": "markdown", "id": "93b04468", "metadata": {}, "source": [ "# invertMatrix\n", "This macro shows several ways to invert a matrix . Each method\n", "is a trade-off between accuracy of the inversion and speed.\n", "Which method to chose depends on \"how well-behaved\" the matrix is.\n", "This is best checked through a call to Condition(), available in each\n", "decomposition class. A second possibility (less preferred) would be to\n", "check the determinant\n", "\n", " #### USAGE\n", "\n", "This macro can be executed with Cling or ACLIC\n", " - via the interpretor, do\n", "```cpp\n", " root > .x invertMatrix.C\n", "```\n", " - via ACLIC\n", "```cpp\n", " root > gSystem->Load(\"libMatrix\");\n", " root > .x invertMatrix.C+\n", "```\n", "\n", "\n", "\n", "\n", "**Author:** Eddy Offermann \n", "This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, May 19, 2026 at 08:26 PM." ] }, { "cell_type": "markdown", "id": "75c53845", "metadata": {}, "source": [ " Arguments are defined. " ] }, { "cell_type": "code", "execution_count": null, "id": "5ec4cfc3", "metadata": { "collapsed": false }, "outputs": [], "source": [ "Int_t msize=6;" ] }, { "cell_type": "code", "execution_count": null, "id": "9406346d", "metadata": { "collapsed": false }, "outputs": [], "source": [ "if (msize < 2 || msize > 10) {\n", " std::cout << \"2 <= msize <= 10\" < 6 x 6 but for smaller sizes, the\n", "inversion is performed according to Cramer's rule by explicitly calculating\n", "all Jacobi's sub-determinants . For instance for a 6 x 6 matrix this means:\n", "\\# of 5 x 5 determinant : 36\n", "\\# of 4 x 4 determinant : 75\n", "\\# of 3 x 3 determinant : 80\n", "\\# of 2 x 2 determinant : 45 (see TMatrixD/FCramerInv.cxx)\n", "\n", "The only \"quality\" control in this process is to check whether the 6 x 6\n", "determinant is unequal 0 . But speed gains are significant compared to Invert() ,\n", "up to an order of magnitude for sizes <= 4 x 4\n", "\n", "The inversion is done \"in place\", so the original matrix will be overwritten\n", "If a pointer to a Double_t is supplied the determinant is calculated" ] }, { "cell_type": "code", "execution_count": null, "id": "6d094698", "metadata": { "collapsed": false }, "outputs": [], "source": [ "std::cout << \"1. Use .InvertFast(&det)\" < 6)\n", " std::cout << \" for (\"< 1\n", "- The last step is a standard forward/backward substitution .\n", "\n", "It is important to realize that both InvertFast() and Invert() are \"one-shot\" deals , speed\n", "comes at a price . If something goes wrong because the matrix is (near) singular, you have\n", "overwritten your original matrix and no factorization is available anymore to get more\n", "information like condition number or change the tolerance number .\n", "\n", "All other calls in the matrix classes involving inversion like the ones with the \"smart\"\n", "constructors (kInverted,kInvMult...) use this inversion method ." ] }, { "cell_type": "code", "execution_count": null, "id": "d5d0d6e7", "metadata": { "collapsed": false }, "outputs": [], "source": [ "std::cout << \"2. Use .Invert(&det)\" << std::endl;\n", "\n", "Double_t det2;\n", "TMatrixD H2 = H_square;\n", "H2.Invert(&det2);\n", "\n", "TMatrixD U2(H2,TMatrixD::kMult,H_square);\n", "TMatrixDDiag diag2(U2); diag2 = 0.0;\n", "const Double_t U2_max_offdiag = (U2.Abs()).Max();\n", "std::cout << \" Maximum off-diagonal = \" << U2_max_offdiag << std::endl;\n", "std::cout << \" Determinant = \" << det2 << std::endl;" ] }, { "cell_type": "markdown", "id": "56a4962c", "metadata": {}, "source": [ "### 3. Inversion through LU decomposition\n", "The (default) algorithms used are similar to 2. (Not identical because in 2, the whole\n", "calculation is done \"in-place\". Here the original matrix is copied (so more memory\n", "management => slower) and several operations can be performed without having to repeat\n", "the decomposition step .\n", "Inverting a matrix is nothing else than solving a set of equations where the rhs is given\n", "by the unit matrix, so the steps to take are identical to those solving a linear equation :" ] }, { "cell_type": "code", "execution_count": null, "id": "3367e472", "metadata": { "collapsed": false }, "outputs": [], "source": [ "std::cout << \"3. Use TDecompLU\" << std::endl;\n", "\n", "TMatrixD H3 = H_square;\n", "TDecompLU lu(H_square);" ] }, { "cell_type": "markdown", "id": "eeb253a0", "metadata": {}, "source": [ "Any operation that requires a decomposition will trigger it . The class keeps\n", "an internal state so that following operations will not perform the decomposition again\n", "unless the matrix is changed through SetMatrix(..)\n", "One might want to proceed more cautiously by invoking first Decompose() and check its\n", "return value before proceeding...." ] }, { "cell_type": "code", "execution_count": null, "id": "7a16adf1", "metadata": { "collapsed": false }, "outputs": [], "source": [ "lu.Invert(H3);\n", "Double_t d1_lu; Double_t d2_lu;\n", "lu.Det(d1_lu,d2_lu);\n", "Double_t det3 = d1_lu*TMath::Power(2.,d2_lu);\n", "\n", "TMatrixD U3(H3,TMatrixD::kMult,H_square);\n", "TMatrixDDiag diag3(U3); diag3 = 0.0;\n", "const Double_t U3_max_offdiag = (U3.Abs()).Max();\n", "std::cout << \" Maximum off-diagonal = \" << U3_max_offdiag << std::endl;\n", "std::cout << \" Determinant = \" << det3 << std::endl;" ] }, { "cell_type": "markdown", "id": "28e84eba", "metadata": {}, "source": [ "### 4. Inversion through SVD decomposition\n", "For SVD and QRH, the (n x m) matrix does only have to fulfill n >=m . In case n > m\n", "a pseudo-inverse is calculated" ] }, { "cell_type": "code", "execution_count": null, "id": "abd1d4a9", "metadata": { "collapsed": false }, "outputs": [], "source": [ "std::cout << \"4. Use TDecompSVD on non-square matrix\" << std::endl;\n", "\n", "TMatrixD H_nsquare = THilbertMatrixD(msize,msize-1);\n", "\n", "TDecompSVD svd(H_nsquare);\n", "\n", "TMatrixD H4 = svd.Invert();\n", "Double_t d1_svd; Double_t d2_svd;\n", "svd.Det(d1_svd,d2_svd);\n", "Double_t det4 = d1_svd*TMath::Power(2.,d2_svd);\n", "\n", "TMatrixD U4(H4,TMatrixD::kMult,H_nsquare);\n", "TMatrixDDiag diag4(U4); diag4 = 0.0;\n", "const Double_t U4_max_offdiag = (U4.Abs()).Max();\n", "std::cout << \" Maximum off-diagonal = \" << U4_max_offdiag << std::endl;\n", "std::cout << \" Determinant = \" << det4 << std::endl;" ] } ], "metadata": { "kernelspec": { "display_name": "ROOT C++", "language": "c++", "name": "root" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".C", "mimetype": " text/x-c++src", "name": "c++" } }, "nbformat": 4, "nbformat_minor": 5 }