/* 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 "gtest/gtest.h" #include "CLHEP/Matrix/Vector.h" #include "Maths/Complex.hh" #include "Maths/Vector.hh" #include "Utils/Exception.hh" using MAUS::Vector; using MAUS::operator ==; using MAUS::operator !=; using MAUS::operator +; using MAUS::operator +=; using MAUS::operator -; using MAUS::operator -=; using MAUS::operator *; using MAUS::operator *=; using MAUS::operator /; using MAUS::real; using MAUS::imag; // Defined in ComplexTest.cc bool equal(const MAUS::complex c1, const MAUS::complex c2); bool equal(double c1, double c2); class VectorTest : public testing::Test { public: VectorTest() : d_mv1(4), d_mv2(Vector(4, 4.)), d_mv3(Vector(&da[0], 3)), d_mv6(d_mv1), c_mv1(Vector(4)), c_mv2(Vector(4, MAUS::Complex::complex(1., 1.))), c_mv3(Vector(&ca[0], 3)), c_mv6(c_mv1) { } protected: static const double da[]; static const Vector d_mv0; Vector d_mv1; Vector d_mv2; Vector d_mv3; static const Vector d_mv4; static const Vector d_mv5; Vector d_mv6; static const MAUS::complex ca[3]; static const Vector c_mv0; Vector c_mv1; Vector c_mv2; Vector c_mv3; static const Vector c_mv4; static const Vector c_mv5; Vector c_mv6; }; // **************************************** // VectorTest static const initializations // **************************************** const double VectorTest::da[3] = {1., 2., 3.}; const Vector VectorTest::d_mv0 = Vector(); const Vector VectorTest::d_mv4 = Vector(std::vector(&da[0], &da[3])); const Vector VectorTest::d_mv5 = d_mv4; const MAUS::complex VectorTest::ca[3] = {MAUS::Complex::complex(1., -1.), MAUS::Complex::complex(2., 0.), MAUS::Complex::complex(3., 1.)}; const Vector VectorTest::c_mv0 = Vector(); const Vector VectorTest::c_mv4 = Vector(std::vector(&ca[0], &ca[3])); const Vector VectorTest::c_mv5 = c_mv4; // *********** // test cases // *********** TEST_F(VectorTest, Size) { ASSERT_EQ(d_mv1.size(), (size_t) 4); ASSERT_EQ(d_mv2.size(), (size_t) 4); ASSERT_EQ(d_mv3.size(), (size_t) 3); ASSERT_EQ(d_mv4.size(), (size_t) 3); ASSERT_EQ(c_mv1.size(), (size_t) 4); ASSERT_EQ(c_mv2.size(), (size_t) 4); ASSERT_EQ(c_mv3.size(), (size_t) 3); ASSERT_EQ(c_mv4.size(), (size_t) 3); } TEST_F(VectorTest, Subvector) { // bad access of empty vector bool testpass = true; try { d_mv0.subvector(0, 1); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); size_t sub1 = 2, sub2 = 3; Vector d_mv_sub = d_mv4.subvector(sub1, sub2); ASSERT_TRUE(d_mv_sub.size() == size_t(sub2-sub1)); for (size_t i = 0; i < d_mv_sub.size(); ++i) ASSERT_TRUE(d_mv_sub[i] == d_mv4[i+sub1]); // bad access of empty vector testpass = true; try { c_mv0.subvector(0, 1); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); Vector c_mv_sub = c_mv4.subvector(sub1, sub2); ASSERT_TRUE(c_mv_sub.size() == size_t(sub2-sub1)); for (size_t i = 0; i < c_mv_sub.size(); ++i) ASSERT_TRUE(c_mv_sub[i] == c_mv4[i+sub1]); } TEST_F(VectorTest, Indexing) { // bad access of empty vector bool testpass = true; try { d_mv0[0]; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { const double test_vector = d_mv0[0]; std::cout << test_vector; // eliminate unused variable warning testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { d_mv0(1); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { const double test_vector = d_mv0(1); std::cout << test_vector; // eliminate unused variable warning testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); for (size_t i = 0; i < d_mv2.size(); ++i) ASSERT_TRUE(d_mv2(i+1) == 4.); for (size_t i = 0; i < d_mv3.size(); ++i) ASSERT_TRUE(d_mv3(i+1) == da[i]); for (size_t i = 0; i < d_mv4.size(); ++i) ASSERT_TRUE(d_mv4(i+1) == da[i]); for (size_t i = 0; i < d_mv5.size(); ++i) ASSERT_TRUE(d_mv5(i+1) == da[i]); for (size_t i = 0; i < c_mv2.size(); ++i) ASSERT_TRUE(c_mv2(i+1) == MAUS::Complex::complex(1., 1.)); d_mv2(2+1) = 2.; EXPECT_TRUE(d_mv2(2+1) == 2.); d_mv2(2+1) = 4.; // bad access of empty vector testpass = true; try { c_mv0[0]; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { const MAUS::complex test_vector = c_mv0[0]; // eliminate unused variable warning std::cout << real(test_vector) << imag(test_vector); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { c_mv0(1); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { const MAUS::complex test_vector = c_mv0(1); // eliminate unused variable warning std::cout << real(test_vector) << imag(test_vector); testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); for (size_t i = 0; i < c_mv3.size(); ++i) ASSERT_TRUE(c_mv3(i+1) == ca[i]); for (size_t i = 0; i < c_mv4.size(); ++i) ASSERT_TRUE(c_mv4(i+1) == ca[i]); for (size_t i = 0; i < c_mv5.size(); ++i) ASSERT_TRUE(c_mv5(i+1) == ca[i]); for (size_t i = 1; i <= d_mv2.size(); ++i) ASSERT_TRUE(d_mv2(i) == 4.); for (size_t i = 1; i <= d_mv3.size(); ++i) ASSERT_TRUE(d_mv3(i) == da[i-1]); for (size_t i = 1; i <= c_mv2.size(); ++i) ASSERT_TRUE(c_mv2(i) == MAUS::Complex::complex(1., 1.)); for (size_t i = 1; i <= c_mv3.size(); ++i) ASSERT_TRUE(c_mv3(i) == ca[i-1]); c_mv2(2+1) = MAUS::Complex::complex(-2., 2.); EXPECT_TRUE(c_mv2(2+1) == MAUS::Complex::complex(-2., 2.)); c_mv2(2+1) = MAUS::Complex::complex(1., 1.); } TEST_F(VectorTest, Equals) { Vector empty_d_vector; EXPECT_EQ(empty_d_vector, d_mv0); EXPECT_EQ(d_mv5, d_mv4); Vector empty_c_vector; EXPECT_EQ(empty_c_vector, c_mv0); EXPECT_EQ(c_mv5, c_mv4); } TEST_F(VectorTest, NotEquals) { d_mv3(1) *= -1; EXPECT_TRUE(d_mv5 != d_mv0); EXPECT_TRUE(d_mv5 != d_mv1); EXPECT_TRUE(d_mv5 != d_mv2); EXPECT_TRUE(d_mv5 != d_mv3); d_mv3(1) *= -1; c_mv3(1) *= -1; EXPECT_TRUE(c_mv5 != c_mv0); EXPECT_TRUE(c_mv5 != c_mv1); EXPECT_TRUE(c_mv5 != c_mv2); EXPECT_TRUE(c_mv5 != c_mv3); c_mv3(1) *= -1; } TEST_F(VectorTest, StdVectorConstructor) { std::vector stdvec(4, 4.); // like d_mv2 Vector vector_d0(stdvec); ASSERT_TRUE(vector_d0 == d_mv2); } TEST_F(VectorTest, HepVectorConstructor) { CLHEP::HepVector hepvec(4, 1.); Vector d_test_vec(4, 1.); Vector vector_d0(hepvec); ASSERT_EQ(vector_d0, d_test_vec); hepvec = CLHEP::HepVector(4, 1.); Vector vector_c0(hepvec); Vector c_test_vec(4, MAUS::Complex::complex(1., 0.)); ASSERT_EQ(vector_c0, c_test_vec); } TEST_F(VectorTest, Assignment) { // bad empty vector assignment Vector empty_d_vector(4); bool testpass = true; try { empty_d_vector = d_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); // bad assignment of differently sized vector testpass = true; try { d_mv2 = d_mv4; // d_mv2.size() is 4 while d_mv4.size() is 3 testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); Vector vector_d0 = d_mv3; vector_d0 = vector_d0; // check for specific subtle bug when self-allocating EXPECT_TRUE(vector_d0 == d_mv3); // should be exactly == for (size_t i = 0; i < d_mv3.size(); ++i) vector_d0(i+1) = 2.*vector_d0(i+1); EXPECT_TRUE(vector_d0 != d_mv3); // verify deepcopy // check special assignement to null matrix Vector vector_d1; vector_d1 = vector_d0; EXPECT_TRUE(vector_d1 == vector_d0); // bad empty vector assignment Vector empty_c_vector(4); testpass = true; try { empty_c_vector = c_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); // bad assignment of differently sized vector testpass = true; try { c_mv2 = c_mv4; // c_mv2.size() is 4 while c_mv4.size() is 3 testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); Vector vector_c0 = c_mv3; vector_c0 = vector_c0; // check for specific subtle bug when self-allocating EXPECT_TRUE(vector_c0 == c_mv3); // should be exactly == for (size_t i = 0; i < c_mv3.size(); ++i) vector_c0(i+1) = 2.*vector_c0(i+1); EXPECT_TRUE(vector_c0 != c_mv3); // verify deepcopy) // check special assignement to null matrix Vector vector_c1; vector_c1 = vector_c0; EXPECT_TRUE(vector_c1 == vector_c0); } TEST_F(VectorTest, Multiplication) { // real, vector multiplication // bad multiplication of differently sized vectors Vector test_d_vector(3, 2.); bool testpass = true; try { test_d_vector *= d_mv2; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { test_d_vector * d_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); test_d_vector *= d_mv4; // {2., 2., 2.} * {1., 2., 3.} for (size_t i = 0; i < test_d_vector.size(); ++i) ASSERT_TRUE(fabs(test_d_vector(i+1) - da[i]*2.) < 1e-9); // real, scalar multiplication d_mv3 *= 2.; for (size_t i = 0; i < d_mv3.size(); ++i) ASSERT_TRUE(fabs(d_mv3(i+1) - da[i]*2.) < 1e-9); d_mv3 = d_mv4 * 2.; for (size_t i = 0; i < d_mv3.size(); ++i) ASSERT_TRUE(fabs(d_mv3(i+1) - da[i]*2.) < 1e-9); d_mv3 = 2. * d_mv4; for (size_t i = 0; i < d_mv3.size(); ++i) ASSERT_TRUE(fabs(d_mv3(i+1) - da[i]*2.) < 1e-9); d_mv3 = d_mv4; // complex, vector multiplication // bad multiplication of differently sized vectors Vector test_c_vector(3, MAUS::Complex::complex(2., 1.)); testpass = true; try { test_c_vector *= c_mv2; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { test_c_vector * c_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); // {(2.,1.), (2.,1.), (2.,1.)} * {(1.,-1.), (2.,0.), (3.,1.)} test_c_vector *= c_mv4; MAUS::complex difference; difference = test_c_vector(1) - MAUS::Complex::complex(3., -1.); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); difference = test_c_vector(2) - MAUS::Complex::complex(4., 2.); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); difference = test_c_vector(3) - MAUS::Complex::complex(5., 5.); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); // complex, scalar multiplication c_mv3 *= MAUS::Complex::complex(2., -2.); for (size_t i = 0; i < c_mv3.size(); ++i) ASSERT_TRUE(equal(c_mv3(i+1), ca[i]*MAUS::Complex::complex(2., -2.))); c_mv3 = c_mv4 * MAUS::Complex::complex(2., -2.); for (size_t i = 0; i < c_mv3.size(); ++i) ASSERT_TRUE(equal(c_mv3(i+1), ca[i]*MAUS::Complex::complex(2., -2.))); c_mv3 = MAUS::Complex::complex(2., -2.) * c_mv4; for (size_t i = 0; i < c_mv3.size(); ++i) ASSERT_TRUE(equal(c_mv3(i+1), ca[i]*MAUS::Complex::complex(2., -2.))); c_mv3 = c_mv4; } TEST_F(VectorTest, Division) { // real, vector multiplication // bad division of differently sized vectors Vector test_d_vector(3, 2.); bool testpass = true; try { test_d_vector /= d_mv2; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { test_d_vector / d_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); test_d_vector /= d_mv4; // {2., 2., 2.} / {1., 2., 3.} for (size_t i = 0; i < test_d_vector.size(); ++i) ASSERT_TRUE(fabs(test_d_vector(i+1) - 2./da[i]) < 1e-9); // real, scalar division d_mv3 /= 2.; for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs(d_mv3[i] - da[i]/2.) < 1e-9); d_mv3 = d_mv4; d_mv3 = d_mv3 / 2.; for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs(d_mv3[i] - da[i]/2.) < 1e-9); d_mv3 = d_mv4; // complex, vector multiplication // bad multiplication of differently sized vectors Vector test_c_vector(3, MAUS::Complex::complex(2., 1.)); testpass = true; try { test_c_vector /= c_mv2; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); testpass = true; try { test_c_vector / c_mv0; testpass = false; } catch (MAUS::Exception exc) {} EXPECT_TRUE(testpass); // {(2.,1.), (2.,1.), (2.,1.)} / {(1.,-1.), (2.,0.), (3.,1.)} test_c_vector /= c_mv4; MAUS::complex difference; difference = test_c_vector(1) - MAUS::Complex::complex(0.5, 1.5); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); difference = test_c_vector(2) - MAUS::Complex::complex(1., 0.5); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); difference = test_c_vector(3) - MAUS::Complex::complex(0.7, 0.1); ASSERT_TRUE(fabs(real(difference)) < 1e-9); ASSERT_TRUE(fabs(imag(difference)) < 1e-9); // complex, scalar multiplication c_mv3 /= MAUS::Complex::complex(2., -3); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal(c_mv3[i], ca[i]/MAUS::Complex::complex(2., -3))); c_mv3 = c_mv4; c_mv3 = c_mv3 / MAUS::Complex::complex(2., -3); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal(c_mv3[i], ca[i]/MAUS::Complex::complex(2., -3))); c_mv3 = c_mv4; } TEST_F(VectorTest, Addition) { d_mv3 += (d_mv3/2.); for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs(d_mv3[i] - da[i]*(1.+1./2.)) < 1e-9); d_mv3 = d_mv4; c_mv3 += (c_mv3/MAUS::Complex::complex(3, -2)); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal(c_mv3[i], ca[i]*(1.+1./MAUS::Complex::complex(3, -2)))); c_mv3 = c_mv4; d_mv3 = d_mv3 + (d_mv3/2.); for (size_t i = 0; i < d_mv3.size(); ++i) { EXPECT_TRUE(fabs(d_mv3[i] - da[i]*(1.+1./2.) ) < 1e-9); } d_mv3 = d_mv4; c_mv3 = c_mv3 + (c_mv3/MAUS::Complex::complex(3, -2)); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal(c_mv3[i], ca[i]*(1.+1./MAUS::Complex::complex(3, -2)))); c_mv3 = c_mv4; } TEST_F(VectorTest, Inversion) { for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs((-d_mv3)(i+1) + d_mv3(i+1)) < 1e-9); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal((-c_mv3)(i+1), -(c_mv3(i+1)))); } TEST_F(VectorTest, Subtraction) { d_mv3 -= d_mv4; c_mv3 -= c_mv4; for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs(d_mv3(i+1)) < 1e-9); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal((-c_mv3)(i+1), MAUS::Complex::complex(0, 0))); d_mv3 = d_mv4; c_mv3 = c_mv4; d_mv3 = d_mv3 - d_mv4; c_mv3 = c_mv3 - c_mv4; for (size_t i = 0; i < d_mv3.size(); ++i) EXPECT_TRUE(fabs(d_mv3(i+1) ) < 1e-9); for (size_t i = 0; i < c_mv3.size(); ++i) EXPECT_TRUE(equal((-c_mv3)(i+1), MAUS::Complex::complex(0, 0))); } TEST_F(VectorTest, ComplexDecomposition) { Vector real_part = real(c_mv4); EXPECT_EQ(real_part, d_mv4); Vector imag_part = imag(c_mv4); for (int index = 0; index < 3; ++index) { EXPECT_EQ(imag_part[index], static_cast(index-1)); } } TEST_F(VectorTest, Streaming) { std::stringstream ss; ss << d_mv4 << "\n"; Vector d_mvio; Vector c_mvio; ss >> d_mvio; ss << c_mv4 << std::endl; ss >> c_mvio; for (size_t i = 1; i <= d_mvio.size(); ++i) ASSERT_TRUE(equal(d_mvio(i), d_mv4(i))); for (size_t i = 1; i <= c_mvio.size(); ++i) ASSERT_TRUE(equal(c_mvio(i), c_mv4(i))); }