/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * MatrixContentUnitTest.cpp * * Created on: Jan 8, 2010 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif using namespace std; #include #include #include #include #include // include headers that implement a archive in simple text format #include #include #include "MatrixContentUnitTest.hpp" #include "MatrixContent.hpp" #include "VectorContent.hpp" #ifdef HAVE_TESTRUNNER #include "UnitTestMain.hpp" #endif /*HAVE_TESTRUNNER*/ /********************************************** Test classes **************************************/ const std::string matrixA = " 9.962848439806617e-01 5.950413028139907e-01 3.172650036465889e-01\n\ 2.070939109924951e-01 8.365712117773689e-01 3.980567886073226e-01\n\ 1.021600573071414e-01 8.061359922326598e-02 8.493537275043391e-01\n\ 6.955361514014282e-01 6.873206387346102e-02 2.649165458481005e-01"; const std::string vectorS = "1.630290761001098e+00 7.624807744374841e-01 6.374093742147465e-01"; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( MatrixContentTest ); void MatrixContentTest::setUp() { m = new MatrixContent(4,3); }; void MatrixContentTest::tearDown() { delete(m); }; /** Unit Test for accessing matrix elements. * */ void MatrixContentTest::AccessTest() { // check whether all elements are initially zero for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( 0., m->at(i,j) ); // set for (int i=0;i<4;i++) for (int j=0;j<3;j++) m->set(i,j, i*3+j ); // and check double *ptr = NULL; for (int i=0;i<4;i++) for (int j=0;j<3;j++) { CPPUNIT_ASSERT_EQUAL( (double)(i*3+j), m->at(i,j) ); ptr = m->Pointer(i,j); CPPUNIT_ASSERT_EQUAL( (double)(i*3+j), *ptr ); } // assignment for (int i=0;i<4;i++) for (int j=0;j<3;j++) m->set(i,j, i*3+j ); MatrixContent *dest = new MatrixContent(4,3); *dest = *m; for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( dest->at(i,j), m->at(i,j) ); delete(dest); // out of bounds //CPPUNIT_ASSERT_EQUAL(0., v->at(5,2) ); //CPPUNIT_ASSERT_EQUAL(0., v->at(2,17) ); //CPPUNIT_ASSERT_EQUAL(0., v->at(1024,140040) ); //CPPUNIT_ASSERT_EQUAL(0., v->at(-1,0) ); //CPPUNIT_ASSERT_EQUAL(0., v->at(0,-1) ); //CPPUNIT_ASSERT_EQUAL(0., v->at(-1,-1) ); }; /** Unit Test for initializating matrices. * */ void MatrixContentTest::InitializationTest() { // set zero m->setZero(); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( 0., m->at(i,j) ); // set all m->setValue(1.5); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( 1.5, m->at(i,j) ); // set basis m->setIdentity(); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( i == j ? 1. : 0. , m->at(i,j) ); // set from array double array[] = { 1., 0., 0., 0., 1., 0., 0., 0., 1., 0., 0., 0. }; m->setFromDoubleArray(array); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( i == j ? 1. : 0. , m->at(i,j) ); }; /** Unit Test for copying matrices. * */ void MatrixContentTest::CopyTest() { // set basis MatrixContent *dest = NULL; for (int i=0;i<4;i++) { m->setValue(i); dest = new MatrixContent(m); for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( m->at(i,j) , dest->at(i,j) ); delete(dest); } }; /** Unit Test for exchanging rows and columns. * */ void MatrixContentTest::ExchangeTest() { // set to 1,1,1,2, ... for (int i=0;i<4;i++) for (int j=0;j<3;j++) m->set(i,j, i+1 ); // swap such that nothing happens CPPUNIT_ASSERT_EQUAL( true, m->SwapColumns(1,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( (double)i+1., m->at(i,j) ); // swap two rows CPPUNIT_ASSERT_EQUAL( true, m->SwapRows(1,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) switch (i) { case 0: CPPUNIT_ASSERT_EQUAL( 1., m->at(i,j) ); break; case 1: CPPUNIT_ASSERT_EQUAL( 3., m->at(i,j) ); break; case 2: CPPUNIT_ASSERT_EQUAL( 2., m->at(i,j) ); break; case 3: CPPUNIT_ASSERT_EQUAL( 4., m->at(i,j) ); break; default: CPPUNIT_ASSERT_EQUAL( -1., m->at(i,j) ); } // check that op is reversable CPPUNIT_ASSERT_EQUAL( true, m->SwapRows(1,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( (double)i+1., m->at(i,j) ); // set to 1,2,3,1, ... for (int i=0;i<4;i++) for (int j=0;j<3;j++) m->set(i,j, j+1. ); // swap such that nothing happens CPPUNIT_ASSERT_EQUAL( true, m->SwapRows(0,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( (double)j+1., m->at(i,j) ); // swap two columns CPPUNIT_ASSERT_EQUAL( true, m->SwapColumns(0,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) switch (j) { case 0: CPPUNIT_ASSERT_EQUAL( 3., m->at(i,j) ); break; case 1: CPPUNIT_ASSERT_EQUAL( 2., m->at(i,j) ); break; case 2: CPPUNIT_ASSERT_EQUAL( 1., m->at(i,j) ); break; default: CPPUNIT_ASSERT_EQUAL( -1., m->at(i,j) ); } // check that op is reversable CPPUNIT_ASSERT_EQUAL( true, m->SwapColumns(0,2) ); for (int i=0;i<4;i++) for (int j=0;j<3;j++) CPPUNIT_ASSERT_EQUAL( (double)j+1., m->at(i,j) ); // set to 1,2,3,4, ... MatrixContent *n = new MatrixContent(3,4); for (int i=0;i<4;i++) for (int j=0;j<3;j++) { m->set(i,j, 3*i+j+1 ); n->set(j,i, 3*i+j+1 ); } // transpose MatrixContent res = (*m).transposed(); CPPUNIT_ASSERT( *n == res ); // second transpose MatrixContent res2 = res.transposed(); CPPUNIT_ASSERT( *m == res2 ); delete n; }; /** Unit Test for matrix properties. * */ void MatrixContentTest::PropertiesTest() { // is zero m->setZero(); CPPUNIT_ASSERT_EQUAL( true, m->IsNull() ); CPPUNIT_ASSERT_EQUAL( false, m->IsPositive() ); CPPUNIT_ASSERT_EQUAL( false, m->IsNegative() ); CPPUNIT_ASSERT_EQUAL( true, m->IsNonNegative() ); // is positive m->setValue(0.5); CPPUNIT_ASSERT_EQUAL( false, m->IsNull() ); CPPUNIT_ASSERT_EQUAL( true, m->IsPositive() ); CPPUNIT_ASSERT_EQUAL( false, m->IsNegative() ); CPPUNIT_ASSERT_EQUAL( true, m->IsNonNegative() ); // is negative m->setValue(-0.1); CPPUNIT_ASSERT_EQUAL( false, m->IsNull() ); CPPUNIT_ASSERT_EQUAL( false, m->IsPositive() ); CPPUNIT_ASSERT_EQUAL( true, m->IsNegative() ); CPPUNIT_ASSERT_EQUAL( false, m->IsNonNegative() ); // is positive definite CPPUNIT_ASSERT_EQUAL( false, m->IsPositiveDefinite() ); }; /** Unit test for reading from and writing matrix to stream * */ void MatrixContentTest::ReadWriteTest() { // set up matrix for (int i=0;i<4;i++) for (int j=0;j<3;j++) m->set(i,j, i*3+j ); // write to stream std::stringstream matrixstream; m->write(matrixstream); // parse in dimensions and check std::pair matrixdimensions = MatrixContent::preparseMatrixDimensions(matrixstream); CPPUNIT_ASSERT_EQUAL( (size_t)4, matrixdimensions.first ); CPPUNIT_ASSERT_EQUAL( (size_t)3, matrixdimensions.second ); // parse in matrix and check MatrixContent* n = new MatrixContent(4,3, matrixstream); CPPUNIT_ASSERT_EQUAL( *m, *n ); // free matrix delete n; } /** Unit test for MatrixContent::performSingularValueDecomposition(). * */ void MatrixContentTest::SVDTest() { // setup "A", U,S,V std::stringstream Astream(matrixA); std::stringstream Sstream(vectorS); MatrixContent A(m->getRows(), m->getColumns(), Astream); VectorContent S_expected(m->getColumns(), Sstream); *m = A; // check SVD VectorContent S(m->getColumns()); MatrixContent V(m->getColumns(), m->getColumns()); A.performSingularValueDecomposition(V,S); MatrixContent S_diag(m->getColumns(), m->getColumns()); for (size_t index = 0; index < m->getColumns(); ++index) S_diag.set(index, index, S[index]); CPPUNIT_ASSERT_EQUAL(*m,A*S_diag*(V.transpose())); for (size_t index = 0; index < m->getColumns(); ++index) { //CPPUNIT_ASSERT_EQUAL(S_expected[index], S[index]); CPPUNIT_ASSERT(fabs(S_expected[index] - S[index]) < numeric_limits::epsilon()*10.); } // set up right-hand side VectorContent b(4); b[0] = 1.; b[1] = 0.; b[2] = 0.; b[3] = 0.; // SVD VectorContent x_expected(3); x_expected[0] = -0.00209169; x_expected[1] = -0.325399; x_expected[2] = 0.628004; const VectorContent x_result(A.solveOverdeterminedLinearEquation(V,S,b)); // check result for (size_t index = 0; index < m->getColumns(); ++index) { CPPUNIT_ASSERT(fabs(x_expected[index] - x_result[index]) < 1.e-6); } } /** Unit test for serialization * */ void MatrixContentTest::SerializationTest() { m->setZero(); int count=0; for (size_t x = 0; x < 4 ; ++x) for (size_t y = 0; y < 3 ; ++y) m->at(x,y) = count++; // write element to stream std::stringstream stream; boost::archive::text_oarchive oa(stream); oa << m; //std::cout << "Contents of archive is " << stream.str() << std::endl; // create and open an archive for input boost::archive::text_iarchive ia(stream); // read class state from archive MatrixContent *newm; ia >> newm; CPPUNIT_ASSERT (*m == *newm); }