/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2010-2012 University of Bonn. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder 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 2 of the License, or
* (at your option) any later version.
*
* MoleCuilder 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 MoleCuilder. If not, see .
*/
/*
* 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) );
break;
}
// 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) );
break;
}
// 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);
}