Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:20:02

0001 
0002 /***********************************************************************
0003 * Copyright 1998-2020 CERN for the benefit of the EvtGen authors       *
0004 *                                                                      *
0005 * This file is part of EvtGen.                                         *
0006 *                                                                      *
0007 * EvtGen is free software: you can redistribute it and/or modify       *
0008 * it under the terms of the GNU General Public License as published by *
0009 * the Free Software Foundation, either version 3 of the License, or    *
0010 * (at your option) any later version.                                  *
0011 *                                                                      *
0012 * EvtGen is distributed in the hope that it will be useful,            *
0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
0015 * GNU General Public License for more details.                         *
0016 *                                                                      *
0017 * You should have received a copy of the GNU General Public License    *
0018 * along with EvtGen.  If not, see <https://www.gnu.org/licenses/>.     *
0019 ***********************************************************************/
0020 
0021 #ifndef __EVT_MATRIX_HH__
0022 #define __EVT_MATRIX_HH__
0023 
0024 #include <cmath>
0025 #include <sstream>
0026 #include <vector>
0027 
0028 template <class T>
0029 class EvtMatrix {
0030   private:
0031     T** _mat;
0032     int _range;
0033 
0034   public:
0035     EvtMatrix() : _range( 0 ){};
0036     ~EvtMatrix();
0037     inline void setRange( int range );
0038 
0039     T& operator()( int row, int col ) { return _mat[row][col]; }
0040     T* operator[]( int row ) { return _mat[row]; }
0041     T det();
0042     EvtMatrix* min( int row, int col );
0043     EvtMatrix* inverse();
0044     std::string dump();
0045 
0046     template <class M>
0047     friend EvtMatrix<M>* operator*( const EvtMatrix<M>& left,
0048                                     const EvtMatrix<M>& right );
0049 };
0050 
0051 template <class T>
0052 inline void EvtMatrix<T>::setRange( int range )
0053 {
0054     // If the range is changed, delete any previous matrix stored
0055     //    and allocate elements with the newly specified range.
0056     if ( _range != range ) {
0057         if ( _range ) {
0058             for ( int row = 0; row < _range; row++ )
0059                 delete[] _mat[row];
0060             delete[] _mat;
0061         }
0062 
0063         _mat = new T*[range];
0064         for ( int row = 0; row < range; row++ )
0065             _mat[row] = new T[range];
0066 
0067         // Set the new range.
0068         _range = range;
0069     }
0070 
0071     // Since user is willing to change the range, reset the matrix elements.
0072     for ( int row = 0; row < _range; row++ )
0073         for ( int col = 0; col < _range; col++ )
0074             _mat[row][col] = 0.;
0075 }
0076 
0077 template <class T>
0078 EvtMatrix<T>::~EvtMatrix()
0079 {
0080     for ( int row = 0; row < _range; row++ )
0081         delete[] _mat[row];
0082     delete[] _mat;
0083 }
0084 
0085 template <class T>
0086 std::string EvtMatrix<T>::dump()
0087 {
0088     std::ostringstream str;
0089 
0090     for ( int row = 0; row < _range; row++ ) {
0091         str << "|";
0092         for ( int col = 0; col < _range; col++ )
0093             str << "\t" << _mat[row][col];
0094         str << "\t|" << std::endl;
0095     }
0096 
0097     return str.str();
0098 }
0099 
0100 template <class T>
0101 T EvtMatrix<T>::det()
0102 {
0103     if ( _range == 1 )
0104         return _mat[0][0];
0105 
0106     // There's no need to define the range 2 determinant manually, but it may
0107     //    speed up the calculation.
0108     if ( _range == 2 )
0109         return _mat[0][0] * _mat[1][1] - _mat[0][1] * _mat[1][0];
0110 
0111     T sum = 0.;
0112 
0113     for ( int col = 0; col < _range; col++ ) {
0114         EvtMatrix<T>* minor = min( 0, col );
0115         sum += std::pow( -1., col ) * _mat[0][col] * minor->det();
0116         delete minor;
0117     }
0118 
0119     return sum;
0120 }
0121 
0122 // Returns the minor at (i, j).
0123 template <class T>
0124 EvtMatrix<T>* EvtMatrix<T>::min( int row, int col )
0125 {
0126     EvtMatrix<T>* minor = new EvtMatrix<T>();
0127     minor->setRange( _range - 1 );
0128 
0129     int minIndex = 0;
0130 
0131     for ( int r = 0; r < _range; r++ )
0132         for ( int c = 0; c < _range; c++ )
0133             if ( ( r != row ) && ( c != col ) ) {
0134                 ( *minor )( minIndex / ( _range - 1 ),
0135                             minIndex % ( _range - 1 ) ) = _mat[r][c];
0136                 minIndex++;
0137             }
0138 
0139     return minor;
0140 }
0141 
0142 template <class T>
0143 EvtMatrix<T>* EvtMatrix<T>::inverse()
0144 {
0145     EvtMatrix<T>* inv = new EvtMatrix<T>();
0146     inv->setRange( _range );
0147 
0148     if ( det() == 0 ) {
0149         std::cerr << "This matrix has a null determinant and cannot be inverted. Returning zero matrix."
0150                   << std::endl;
0151         for ( int row = 0; row < _range; row++ )
0152             for ( int col = 0; col < _range; col++ )
0153                 ( *inv )( row, col ) = 0.;
0154         return inv;
0155     }
0156 
0157     T determinant = det();
0158 
0159     for ( int row = 0; row < _range; row++ )
0160         for ( int col = 0; col < _range; col++ ) {
0161             EvtMatrix<T>* minor = min( row, col );
0162             inv->_mat[col][row] = std::pow( -1., row + col ) * minor->det() /
0163                                   determinant;
0164             delete minor;
0165         }
0166 
0167     return inv;
0168 }
0169 
0170 template <class T>
0171 EvtMatrix<T>* operator*( const EvtMatrix<T>& left, const EvtMatrix<T>& right )
0172 {
0173     // Chech that the matrices have the correct range.
0174     if ( left._range != right._range ) {
0175         std::cerr << "These matrices cannot be multiplied." << std::endl;
0176         return new EvtMatrix<T>();
0177     }
0178 
0179     EvtMatrix<T>* mat = new EvtMatrix<T>();
0180     mat->setRange( left._range );
0181 
0182     // Initialize the elements of the matrix.
0183     for ( int row = 0; row < left._range; row++ )
0184         for ( int col = 0; col < right._range; col++ )
0185             ( *mat )[row][col] = 0;
0186 
0187     for ( int row = 0; row < left._range; row++ )
0188         for ( int col = 0; col < right._range; col++ )
0189             for ( int line = 0; line < right._range; line++ )
0190                 ( *mat )[row][col] += left._mat[row][line] *
0191                                       right._mat[line][col];
0192 
0193     return mat;
0194 }
0195 
0196 #endif