/* This file is part of MAUS: http:// micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . */ /* Author: Peter Lane */ #include #include #include #include #include #include "TMatrixDSym.h" #include "gtest/gtest.h" #include "CLHEP/Matrix/SymMatrix.h" #include "CLHEP/Random/Random.h" #include "Maths/Matrix.hh" #include "Maths/SymmetricMatrix.hh" #include "Maths/Vector.hh" using MAUS::Matrix; using MAUS::SymmetricMatrix; using MAUS::Vector; // Defined in ComplexTest.cc bool equal(double c1, double c2); class SymmetricMatrixTest : public ::testing::Test { public: SymmetricMatrixTest() { for (size_t index = 0; index < data_size_; ++index) { double_data_doubled_[index] = double_data_[index] * 2; } } bool elements_equal(const SymmetricMatrix& matrix, const double value) { bool are_equal = true; if (matrix.size() != size_) { return false; } for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= row; ++column) { are_equal &= ::equal(matrix(row, column), value); are_equal &= ::equal(matrix(column, row), value); } } return are_equal; } bool equal(const SymmetricMatrix& matrix, const double* array) { bool are_equal = true; if (matrix.size() != size_) { return false; } for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= row; ++column) { are_equal &= ::equal(matrix(row, column), array[(row-1)*size_+(column-1)]); are_equal &= ::equal(matrix(column, row), array[(row-1)*size_+(column-1)]); } } return are_equal; } bool equal(const SymmetricMatrix& m1, const SymmetricMatrix& m2) { bool are_equal = true; if (m1.size() != m2.size()) { return false; } for (size_t row = 1; row <= m1.size(); ++row) { for (size_t column = 1; column <= row; ++column) { are_equal &= ::equal(m1(row, column), m1(column, row)); are_equal &= ::equal(m1(row, column), m2(row, column)); } } return are_equal; } bool equal(const Vector& v1, const Vector& v2) { bool are_equal = true; if (v1.size() != v2.size()) { return false; } for (size_t i = 1; i <= v1.size(); ++i) are_equal &= ::equal(v1(i), v2(i)); return are_equal; } protected: static const size_t data_size_; static const double double_data_[25]; static const size_t size_; double double_data_doubled_[25]; }; // ************************************************ // SymmetricMatrixTest static const initializations // ************************************************ const double SymmetricMatrixTest::double_data_[25] = { 0., 1., 2., 3., -5., 1., -13., -21., 34.5, 55.7, 2., -21., -32.5, -57.5, -91.2, 3., 34.5, -57.5, 2.65, -3.58, -5., -55.7, -91.2, -3.58, 3.38 }; const size_t SymmetricMatrixTest::data_size_ = 25; const size_t SymmetricMatrixTest::size_ = 5; // *********** // test cases // *********** TEST_F(SymmetricMatrixTest, DefaultConstructor) { SymmetricMatrix matrix_d0; ASSERT_EQ(matrix_d0.size(), (size_t) 0); } TEST_F(SymmetricMatrixTest, CopyConstructor) { // should work if matrix is const const SymmetricMatrix matrix_d0(size_, double_data_); const SymmetricMatrix matrix_d1(matrix_d0); EXPECT_TRUE(equal(matrix_d0, matrix_d1)); // check that handles 0 length okay SymmetricMatrix matrix_d2; SymmetricMatrix matrix_d3(matrix_d2); EXPECT_TRUE(equal(matrix_d2, matrix_d3)); } TEST_F(SymmetricMatrixTest, HepSymMatrixConstructor) { ::CLHEP::HepRandom hep_random; const ::CLHEP::HepSymMatrix matrix_hep0(size_, hep_random); const SymmetricMatrix matrix_d0(matrix_hep0); ASSERT_EQ(matrix_d0.size(), (size_t) size_); for (size_t i = 1; i <= size_; ++i) for (size_t j = 1; j <= size_; ++j) EXPECT_EQ(matrix_d0(i, j), matrix_hep0(i, j)); // check that handles 0 length okay ::CLHEP::HepSymMatrix matrix_hep1; SymmetricMatrix matrix_d1(matrix_hep1); ASSERT_EQ(matrix_d1.size(), (size_t) 0); } TEST_F(SymmetricMatrixTest, RootSymMatrixConstructor) { TMatrixDSym matrix_root0(size_); Double_t seed = 2.; matrix_root0.RandomizePD(-2., 2., seed); const SymmetricMatrix matrix_d0(matrix_root0); ASSERT_EQ(matrix_d0.size(), (size_t) size_); for (size_t i = 1; i <= size_; ++i) for (size_t j = 1; j <= size_; ++j) EXPECT_EQ(matrix_d0(i, j), matrix_root0(i-1, j-1)); // check that handles 0 length okay TMatrixDSym matrix_root1; SymmetricMatrix matrix_d1(matrix_root1); ASSERT_EQ(matrix_d1.size(), (size_t) 0); } TEST_F(SymmetricMatrixTest, ConstructorSizeOnly) { SymmetricMatrix matrix_d0(size_); EXPECT_TRUE(elements_equal(matrix_d0, 0.)); } TEST_F(SymmetricMatrixTest, ConstructorFill) { SymmetricMatrix matrix_d0(size_, double_data_[4]); EXPECT_TRUE(elements_equal(matrix_d0, double_data_[4])); } TEST_F(SymmetricMatrixTest, ConstructorFromArray) { SymmetricMatrix matrix_d0(size_, double_data_); EXPECT_TRUE(equal(matrix_d0, double_data_)); } TEST_F(SymmetricMatrixTest, Set) { const SymmetricMatrix matrix_s0(size_, double_data_); SymmetricMatrix matrix_s1(size_); for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= row; ++column) { matrix_s1.set(row, column, double_data_[(row-1)*size_+(column-1)]); } } EXPECT_TRUE(equal(matrix_s0, matrix_s1)); } TEST_F(SymmetricMatrixTest, Assignment) { // plain vanilla assignment SymmetricMatrix matrix_d0(size_, double_data_); SymmetricMatrix matrix_d1 = matrix_d0; EXPECT_TRUE(equal(matrix_d0, matrix_d1)); } TEST_F(SymmetricMatrixTest, Addition) { // add and assign SymmetricMatrix matrix_d0(size_, double_data_); SymmetricMatrix matrix_d1(size_); matrix_d1 += matrix_d0; ASSERT_TRUE(equal(matrix_d0, matrix_d1)); // add SymmetricMatrix matrix_d2 = matrix_d0 + matrix_d1; EXPECT_TRUE(equal(matrix_d2, double_data_doubled_)); } TEST_F(SymmetricMatrixTest, Subtraction) { // subtract and assign SymmetricMatrix matrix_d0(size_, double_data_); SymmetricMatrix matrix_d1(size_, double_data_doubled_); SymmetricMatrix matrix_d2(matrix_d1); matrix_d2 -= matrix_d0; ASSERT_TRUE(equal(matrix_d2, matrix_d0)); // subtract SymmetricMatrix matrix_d3 = matrix_d1 - matrix_d0; EXPECT_TRUE(equal(matrix_d3, double_data_)); } TEST_F(SymmetricMatrixTest, ScalarMultiplication) { // multiply and assign const SymmetricMatrix matrix_d0(size_, double_data_); SymmetricMatrix matrix_d1(matrix_d0); matrix_d1 *= 2.; ASSERT_TRUE(equal(matrix_d1, double_data_doubled_)); // multiplication on the right by a scalar SymmetricMatrix matrix_d2 = matrix_d0 * 2.; ASSERT_TRUE(equal(matrix_d2, double_data_doubled_)); // multiplication on the left by a scalar SymmetricMatrix matrix_d3 = 2. * matrix_d0; ASSERT_TRUE(equal(matrix_d3, double_data_doubled_)); } TEST_F(SymmetricMatrixTest, ScalarDivision) { const SymmetricMatrix matrix_d0(size_, double_data_doubled_); SymmetricMatrix matrix_d1(matrix_d0); matrix_d1 /= 2.; ASSERT_TRUE(equal(matrix_d1, double_data_)); SymmetricMatrix matrix_d2 = matrix_d0 / 2.; ASSERT_TRUE(equal(matrix_d2, double_data_)); } TEST_F(SymmetricMatrixTest, Inverse) { SymmetricMatrix matrix_d1(size_, double_data_); SymmetricMatrix matrix_d2 = inverse(matrix_d1); // M^-1 * M = Identity Matrix matrix_d3 = (Matrix) matrix_d1 * matrix_d2; for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= size_; ++column) { EXPECT_TRUE(::equal(row == column ? 1. : 0., matrix_d3(row, column))); } } } TEST_F(SymmetricMatrixTest, HepSymMatrix) { ::CLHEP::HepRandom hep_random; const SymmetricMatrix matrix_d0(size_, double_data_); ::CLHEP::HepSymMatrix matrix_hep0 = MAUS::CLHEP::HepSymMatrix(matrix_d0); ASSERT_EQ((size_t) matrix_hep0.num_row(), matrix_d0.size()); ASSERT_EQ((size_t) matrix_hep0.num_col(), matrix_d0.size()); for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= size_; ++column) { EXPECT_TRUE(::equal(matrix_hep0(row, column), matrix_d0(row, column))); } } } TEST_F(SymmetricMatrixTest, Eigen) { // verify the eigensystem equation M*E = e*E SymmetricMatrix matrix_d0(size_, double_data_); std::pair< Vector, Matrix > eigensys = eigensystem(matrix_d0); Vector eigenvals = eigensys.first; Matrix eigenvectors = eigensys.second; ASSERT_EQ(eigenvals.size(), size_); ASSERT_EQ(eigenvectors.number_of_columns(), size_); for (size_t i = 1; i < eigenvals.size(); ++i) { double eigenvalue = eigenvals(i); Vector eigenvector = eigenvectors.column(i); EXPECT_TRUE(equal(matrix_d0 * eigenvector, eigenvalue * eigenvector)); } // verify that just getting the eigenvalues returns the same set from // eigensystem() (but perhaps in a different order) Vector eigenvals2 = eigenvalues(matrix_d0); ASSERT_EQ(eigenvals2.size(), size_); for (size_t i = 1; i <= size_; ++i) { bool found_match = false; for (size_t j = 1; j <= size_; j++) { if (::equal(eigenvals2(i), eigenvals(j))) { found_match = true; } } EXPECT_TRUE(found_match); } } TEST_F(SymmetricMatrixTest, Negation) { SymmetricMatrix matrix_d0(size_, double_data_); SymmetricMatrix matrix_d1(-matrix_d0); for (size_t row = 1; row <= size_; ++row) { for (size_t column = 1; column <= row; ++column) { EXPECT_TRUE(::equal(-matrix_d1(row, column), matrix_d0(row, column))); EXPECT_TRUE(::equal(-matrix_d1(column, row), matrix_d0(row, column))); } } }