Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:06:46

0001 #ifndef RIVET_MATH_MATRIXN
0002 #define RIVET_MATH_MATRIXN
0003 
0004 #include "Rivet/Math/MathConstants.hh"
0005 #include "Rivet/Math/MathUtils.hh"
0006 #include "Rivet/Math/Vectors.hh"
0007 
0008 #include "Rivet/Math/eigen3/Dense"
0009 
0010 namespace Rivet {
0011 
0012 
0013   template <size_t N>
0014   class Matrix;
0015   typedef Matrix<4> Matrix4;
0016 
0017   template <size_t N>
0018   Matrix<N> multiply(const Matrix<N>& a, const Matrix<N>& b);
0019   template <size_t N>
0020   Matrix<N> divide(const Matrix<N>&, const double);
0021   template <size_t N>
0022   Matrix<N> operator*(const Matrix<N>& a, const Matrix<N>& b);
0023 
0024 
0025   ///////////////////////////////////
0026 
0027 
0028   /// @brief General \f$ N \f$-dimensional mathematical matrix object.
0029   template <size_t N>
0030   class Matrix {
0031 
0032     template <size_t M>
0033     friend Matrix<M> add(const Matrix<M>&, const Matrix<M>&);
0034     template <size_t M>
0035     friend Matrix<M> multiply(const double, const Matrix<M>&);
0036     template <size_t M>
0037     friend Matrix<M> multiply(const Matrix<M>&, const Matrix<M>&);
0038     template <size_t M>
0039     friend Vector<M> multiply(const Matrix<M>&, const Vector<M>&);
0040     template <size_t M>
0041     friend Matrix<M> divide(const Matrix<M>&, const double);
0042 
0043 
0044   public:
0045 
0046     static Matrix<N> mkZero() {
0047       Matrix<N> rtn;
0048       return rtn;
0049     }
0050 
0051     static Matrix<N> mkDiag(Vector<N> diag) {
0052       Matrix<N> rtn;
0053       for (size_t i = 0; i < N; ++i) {
0054         rtn.set(i, i, diag[i]);
0055       }
0056       return rtn;
0057     }
0058 
0059     static Matrix<N> mkIdentity() {
0060       Matrix<N> rtn;
0061       for (size_t i = 0; i < N; ++i) {
0062         rtn.set(i, i, 1);
0063       }
0064       return rtn;
0065     }
0066 
0067 
0068   public:
0069 
0070     Matrix() : _matrix(EMatrix::Zero()) {}
0071 
0072     Matrix& set(const size_t i, const size_t j, const double value) {
0073       if (i < N && j < N) {
0074         _matrix(i, j) = value;
0075       } else {
0076         throw std::runtime_error("Attempted set access outside matrix bounds.");
0077       }
0078       return *this;
0079     }
0080 
0081     double get(const size_t i, const size_t j) const {
0082       if (i < N && j < N) {
0083         return _matrix(i, j);
0084       } else {
0085         throw std::runtime_error("Attempted get access outside matrix bounds.");
0086       }
0087     }
0088 
0089     Vector<N> getRow(const size_t row) const {
0090       Vector<N> rtn;
0091       for (size_t i = 0; i < N; ++i) {
0092         rtn.set(i, _matrix(row,i));
0093       }
0094       return rtn;
0095     }
0096 
0097     Matrix<N>& setRow(const size_t row, const Vector<N>& r) {
0098       for (size_t i = 0; i < N; ++i) {
0099         _matrix(row,i) = r.get(i);
0100       }
0101       return *this;
0102     }
0103 
0104     Vector<N> getColumn(const size_t col) const {
0105       Vector<N> rtn;
0106       for (size_t i = 0; i < N; ++i) {
0107         rtn.set(i, _matrix(i,col));
0108       }
0109       return rtn;
0110     }
0111 
0112     Matrix<N>& setColumn(const size_t col, const Vector<N>& c) {
0113       for (size_t i = 0; i < N; ++i) {
0114         _matrix(i,col) = c.get(i);
0115       }
0116       return *this;
0117     }
0118 
0119     Matrix<N> transpose() const {
0120       Matrix<N> tmp;
0121       tmp._matrix = _matrix.transpose();
0122       return tmp;
0123     }
0124 
0125     // Matrix<N>& transposeInPlace() {
0126     //   _matrix.replaceWithAdjoint();
0127     //   return *this;
0128     // }
0129 
0130     /// Calculate inverse
0131     Matrix<N> inverse() const {
0132       Matrix<N> tmp;
0133       tmp._matrix = _matrix.inverse();
0134       return tmp;
0135     }
0136 
0137     /// Calculate determinant
0138     double det() const  {
0139       return _matrix.determinant();
0140     }
0141 
0142     /// Calculate trace
0143     double trace() const {
0144       double tr = 0.0;
0145       for (size_t i = 0; i < N; ++i) {
0146         tr += _matrix(i,i);
0147       }
0148       return tr;
0149       // return _matrix.trace();
0150     }
0151 
0152     /// Negate
0153     Matrix<N> operator-() const {
0154       Matrix<N> rtn;
0155       rtn._matrix = -_matrix;
0156       return rtn;
0157     }
0158 
0159     /// Get dimensionality
0160     constexpr size_t size() const {
0161       return N;
0162     }
0163 
0164     /// Index-wise check for nullness, allowing for numerical precision
0165     bool isZero(double tolerance=1E-5) const {
0166       for (size_t i=0; i < N; ++i) {
0167         for (size_t j=0; j < N; ++j) {
0168           if (! Rivet::isZero(_matrix(i,j), tolerance) ) return false;
0169         }
0170       }
0171       return true;
0172     }
0173 
0174     /// Check for index-wise equality, allowing for numerical precision
0175     bool isEqual(Matrix<N> other) const {
0176       for (size_t i=0; i < N; ++i) {
0177         for (size_t j=i; j < N; ++j) {
0178           if (! Rivet::isZero(_matrix(i,j) - other._matrix(i,j)) ) return false;
0179         }
0180       }
0181       return true;
0182     }
0183 
0184     /// Check for symmetry under transposition
0185     bool isSymm() const {
0186       return isEqual(this->transpose());
0187     }
0188 
0189     /// Check that all off-diagonal elements are zero, allowing for numerical precision
0190     bool isDiag() const {
0191       for (size_t i=0; i < N; ++i) {
0192         for (size_t j=0; j < N; ++j) {
0193           if (i == j) continue;
0194           if (! Rivet::isZero(_matrix(i,j)) ) return false;
0195         }
0196       }
0197       return true;
0198     }
0199 
0200     bool operator == (const Matrix<N>& a) const {
0201       return _matrix == a._matrix;
0202     }
0203 
0204     bool operator != (const Matrix<N>& a) const {
0205       return _matrix != a._matrix;
0206     }
0207 
0208     // bool operator < (const Matrix<N>& a) const {
0209     //   return _matrix < a._matrix;
0210     // }
0211 
0212     // bool operator <= (const Matrix<N>& a) const {
0213     //   return _matrix <= a._matrix;
0214     // }
0215 
0216     // bool operator > (const Matrix<N>& a) const {
0217     //   return _matrix > a._matrix;
0218     // }
0219 
0220     // bool operator >= (const Matrix<N>& a) const {
0221     //   return _matrix >= a._matrix;
0222     // }
0223 
0224     Matrix<N>& operator *= (const Matrix<N>& m) {
0225       _matrix *= m._matrix;
0226       return *this;
0227     }
0228 
0229     Matrix<N>& operator *= (const double a) {
0230       _matrix *= a;
0231       return *this;
0232     }
0233 
0234     Matrix<N>& operator /= (const double a) {
0235       _matrix /= a;
0236       return *this;
0237     }
0238 
0239     Matrix<N>& operator += (const Matrix<N>& m) {
0240       _matrix += m._matrix;
0241       return *this;
0242     }
0243 
0244     Matrix<N>& operator -= (const Matrix<N>& m) {
0245       _matrix -= m._matrix;
0246       return *this;
0247     }
0248 
0249   protected:
0250 
0251     using EMatrix = RivetEigen::Matrix<double,N,N>;
0252     EMatrix _matrix;
0253 
0254   };
0255 
0256 
0257   /////////////////////////////////
0258 
0259 
0260   template <size_t N>
0261   inline Matrix<N> add(const Matrix<N>& a, const Matrix<N>& b) {
0262     Matrix<N> result;
0263     result._matrix = a._matrix + b._matrix;
0264     return result;
0265   }
0266 
0267   template <size_t N>
0268   inline Matrix<N> subtract(const Matrix<N>& a, const Matrix<N>& b) {
0269     return add(a, -b);
0270   }
0271 
0272   template <size_t N>
0273   inline Matrix<N> operator + (const Matrix<N> a, const Matrix<N>& b) {
0274     return add(a, b);
0275   }
0276 
0277   template <size_t N>
0278   inline Matrix<N> operator - (const Matrix<N> a, const Matrix<N>& b) {
0279     return subtract(a, b);
0280   }
0281 
0282   template <size_t N>
0283   inline Matrix<N> multiply(const double a, const Matrix<N>& m) {
0284     Matrix<N> rtn;
0285     rtn._matrix = a * m._matrix;
0286     return rtn;
0287   }
0288 
0289   template <size_t N>
0290   inline Matrix<N> multiply(const Matrix<N>& m, const double a) {
0291     return multiply(a, m);
0292   }
0293 
0294   template <size_t N>
0295   inline Matrix<N> divide(const Matrix<N>& m, const double a) {
0296     return multiply(1/a, m);
0297   }
0298 
0299   template <size_t N>
0300   inline Matrix<N> operator * (const double a, const Matrix<N>& m) {
0301     return multiply(a, m);
0302   }
0303 
0304   template <size_t N>
0305   inline Matrix<N> operator * (const Matrix<N>& m, const double a) {
0306     return multiply(a, m);
0307   }
0308 
0309   template <size_t N>
0310   inline Matrix<N> multiply(const Matrix<N>& a, const Matrix<N>& b) {
0311     Matrix<N> tmp;
0312     tmp._matrix = a._matrix * b._matrix;
0313     return tmp;
0314   }
0315 
0316   template <size_t N>
0317   inline Matrix<N> operator * (const Matrix<N>& a, const Matrix<N>& b) {
0318     return multiply(a, b);
0319   }
0320 
0321 
0322   template <size_t N>
0323   inline Vector<N> multiply(const Matrix<N>& a, const Vector<N>& b) {
0324     Vector<N> tmp;
0325     tmp._vec = a._matrix * b._vec;
0326     return tmp;
0327   }
0328 
0329   template <size_t N>
0330   inline Vector<N> operator * (const Matrix<N>& a, const Vector<N>& b) {
0331     return multiply(a, b);
0332   }
0333 
0334   template <size_t N>
0335   inline Matrix<N> transpose(const Matrix<N>& m) {
0336     // Matrix<N> tmp;
0337     // for (size_t i = 0; i < N; ++i) {
0338     //   for (size_t j = 0; j < N; ++j) {
0339     //     tmp.set(i, j, m.get(j, i));
0340     //   }
0341     // }
0342     // return tmp;
0343     return m.transpose();
0344   }
0345 
0346   template <size_t N>
0347   inline Matrix<N> inverse(const Matrix<N>& m) {
0348     return m.inverse();
0349   }
0350 
0351   template <size_t N>
0352   inline double det(const Matrix<N>& m) {
0353     return m.determinant();
0354   }
0355 
0356   template <size_t N>
0357   inline double trace(const Matrix<N>& m) {
0358     return m.trace();
0359   }
0360 
0361 
0362   /////////////////////////////////
0363 
0364 
0365   /// Make string representation
0366   template <size_t N>
0367   inline string toString(const Matrix<N>& m) {
0368     std::ostringstream ss;
0369     ss << "[ ";
0370     for (size_t i = 0; i < m.size(); ++i) {
0371       ss << "( ";
0372       for (size_t j = 0; j < m.size(); ++j) {
0373         const double e = m.get(i, j);
0374         ss << (Rivet::isZero(e) ? 0.0 : e) << " ";
0375       }
0376       ss << ") ";
0377     }
0378     ss << "]";
0379     return ss.str();
0380   }
0381 
0382 
0383   /// Stream out string representation
0384   template <size_t N>
0385   inline std::ostream& operator << (std::ostream& out, const Matrix<N>& m) {
0386     out << toString(m);
0387     return out;
0388   }
0389 
0390 
0391   /////////////////////////////////////////////////
0392 
0393 
0394   /// Compare two matrices by index, allowing for numerical precision
0395   template <size_t N>
0396   inline bool fuzzyEquals(const Matrix<N>& ma, const Matrix<N>& mb, double tolerance=1E-5) {
0397     for (size_t i = 0; i < N; ++i) {
0398       for (size_t j = 0; j < N; ++j) {
0399         const double a = ma.get(i, j);
0400         const double b = mb.get(i, j);
0401         if (!Rivet::fuzzyEquals(a, b, tolerance)) return false;
0402       }
0403     }
0404     return true;
0405   }
0406 
0407 
0408   /// External form of numerically safe nullness check
0409   template <size_t N>
0410   inline bool isZero(const Matrix<N>& m, double tolerance=1E-5) {
0411     return m.isZero(tolerance);
0412   }
0413 
0414 
0415 }
0416 
0417 #endif