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
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
0126
0127
0128
0129
0130
0131 Matrix<N> inverse() const {
0132 Matrix<N> tmp;
0133 tmp._matrix = _matrix.inverse();
0134 return tmp;
0135 }
0136
0137
0138 double det() const {
0139 return _matrix.determinant();
0140 }
0141
0142
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
0150 }
0151
0152
0153 Matrix<N> operator-() const {
0154 Matrix<N> rtn;
0155 rtn._matrix = -_matrix;
0156 return rtn;
0157 }
0158
0159
0160 constexpr size_t size() const {
0161 return N;
0162 }
0163
0164
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
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
0185 bool isSymm() const {
0186 return isEqual(this->transpose());
0187 }
0188
0189
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
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
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
0337
0338
0339
0340
0341
0342
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
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
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
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
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