//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see .
//
//---------------------------------------------------------------------------
#ifndef WTENSORBASE_TEST_H
#define WTENSORBASE_TEST_H
// unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
// note that this may be overwritten by defines in WTensorBase.h
// or any files included from there
#ifdef WASSERT_AS_CASSERT
#define WASSERT_FLAG_CHANGED
#undef WASSERT_AS_CASSERT
#endif
#include
#include
#include
#include "../WTensorBase.h"
#include "../WMatrix.h"
#include "../WValue.h"
#include "../../WException.h"
/**
* Test class for WTensorBase.
*
* \note We cannot test invalid template parameters here, as these should lead to compiler errors.
*/
class WTensorBaseTest : public CxxTest::TestSuite
{
public:
// remember we are testing class templates
// we'll need to instantiate every operation/member function at least once
// in order to verify that everything compiles
/**
* The standard constructor should allocate enough memory and set all elements to zero.
*/
void testTensorBaseConstructor()
{
// define tensor types
typedef WTensorBase< 1, 2, double > T12;
typedef WTensorBase< 2, 3, float > T23;
typedef WTensorBase< 4, 2, int > T42;
typedef WTensorBase< 6, 3, double > T63;
typedef WTensorBase< 0, 0, int > T00;
// standard constructor should never throw
TS_ASSERT_THROWS_NOTHING( T12 t12 );
T12 t12;
// number of data elements should be 2
// note that dataSize is private, direct access is only for testing purposes
std::size_t ds = T12::dataSize;
TS_ASSERT_EQUALS( ds, 2 );
// test if all elements were set to zero
// note that m_data is private
for( std::size_t k = 0; k < 2; ++k )
{
TS_ASSERT_EQUALS( t12.m_data[ k ], 0.0 );
}
// do the same for some more tensors
TS_ASSERT_THROWS_NOTHING( T23 t23 );
T23 t23;
ds = T23::dataSize;
TS_ASSERT_EQUALS( ds, 9 );
for( std::size_t k = 0; k < 9; ++k )
{
TS_ASSERT_EQUALS( t23.m_data[ k ], 0.0f );
}
TS_ASSERT_THROWS_NOTHING( T42 t42 );
T42 t42;
ds = T42::dataSize;
TS_ASSERT_EQUALS( ds, 16 );
for( std::size_t k = 0; k < 16; ++k )
{
TS_ASSERT_EQUALS( t42.m_data[ k ], 0 );
}
TS_ASSERT_THROWS_NOTHING( T63 t63 );
T63 t63;
ds = T63::dataSize;
TS_ASSERT_EQUALS( ds, 729 );
for( std::size_t k = 0; k < 729; ++k )
{
TS_ASSERT_EQUALS( t63.m_data[ k ], 0.0 );
}
TS_ASSERT_THROWS_NOTHING( T00 t00 );
T00 t00;
TS_ASSERT_EQUALS( t00.m_data, 0 );
}
/**
* The copy constructor should copy all values.
*/
void testWTensorBaseCopyConstructor()
{
typedef WTensorBase< 2, 3, int > T23;
typedef WTensorBase< 5, 4, double > T54;
typedef WTensorBase< 3, 3, float > T33;
typedef WTensorBase< 0, 2, int > T02;
{
// create a tensor and fill in some values
T23 t;
t.m_data[ 2 ] = 3;
t.m_data[ 3 ] = 2;
t.m_data[ 7 ] = -1;
// also test the first and last elements to avoid off-by-one error
t.m_data[ 8 ] = -25;
t.m_data[ 0 ] = 26;
TS_ASSERT_THROWS_NOTHING( T23 m( t ) );
T23 m( t );
// the data arrays of t and m should be the same
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 9 * sizeof( int ) );
// copy from a const ref
T23 const& w = t;
T23 const r( w );
// the data arrays of r and t should be the same
TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 9 * sizeof( int ) );
}
// now test some other tensors
{
T54 t;
t.m_data[ 2 ] = 3.0;
t.m_data[ 3 ] = 2.4;
t.m_data[ 7 ] = -1.0;
t.m_data[ 675 ] = 20.0;
t.m_data[ 239 ] = -134.243;
t.m_data[ 964 ] = 567.534;
t.m_data[ 1001 ] = -5.4276;
t.m_data[ 543 ] = 1233.4;
t.m_data[ 827 ] = -9878.765;
t.m_data[ 1023 ] = -265.63;
t.m_data[ 0 ] = 2453.0;
TS_ASSERT_THROWS_NOTHING( T54 m( t ) );
T54 m( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 1024 * sizeof( double ) );
}
{
T33 t;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 16 ] = 200.0f;
t.m_data[ 23 ] = -13.4243f;
t.m_data[ 19 ] = 5675.34f;
t.m_data[ 10 ] = -54276.0f;
t.m_data[ 24 ] = 123.34f;
t.m_data[ 18 ] = -98787.65f;
t.m_data[ 26 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
TS_ASSERT_THROWS_NOTHING( T33 m( t ) );
T33 m( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
}
{
T02 t;
t.m_data = -5;
TS_ASSERT_THROWS_NOTHING( T02 m( t ) );
T02 m( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
}
/**
* Test the copy operator.
*/
void testWTensorBaseCopyOperatorSimple()
{
// this is essentially the same test as with the copy constructor,
// only this time we use the copy operator
typedef WTensorBase< 2, 3, int > T23;
typedef WTensorBase< 5, 4, double > T54;
typedef WTensorBase< 3, 3, float > T33;
typedef WTensorBase< 0, 3, double > T03;
{
// create a tensor and fill in some values
T23 t, m;
t.m_data[ 2 ] = 3;
t.m_data[ 3 ] = 2;
t.m_data[ 7 ] = -1;
// also test the first and last elements to avoid off-by-one error
t.m_data[ 8 ] = -25;
t.m_data[ 0 ] = 26;
// force operator =
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
// the data arrays of t and m should be the same
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 9 * sizeof( int ) );
// copy from a const ref
T23 const& w = t;
T23 r;
r.operator = ( w );
// the data arrays of r and t should be the same
TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 9 * sizeof( int ) );
}
// now test some other tensors
{
T54 t, m;
t.m_data[ 2 ] = 3.0;
t.m_data[ 3 ] = 2.4;
t.m_data[ 7 ] = -1.0;
t.m_data[ 675 ] = 20.0;
t.m_data[ 239 ] = -134.243;
t.m_data[ 964 ] = 567.534;
t.m_data[ 1001 ] = -5.4276;
t.m_data[ 543 ] = 1233.4;
t.m_data[ 827 ] = -9878.765;
t.m_data[ 1023 ] = -265.63;
t.m_data[ 0 ] = 2453.0;
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 1024 * sizeof( double ) );
}
{
T33 t, m;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 16 ] = 200.0f;
t.m_data[ 23 ] = -13.4243f;
t.m_data[ 19 ] = 5675.34f;
t.m_data[ 10 ] = -54276.0f;
t.m_data[ 24 ] = 123.34f;
t.m_data[ 18 ] = -98787.65f;
t.m_data[ 26 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
}
{
T03 t;
t.m_data = -4;
TS_ASSERT_THROWS_NOTHING( T03 m( t ) );
T03 m( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
// test multiple assignments in one statement
{
T33 t, m, u, z;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 16 ] = 200.0f;
t.m_data[ 23 ] = -13.4243f;
t.m_data[ 19 ] = 5675.34f;
t.m_data[ 10 ] = -54276.0f;
t.m_data[ 24 ] = 123.34f;
t.m_data[ 18 ] = -98787.65f;
t.m_data[ 26 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
z = u = m = t;
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
TS_ASSERT_SAME_DATA( &m.m_data[ 0 ], &u.m_data[ 0 ], 27 * sizeof( float ) );
TS_ASSERT_SAME_DATA( &u.m_data[ 0 ], &z.m_data[ 0 ], 27 * sizeof( float ) );
}
}
/**
* Test if the copy operator handles assignments of variables to themselves correctly.
*/
void testWTensorBaseCopyOperatorSelfCopy()
{
typedef WTensorBase< 3, 3, double > T33;
typedef WTensorBase< 0, 0, int > T00;
{
T33 t;
// set some elements
t.m_data[ 0 ] = 347.856;
t.m_data[ 26 ] = -4.0;
t.m_data[ 4 ] = -564.4;
// create a copy of t for comparison
T33 m( t );
// now try copying t onto itself
// this should not throw anything, as the WTensor documentation states that Data_T
// ( in this case double ) shouldn't throw on assignment
// this is also the reason that there is no test with a datatype whose operator = throws
TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
t.operator = ( t );
// t and m should still be equal
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( double ) );
}
{
T00 t;
t.m_data = -57;
T00 m( t );
TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
t.operator = ( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
}
/**
* Test if the access operator correctly throws Exceptions only when the input indices are invalid.
*/
void testWTensorBaseArrayAccessErrorConditions()
{
typedef WTensorBase< 4, 4, double > T44;
typedef WTensorBase< 1, 4, int > T14;
typedef WTensorBase< 3, 2, float > T32;
typedef WTensorBase< 0, 654, int > T0;
{
// instantiate a tensor
T44 t;
// now create an index array
int idx[] = { 0, 1, 2, 3 };
// this should work
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// try some invalid indices, indices of a tensor of dimension 4 may only be 0, 1, 2 or 3
idx[ 3 ] = 4; // idx == [ 0, 1, 2, 4 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
// indices are cast to std::size_t (which should be unsigned)
idx[ 3 ] = -1; // idx == [ 0, 1, 2, -1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 2;
idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
// some indices that should be valid
idx[ 0 ] = 3;
idx[ 1 ] = 3;
idx[ 2 ] = 3;
idx[ 3 ] = 3;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 0;
idx[ 3 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 1;
idx[ 1 ] = 3;
idx[ 2 ] = 2;
idx[ 3 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 2;
idx[ 3 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// a larger array should also work, all unneeded values should be ignored
std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
// note that the length of the index array cannot be checked
}
// now do the same for another tensor
{
T14 t;
int idx[] = { 0 };
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 4537;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 2;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 3;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
// and another one
{
T32 t;
// note that only values 0 and 1 are valid indices
int idx[] = { 0, 1, 1 };
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 2 ] = 3;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 2 ] = 2;
idx[ 0 ] = 4537;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 0;
idx[ 1 ] = 1;
idx[ 2 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 1;
idx[ 1 ] = 0;
idx[ 2 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
std::size_t idx2[] = { 0, 1, 1, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
{
T0 t;
std::size_t idx[] = { 0, 1 };
std::size_t* idx2 = NULL;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
}
/**
* Test if the array access operator returns the correct elements.
*/
void testWTensorBaseArrayAccess()
{
typedef WTensorBase< 2, 3, std::size_t > T23;
typedef WTensorBase< 3, 4, std::size_t > T34;
typedef WTensorBase< 0, 1, std::size_t > T01;
// now test if operator [] returns the correct elements
{
// create a new tensor
T23 t;
// enumerate all elements
for( std::size_t k = 0; k < T23::dataSize; ++k )
{
t.m_data[ k ] = k;
}
// the order of elements should be
// 0 1 2
// 3 4 5
// 6 7 8
std::size_t idx[] = { 0, 0 };
TS_ASSERT_EQUALS( t[ idx ], 0 );
idx[ 1 ] = 1; // idx == [ 0, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 1 );
idx[ 1 ] = 2; // idx == [ 0, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 2 );
idx[ 0 ] = 1; // idx == [ 1, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 5 );
idx[ 1 ] = 1; // idx == [ 1, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 4 );
idx[ 1 ] = 0; // idx == [ 1, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 3 );
idx[ 0 ] = 2; // idx == [ 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 6 );
idx[ 1 ] = 1; // idx == [ 2, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 7 );
idx[ 1 ] = 2; // idx == [ 2, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 8 );
// const refs should also work
T23 const& w = t;
idx[ 0 ] = idx[ 1 ] = 0;
TS_ASSERT_EQUALS( w[ idx ], 0 );
idx[ 1 ] = 1; // idx == [ 0, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 1 );
idx[ 1 ] = 2; // idx == [ 0, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 2 );
idx[ 0 ] = 1; // idx == [ 1, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 5 );
idx[ 1 ] = 1; // idx == [ 1, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 4 );
idx[ 1 ] = 0; // idx == [ 1, 0 ]
TS_ASSERT_EQUALS( w[ idx ], 3 );
idx[ 0 ] = 2; // idx == [ 2, 0 ]
TS_ASSERT_EQUALS( w[ idx ], 6 );
idx[ 1 ] = 1; // idx == [ 2, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 7 );
idx[ 1 ] = 2; // idx == [ 2, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 8 );
}
{
// create a new tensor
T34 t;
// enumerate all elements
for( std::size_t k = 0; k < T34::dataSize; ++k )
{
t.m_data[ k ] = k;
}
// order should be
//
// idx[0] == 0 idx[0] == 1 idx[0] == 2 idx[0] == 3
//
// 0 1 2 3 16 17 18 19 32 33 34 35 48 49 50 51 idx[1] == 0
// 4 5 6 7 20 21 22 23 36 37 38 39 52 53 54 55 idx[1] == 1
// 8 9 10 11 24 25 26 27 40 41 42 43 56 57 58 59 idx[1] == 2
//12 13 14 15 28 29 30 31 44 45 46 47 60 61 62 63 idx[1] == 3
std::size_t idx[] = { 0, 0, 0 };
TS_ASSERT_EQUALS( t[ idx ], 0 );
idx[ 1 ] = 2; // idx == [ 0, 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 8 );
idx[ 2 ] = 3; // idx == [ 0, 2, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 11 );
idx[ 0 ] = 1; // idx == [ 1, 2, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 27 );
idx[ 1 ] = 1; // idx == [ 1, 1, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 23 );
idx[ 0 ] = 3; // idx == [ 3, 1, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 55 );
idx[ 2 ] = 0; // idx == [ 3, 1, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 52 );
idx[ 1 ] = 3; // idx == [ 3, 3, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 60 );
idx[ 1 ] = 2; // idx == [ 3, 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 56 );
}
// zero order tensor
{
T01 t;
t.m_data = 65;
std::size_t idx[] = { 0, 1 };
std::size_t* idx2 = NULL;
TS_ASSERT_EQUALS( t[ idx ], 65 );
TS_ASSERT_EQUALS( t[ idx2 ], 65 );
}
}
/**
* Test the std::vector version of operator [] for correct handling of
* various input vector sizes.
*/
void testWTensorBaseVectorAccess()
{
typedef WTensorBase< 4, 4, double > T44;
typedef WTensorBase< 1, 4, double > T14;
typedef WTensorBase< 6, 2, double > T62;
typedef WTensorBase< 0, 1, double > T01;
{
T44 t;
// test a vector of invalid size
std::vector< int > idx;
// this should throw a WException (using the WAssert macro)
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 ); // idx == [ 0, 1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 3 ); // idx == [ 0, 1, 2, 3 ]
// now idx has the correct size and all valid indices
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// a larger vector should also work
idx.push_back( 456 ); // idx == [ 0, 0, 2, 0, 456 ]
// this should simply ignore all values after the 4th
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// bounds checking on the indices is done by the array version of operator [],
// which is called by the vector version
// I'll add some tests here though, in case this changes in the future
idx[ 0 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 3;
idx[ 3 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 2;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
}
{
T14 t;
std::vector< int > idx;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 3 ); // idx == [ 0, 3 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 456 ); // idx == [ 0, 3, 456 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
}
{
T62 t;
std::vector< int > idx;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 ); // idx == [ 0, 1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 );
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 );
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 456 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
}
{
T01 t;
std::vector< int > idx;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 4 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
T01 const w;
TS_ASSERT_THROWS_NOTHING( w[ idx ] );
}
}
/**
* Test if operator == works correctly.
*/
void testWTensorBaseCompareOperator()
{
typedef WTensorBase< 1, 7, double > T17;
typedef WTensorBase< 3, 2, int > T32;
typedef WTensorBase< 0, 0, float > T00;
{
T17 t, m;
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// change some values
std::size_t idx[] = { 4 };
t[ idx ] = 5.0;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
m[ idx ] = 5.0;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 0 ] = 2;
m[ idx ] = 543543.0;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// copying a tensor should lead to the respective tensors being equal
t = m;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// test const
T17 const ct, cm;
TS_ASSERT( ct == cm );
TS_ASSERT( cm == ct );
TS_ASSERT( ct == ct );
TS_ASSERT( cm == cm );
}
{
T32 t, m;
std::size_t idx[] = { 0, 0, 0 };
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 1 ] = 1;
m[ idx ] = -5643;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t = m;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 1 ] = 0;
t[ idx ] = 564;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t.m_data[ 0 ] = 5;
t.m_data[ 1 ] = -65464;
t.m_data[ 2 ] = 89;
t.m_data[ 3 ] = 3276;
t.m_data[ 4 ] = -3276;
t.m_data[ 5 ] = 47;
t.m_data[ 6 ] = 68;
t.m_data[ 7 ] = -239;
m.m_data[ 0 ] = -5;
m.m_data[ 1 ] = 65464;
m.m_data[ 2 ] = -89;
m.m_data[ 3 ] = -3276;
m.m_data[ 4 ] = 3276;
m.m_data[ 5 ] = -47;
m.m_data[ 6 ] = -68;
m.m_data[ 7 ] = 239;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
}
{
T00 t, m;
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t.m_data = 2;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
m.m_data = 2;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
}
}
/**
* Test if operator != works correctly.
*/
void testWTensorBaseCompareOperator2()
{
typedef WTensorBase< 3, 3, int > T33;
typedef WTensorBase< 0, 0, int > T00;
{
T33 t, m;
// two new instances should never not be equal
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
// a tensor should never not be equal to itself
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
// change some elements
t.m_data[ 23 ] = -23467;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t = m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
t.m_data[ 0 ] = 1;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t = m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t.m_data[ 26 ] = -1;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
// test const
T33 const ct, cm;
TS_ASSERT( !( ct != cm ) );
TS_ASSERT( !( cm != ct ) );
TS_ASSERT( !( ct != ct ) );
TS_ASSERT( !( cm != cm ) );
}
{
T00 t, m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t.m_data = 2;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
m.m_data = 2;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
}
}
};
/**
* Test class for WTensorBaseSym.
*
* \note We cannot test invalid template parameters here, as these should lead to compiler errors.
*/
class WTensorBaseSymTest : public CxxTest::TestSuite
{
public:
/**
* The standard constructor should allocate enough memory and set all elements to zero.
*/
void testTensorBaseSymConstructor()
{
// define tensor types
typedef WTensorBaseSym< 1, 2, double > T12;
typedef WTensorBaseSym< 2, 3, float > T23;
typedef WTensorBaseSym< 4, 2, int > T42;
typedef WTensorBaseSym< 6, 3, double > T63;
typedef WTensorBaseSym< 0, 0, int > T00;
// standard constructor should never throw
TS_ASSERT_THROWS_NOTHING( T12 t12 );
T12 t12;
// number of data elements should be 2
// note that dataSize is private, direct access is only for testing purposes
std::size_t ds = T12::dataSize;
TS_ASSERT_EQUALS( ds, 2 );
// test if all elements were set to zero
// note that m_data is private
for( std::size_t k = 0; k < 2; ++k )
{
TS_ASSERT_EQUALS( t12.m_data[ k ], 0.0 );
}
// do the same for some more tensors
// symmetric tensors need less memory, 6 instead of 9 values in this case
TS_ASSERT_THROWS_NOTHING( T23 t23 );
T23 t23;
ds = T23::dataSize;
TS_ASSERT_EQUALS( ds, 6 );
for( std::size_t k = 0; k < 6; ++k )
{
TS_ASSERT_EQUALS( t23.m_data[ k ], 0.0f );
}
TS_ASSERT_THROWS_NOTHING( T42 t42 );
T42 t42;
ds = T42::dataSize;
TS_ASSERT_EQUALS( ds, 5 );
for( std::size_t k = 0; k < 5; ++k )
{
TS_ASSERT_EQUALS( t42.m_data[ k ], 0 );
}
TS_ASSERT_THROWS_NOTHING( T63 t63 );
T63 t63;
ds = T63::dataSize;
TS_ASSERT_EQUALS( ds, 28 );
for( std::size_t k = 0; k < 28; ++k )
{
TS_ASSERT_EQUALS( t63.m_data[ k ], 0.0 );
}
TS_ASSERT_THROWS_NOTHING( T00 t00 );
T00 t00;
TS_ASSERT_EQUALS( t00.m_data, 0 );
}
/**
* The copy constructor should copy all values.
*/
void testWTensorBaseSymCopyConstructor()
{
typedef WTensorBaseSym< 2, 3, int > T23;
typedef WTensorBaseSym< 5, 4, double > T54;
typedef WTensorBaseSym< 3, 3, float > T33;
typedef WTensorBaseSym< 0, 2, int > T02;
{
// create a tensor and fill in some values
// use direct access to the m_data array as access operators aren't tested yet
T23 t;
t.m_data[ 2 ] = 3;
t.m_data[ 3 ] = 2;
t.m_data[ 4 ] = -1;
// also test the first and last elements to avoid off-by-one error
t.m_data[ 5 ] = -25;
t.m_data[ 0 ] = 26;
TS_ASSERT_THROWS_NOTHING( T23 m( t ) );
T23 m( t );
// the data arrays of t and m should be the same
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 6 * sizeof( int ) );
// copy from a const ref
T23 const& w = t;
T23 const r( w );
// the data arrays of r and t should be the same
TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 6 * sizeof( int ) );
}
// now test some other tensors
{
T54 t;
t.m_data[ 2 ] = 3.0;
t.m_data[ 3 ] = 2.4;
t.m_data[ 7 ] = -1.0;
t.m_data[ 33 ] = 20.0;
t.m_data[ 21 ] = -134.243;
t.m_data[ 54 ] = 567.534;
t.m_data[ 48 ] = -5.4276;
t.m_data[ 34 ] = 1233.4;
t.m_data[ 27 ] = -9878.765;
t.m_data[ 55 ] = -265.63;
t.m_data[ 0 ] = 2453.0;
TS_ASSERT_THROWS_NOTHING( T54 m( t ) );
T54 m( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 56 * sizeof( double ) );
}
{
T33 t;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 1 ] = -13.4243f;
t.m_data[ 5 ] = 5675.34f;
t.m_data[ 6 ] = -54276.0f;
t.m_data[ 4 ] = 123.34f;
t.m_data[ 8 ] = -98787.65f;
t.m_data[ 9 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
TS_ASSERT_THROWS_NOTHING( T33 m( t ) );
T33 m( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
}
// test multiple assignments in one statement
{
T33 t, m, u, z;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 1 ] = -13.4243f;
t.m_data[ 5 ] = 5675.34f;
t.m_data[ 6 ] = -54276.0f;
t.m_data[ 4 ] = 123.34f;
t.m_data[ 8 ] = -98787.65f;
t.m_data[ 9 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
z = u = m = t;
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
TS_ASSERT_SAME_DATA( &m.m_data[ 0 ], &u.m_data[ 0 ], 10 * sizeof( float ) );
TS_ASSERT_SAME_DATA( &u.m_data[ 0 ], &z.m_data[ 0 ], 10 * sizeof( float ) );
}
{
T02 t;
t.m_data = -5;
TS_ASSERT_THROWS_NOTHING( T02 m( t ) );
T02 m( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
}
/**
* Test the copy operator.
*/
void testWTensorBaseSymCopyOperatorSimple()
{
// this is essentially the same test as with the copy constructor,
// only this time we use the copy operator
typedef WTensorBaseSym< 2, 3, int > T23;
typedef WTensorBaseSym< 5, 4, double > T54;
typedef WTensorBaseSym< 3, 3, float > T33;
typedef WTensorBaseSym< 0, 3, double > T03;
{
// create a tensor and fill in some values
// use direct access to the m_data array as access operators aren't tested yet
T23 t, m;
t.m_data[ 2 ] = 3;
t.m_data[ 3 ] = 2;
t.m_data[ 1 ] = -1;
// also test the first and last elements to avoid off-by-one error
t.m_data[ 5 ] = -25;
t.m_data[ 0 ] = 26;
// force operator =
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
// the data arrays of t and m should be the same
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 6 * sizeof( int ) );
// copy from a const ref
T23 const& w = t;
T23 r;
r.operator = ( w );
// the data arrays of r and t should be the same
TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 6 * sizeof( int ) );
}
// now test some other tensors
{
T54 t, m;
t.m_data[ 2 ] = 3.0;
t.m_data[ 3 ] = 2.4;
t.m_data[ 7 ] = -1.0;
t.m_data[ 33 ] = 20.0;
t.m_data[ 21 ] = -134.243;
t.m_data[ 54 ] = 567.534;
t.m_data[ 48 ] = -5.4276;
t.m_data[ 34 ] = 1233.4;
t.m_data[ 27 ] = -9878.765;
t.m_data[ 55 ] = -265.63;
t.m_data[ 0 ] = 2453.0;
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 56 * sizeof( double ) );
}
{
T33 t, m;
t.m_data[ 2 ] = 3.0f;
t.m_data[ 3 ] = 2.0f;
t.m_data[ 7 ] = -1.0f;
t.m_data[ 1 ] = -13.4243f;
t.m_data[ 5 ] = 5675.34f;
t.m_data[ 6 ] = -54276.0f;
t.m_data[ 4 ] = 123.34f;
t.m_data[ 8 ] = -98787.65f;
t.m_data[ 9 ] = -26.563f;
t.m_data[ 0 ] = 245.3f;
TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
m.operator = ( t );
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
}
{
T03 t;
t.m_data = -4;
TS_ASSERT_THROWS_NOTHING( T03 m( t ) );
T03 m( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
}
/**
* Test if the copy operator handles assignments of variables to themselves correctly.
*/
void testWTensorBaseSymCopyOperatorSelfCopy()
{
typedef WTensorBaseSym< 3, 3, double > T33;
typedef WTensorBaseSym< 0, 0, int > T00;
{
T33 t;
// set some elements
t.m_data[ 0 ] = 347.856;
t.m_data[ 9 ] = -4.0;
t.m_data[ 4 ] = -564.4;
// create a copy of t for comparison
T33 m( t );
// now try copying t onto itself
// this should not throw anything, as the WTensorSym documentation states that Data_T
// ( in this case double ) shouldn't throw on assignment
// this is also the reason that there is no test with a datatype whose operator = throws
TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
t.operator = ( t );
// t and m should still be equal
TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( double ) );
}
{
T00 t;
t.m_data = -57;
T00 m( t );
TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
t.operator = ( t );
TS_ASSERT_EQUALS( m.m_data, t.m_data );
}
}
/**
* Test if the access operator correctly throws Exceptions only when the input indices are invalid.
*/
void testWTensorBaseSymArrayAccessErrorConditions()
{
typedef WTensorBaseSym< 4, 4, double > T44;
typedef WTensorBaseSym< 1, 4, int > T14;
typedef WTensorBaseSym< 3, 2, float > T32;
typedef WTensorBaseSym< 0, 654, int > T0;
// first, we'll check some error conditions
{
// instantiate a tensor
T44 t;
// now create an index array
int idx[] = { 0, 1, 2, 3 };
// this should work
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// try some invalid indices, indices of a tensor of dimension 4 may only be 0, 1, 2 or 3
idx[ 3 ] = 4; // idx == [ 0, 1, 2, 4 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
// indices are cast to std::size_t (which should be unsigned)
idx[ 3 ] = -1; // idx == [ 0, 1, 2, -1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 2;
idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
// some indices that should be valid
idx[ 0 ] = 3;
idx[ 1 ] = 3;
idx[ 2 ] = 3;
idx[ 3 ] = 3;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 0;
idx[ 3 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 1;
idx[ 1 ] = 3;
idx[ 2 ] = 2;
idx[ 3 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 2;
idx[ 3 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// a larger array should also work, all unneeded values should be ignored
std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
// note that the length of the index array cannot be checked
}
// now do the same for another tensor
{
T14 t;
int idx[] = { 0 };
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 4537;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 2;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 3;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
// and another one
{
T32 t;
// note that only values 0 and 1 are valid indices
int idx[] = { 0, 1, 1 };
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 2 ] = 3;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 2 ] = 2;
idx[ 0 ] = 4537;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 0;
idx[ 1 ] = 1;
idx[ 2 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 0;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 1;
idx[ 1 ] = 0;
idx[ 2 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx[ 0 ] = 0;
idx[ 1 ] = 0;
idx[ 2 ] = 1;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
std::size_t idx2[] = { 0, 1, 1, 3, 8, 54643 };
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
{
T0 t;
std::size_t idx[] = { 0, 1 };
std::size_t* idx2 = NULL;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
}
}
/**
* Test if the array access operator returns the correct elements.
*/
void testWTensorBaseSymArrayAccess()
{
typedef WTensorBaseSym< 2, 3, std::size_t > T23;
typedef WTensorBaseSym< 3, 4, std::size_t > T34;
// now test if operator [] returns the correct elements
{
// create a new tensor
T23 t;
// enumerate all elements
for( std::size_t k = 0; k < T23::dataSize; ++k )
{
t.m_data[ k ] = k;
}
// the order of elements should be
// 0 1 2
// 3 4
// 5
std::size_t idx[] = { 0, 0 };
TS_ASSERT_EQUALS( t[ idx ], 0 );
idx[ 1 ] = 1; // idx == [ 0, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 1 );
idx[ 1 ] = 2; // idx == [ 0, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 2 );
idx[ 0 ] = 1; // idx == [ 1, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 4 );
idx[ 1 ] = 1; // idx == [ 1, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 3 );
idx[ 1 ] = 0; // idx == [ 1, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 1 );
idx[ 0 ] = 2; // idx == [ 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 2 );
idx[ 1 ] = 1; // idx == [ 2, 1 ]
TS_ASSERT_EQUALS( t[ idx ], 4 );
idx[ 1 ] = 2; // idx == [ 2, 2 ]
TS_ASSERT_EQUALS( t[ idx ], 5 );
// const refs should also work
T23 const& w = t;
idx[ 0 ] = idx[ 1 ] = 0;
TS_ASSERT_EQUALS( w[ idx ], 0 );
idx[ 1 ] = 1; // idx == [ 0, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 1 );
idx[ 1 ] = 2; // idx == [ 0, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 2 );
idx[ 0 ] = 1; // idx == [ 1, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 4 );
idx[ 1 ] = 1; // idx == [ 1, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 3 );
idx[ 1 ] = 0; // idx == [ 1, 0 ]
TS_ASSERT_EQUALS( w[ idx ], 1 );
idx[ 0 ] = 2; // idx == [ 2, 0 ]
TS_ASSERT_EQUALS( w[ idx ], 2 );
idx[ 1 ] = 1; // idx == [ 2, 1 ]
TS_ASSERT_EQUALS( w[ idx ], 4 );
idx[ 1 ] = 2; // idx == [ 2, 2 ]
TS_ASSERT_EQUALS( w[ idx ], 5 );
}
{
// create a new tensor
T34 t;
// enumerate all elements
for( std::size_t k = 0; k < T34::dataSize; ++k )
{
t.m_data[ k ] = k;
}
// order should be
//
// idx[0] == 0 idx[0] == 1 idx[0] == 2 idx[0] == 3
//
// 0 1 2 3 idx[1] == 0
// 4 5 6 10 11 12 idx[1] == 1
// 7 8 13 14 16 17 idx[1] == 2
// 9 15 18 19 idx[1] == 3
std::size_t idx[] = { 0, 0, 0 };
TS_ASSERT_EQUALS( t[ idx ], 0 );
idx[ 1 ] = 2; // idx == [ 0, 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 2 );
idx[ 2 ] = 3; // idx == [ 0, 2, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 8 );
idx[ 0 ] = 1; // idx == [ 1, 2, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 14 );
idx[ 1 ] = 1; // idx == [ 1, 1, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 12 );
idx[ 0 ] = 3; // idx == [ 3, 1, 3 ]
TS_ASSERT_EQUALS( t[ idx ], 15 );
idx[ 2 ] = 0; // idx == [ 3, 1, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 6 );
idx[ 1 ] = 3; // idx == [ 3, 3, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 9 );
idx[ 1 ] = 2; // idx == [ 3, 2, 0 ]
TS_ASSERT_EQUALS( t[ idx ], 8 );
}
}
/**
* Test if operator [] correctly maps permutations of the same set of indices to
* the same array positions.
*/
void testWTensorBaseSymAccessOperatorPermutations()
{
typedef WTensorBaseSym< 3, 4, std::size_t > T34;
T34 t;
// enumerate all elements
for( std::size_t k = 0; k < T34::dataSize; ++k )
{
t.m_data[ k ] = k;
}
// create some index set permutations
std::size_t idx1[ 3 ][ 3 ] = { { 0, 0, 1 }, // NOLINT no extra lines for { or } in an array initialization
{ 0, 1, 0 }, // NOLINT
{ 1, 0, 0 } }; // NOLINT
std::size_t idx2[ 6 ][ 3 ] = { { 0, 1, 2 }, // NOLINT
{ 0, 2, 1 }, // NOLINT
{ 1, 2, 0 }, // NOLINT
{ 2, 1, 0 }, // NOLINT
{ 1, 0, 2 }, // NOLINT
{ 2, 1, 0 } }; // NOLINT
std::size_t idx3[ 3 ][ 3 ] = { { 0, 0, 3 }, // NOLINT
{ 0, 3, 0 }, // NOLINT
{ 3, 0, 0 } }; // NOLINT
std::size_t idx4[ 6 ][ 3 ] = { { 0, 3, 2 }, // NOLINT
{ 0, 2, 3 }, // NOLINT
{ 3, 2, 0 }, // NOLINT
{ 2, 3, 0 }, // NOLINT
{ 3, 0, 2 }, // NOLINT
{ 2, 3, 0 } }; // NOLINT
// operator [] should map any permutation of a set of indices onto the same array position
TS_ASSERT_EQUALS( t[ idx1[ 0 ] ], t[ idx1[ 1 ] ] );
TS_ASSERT_EQUALS( t[ idx1[ 1 ] ], t[ idx1[ 2 ] ] );
TS_ASSERT_EQUALS( t[ idx2[ 0 ] ], t[ idx2[ 1 ] ] );
TS_ASSERT_EQUALS( t[ idx2[ 1 ] ], t[ idx2[ 2 ] ] );
TS_ASSERT_EQUALS( t[ idx2[ 2 ] ], t[ idx2[ 3 ] ] );
TS_ASSERT_EQUALS( t[ idx2[ 3 ] ], t[ idx2[ 4 ] ] );
TS_ASSERT_EQUALS( t[ idx2[ 4 ] ], t[ idx2[ 5 ] ] );
TS_ASSERT_EQUALS( t[ idx3[ 0 ] ], t[ idx3[ 1 ] ] );
TS_ASSERT_EQUALS( t[ idx3[ 1 ] ], t[ idx3[ 2 ] ] );
TS_ASSERT_EQUALS( t[ idx4[ 0 ] ], t[ idx4[ 1 ] ] );
TS_ASSERT_EQUALS( t[ idx4[ 1 ] ], t[ idx4[ 2 ] ] );
TS_ASSERT_EQUALS( t[ idx4[ 2 ] ], t[ idx4[ 3 ] ] );
TS_ASSERT_EQUALS( t[ idx4[ 3 ] ], t[ idx4[ 4 ] ] );
TS_ASSERT_EQUALS( t[ idx4[ 4 ] ], t[ idx4[ 5 ] ] );
// permutations of different index sets may never map onto the same position
TS_ASSERT_DIFFERS( t[ idx1[ 0 ] ], t[ idx2[ 0 ] ] );
TS_ASSERT_DIFFERS( t[ idx1[ 1 ] ], t[ idx2[ 5 ] ] );
TS_ASSERT_DIFFERS( t[ idx2[ 0 ] ], t[ idx4[ 4 ] ] );
TS_ASSERT_DIFFERS( t[ idx2[ 0 ] ], t[ idx3[ 2 ] ] );
TS_ASSERT_DIFFERS( t[ idx2[ 3 ] ], t[ idx3[ 1 ] ] );
TS_ASSERT_DIFFERS( t[ idx3[ 0 ] ], t[ idx2[ 0 ] ] );
TS_ASSERT_DIFFERS( t[ idx3[ 1 ] ], t[ idx4[ 3 ] ] );
TS_ASSERT_DIFFERS( t[ idx3[ 0 ] ], t[ idx1[ 2 ] ] );
TS_ASSERT_DIFFERS( t[ idx4[ 2 ] ], t[ idx1[ 0 ] ] );
TS_ASSERT_DIFFERS( t[ idx4[ 5 ] ], t[ idx3[ 2 ] ] );
}
/**
* Test the std::vector version of operator [] for correct handling of
* various input vector sizes.
*/
void testWTensorBaseSymVectorAccess()
{
typedef WTensorBaseSym< 4, 4, double > T44;
typedef WTensorBaseSym< 1, 4, double > T14;
typedef WTensorBaseSym< 6, 2, double > T62;
{
T44 t;
// test a vector of invalid size
std::vector< int > idx;
// this should throw a WException (using the WAssert macro)
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 ); // idx == [ 0, 1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 3 ); // idx == [ 0, 1, 2, 3 ]
// now idx has the correct size and all valid indices
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// a larger vector should also work
idx.push_back( 456 ); // idx == [ 0, 0, 2, 0, 456 ]
// this should simply ignore all values after the 4th
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
// bounds checking on the indices is done by the array version of operator [],
// which is called by the vector version
// I'll add some tests here though, in case this changes in the future
idx[ 0 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 0 ] = 3;
idx[ 3 ] = -1;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 4;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx[ 3 ] = 2;
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
}
{
T14 t;
std::vector< int > idx;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 3 ); // idx == [ 0, 3 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 456 ); // idx == [ 0, 3, 456 ]
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
}
{
T62 t;
std::vector< int > idx;
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 ); // idx == [ 0, 1 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 );
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 1 );
TS_ASSERT_THROWS( t[ idx ], const WException& );
idx.push_back( 0 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( 456 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
idx.push_back( -1 );
TS_ASSERT_THROWS_NOTHING( t[ idx ] );
T62 const w;
TS_ASSERT_THROWS_NOTHING( w[ idx ] );
}
}
/**
* Test if operator == works correctly.
*/
void testWTensorBaseSymCompareOperator()
{
typedef WTensorBaseSym< 1, 7, double > T17;
typedef WTensorBaseSym< 3, 2, int > T32;
typedef WTensorBaseSym< 0, 0, float > T00;
{
T17 t, m;
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// change some values
std::size_t idx[] = { 4 };
t[ idx ] = 5.0;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
m[ idx ] = 5.0;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 0 ] = 2;
m[ idx ] = 543543.0;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// copying a tensor should lead to the respective tensors being equal
t = m;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
// test const
T17 const ct, cm;
TS_ASSERT( ct == cm );
TS_ASSERT( cm == ct );
TS_ASSERT( ct == ct );
TS_ASSERT( cm == cm );
}
{
T32 t, m;
std::size_t idx[] = { 0, 0, 0 };
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 1 ] = 1;
m[ idx ] = -5643;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t = m;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
idx[ 1 ] = 0;
t[ idx ] = 564;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t.m_data[ 0 ] = 5;
t.m_data[ 1 ] = -65464;
t.m_data[ 2 ] = 89;
t.m_data[ 3 ] = 3276;
m.m_data[ 0 ] = -5;
m.m_data[ 1 ] = 65464;
m.m_data[ 2 ] = -89;
m.m_data[ 3 ] = -3276;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
}
{
T00 t, m;
// two tensors of the same type should be initialized to the same values
TS_ASSERT( t == m );
TS_ASSERT( m == t );
// a tensor should always be equal to itself
TS_ASSERT( t == t );
TS_ASSERT( m == m );
t.m_data = 2;
TS_ASSERT( !( t == m ) );
TS_ASSERT( !( m == t ) );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
m.m_data = 2;
TS_ASSERT( t == m );
TS_ASSERT( m == t );
TS_ASSERT( t == t );
TS_ASSERT( m == m );
}
}
/**
* Test if operator != works correctly.
*/
void testWTensorBaseSymCompareOperator2()
{
typedef WTensorBaseSym< 3, 3, int > T33;
typedef WTensorBaseSym< 0, 0, int > T00;
{
T33 t, m;
// two new instances should never not be equal
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
// a tensor should never not be equal to itself
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
// change some elements
t.m_data[ 4 ] = -23467;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t = m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
t.m_data[ 0 ] = 1;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t = m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t.m_data[ 9 ] = -1;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
// test const
T33 const ct, cm;
TS_ASSERT( !( ct != cm ) );
TS_ASSERT( !( cm != ct ) );
TS_ASSERT( !( ct != ct ) );
TS_ASSERT( !( cm != cm ) );
}
{
T00 t, m;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
t.m_data = 2;
TS_ASSERT( t != m );
TS_ASSERT( m != t );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
m.m_data = 2;
TS_ASSERT( !( t != m ) );
TS_ASSERT( !( m != t ) );
TS_ASSERT( !( t != t ) );
TS_ASSERT( !( m != m ) );
}
}
};
/**
* A class that tests the WTensorFunc template.
*/
class WTensorFuncTest : public CxxTest::TestSuite
{
public:
/**
* Test operator () error conditions.
*/
void testAccessOperatorErrors()
{
// first test with an asymmetric tensor base
typedef WTensorFunc< WTensorBase, 3, 3, double > F33;
typedef WTensorFunc< WTensorBase, 1, 5, int > F15;
{
F33 f;
// try some valid indices
TS_ASSERT_THROWS_NOTHING( f( 0, 0, 0 ) );
TS_ASSERT_THROWS_NOTHING( f( 1, 0, 0 ) );
TS_ASSERT_THROWS_NOTHING( f( 2, 2, 2 ) );
TS_ASSERT_THROWS_NOTHING( f( 1, 1, 1 ) );
TS_ASSERT_THROWS_NOTHING( f( 1, 0, 2 ) );
TS_ASSERT_THROWS_NOTHING( f( 0, 2, 0 ) );
// try some invalid indices
// negative indices are not allowed as the parameters are of type std::size_t
TS_ASSERT_THROWS( f( 0, 0, 3 ), const WException& );
TS_ASSERT_THROWS( f( 0, 654465, 0 ), const WException& );
TS_ASSERT_THROWS( f( 4, 0, 0 ), const WException& );
TS_ASSERT_THROWS( f( 0, 0, 45 ), const WException& );
TS_ASSERT_THROWS( f( 0, 64, 0 ), const WException& );
TS_ASSERT_THROWS( f( 792, 981, 5645 ), const WException& );
}
{
F15 f;
TS_ASSERT_THROWS_NOTHING( f( 0 ) );
TS_ASSERT_THROWS_NOTHING( f( 1 ) );
TS_ASSERT_THROWS_NOTHING( f( 2 ) );
TS_ASSERT_THROWS_NOTHING( f( 3 ) );
TS_ASSERT_THROWS_NOTHING( f( 4 ) );
TS_ASSERT_THROWS( f( 5 ), const WException& );
TS_ASSERT_THROWS( f( 5436 ), const WException& );
}
// now try a symmetric tensor base
typedef WTensorFunc< WTensorBaseSym, 2, 4, double > F24;
{
F24 f;
TS_ASSERT_THROWS_NOTHING( f( 0, 0 ) );
TS_ASSERT_THROWS_NOTHING( f( 3, 0 ) );
TS_ASSERT_THROWS_NOTHING( f( 2, 3 ) );
TS_ASSERT_THROWS_NOTHING( f( 3, 3 ) );
TS_ASSERT_THROWS_NOTHING( f( 0, 1 ) );
TS_ASSERT_THROWS( f( 4, 0 ), const WException& );
TS_ASSERT_THROWS( f( 3, 457 ), const WException& );
}
}
/**
* Test if operator () returns the correct elements.
*/
void testAccessOperator()
{
typedef WTensorFunc< WTensorBase, 6, 2, std::size_t > F62;
typedef WTensorBase< 6, 2, std::size_t > Base62;
F62 f;
Base62& b = f;
for( std::size_t k = 0; k < 64; ++k )
{
b.m_data[ k ] = k;
}
TS_ASSERT_EQUALS( f( 0, 0, 0, 0, 0, 0 ), 0 );
TS_ASSERT_EQUALS( f( 0, 0, 0, 1, 0, 1 ), 5 );
TS_ASSERT_EQUALS( f( 1, 1, 1, 0, 0, 0 ), 56 );
TS_ASSERT_EQUALS( f( 0, 1, 0, 0, 0, 1 ), 17 );
TS_ASSERT_EQUALS( f( 0, 0, 1, 0, 1, 0 ), 10 );
TS_ASSERT_EQUALS( f( 1, 0, 1, 0, 0, 1 ), 41 );
TS_ASSERT_EQUALS( f( 1, 1, 1, 1, 1, 1 ), 63 );
F62 const& w = f;
TS_ASSERT_EQUALS( w( 0, 0, 0, 0, 0, 0 ), 0 );
TS_ASSERT_EQUALS( w( 0, 0, 0, 1, 0, 1 ), 5 );
TS_ASSERT_EQUALS( w( 1, 1, 1, 0, 0, 0 ), 56 );
TS_ASSERT_EQUALS( w( 0, 1, 0, 0, 0, 1 ), 17 );
TS_ASSERT_EQUALS( w( 0, 0, 1, 0, 1, 0 ), 10 );
TS_ASSERT_EQUALS( w( 1, 0, 1, 0, 0, 1 ), 41 );
TS_ASSERT_EQUALS( w( 1, 1, 1, 1, 1, 1 ), 63 );
}
/**
* Test if operator () keeps the symmetry of a WTensorBaseSym intact.
*/
void testAccessOperatorSymmetry()
{
typedef WTensorFunc< WTensorBaseSym, 4, 5, std::size_t > F45;
typedef WTensorBaseSym< 4, 5, std::size_t > Base45;
F45 f;
Base45& b = f;
for( std::size_t k = 0; k < 70; ++k )
{
b.m_data[ k ] = k;
}
std::size_t idx[ 8 ][ 6 ] = { { 0, 1, 2, 4 }, // NOLINT no extra line per { or }
{ 3, 2, 4, 0 }, // NOLINT
{ 4, 4, 4, 0 }, // NOLINT
{ 0, 0, 0, 0 }, // NOLINT
{ 3, 4, 0, 1 }, // NOLINT
{ 2, 2, 2, 2 }, // NOLINT
{ 4, 4, 4, 4 }, // NOLINT
{ 2, 2, 0, 3 } }; // NOLINT
TS_ASSERT( f( 0, 1, 2, 4 ) == f[ idx[ 0 ] ] );
TS_ASSERT( f( 1, 0, 2, 4 ) == f[ idx[ 0 ] ] );
TS_ASSERT( f( 4, 1, 0, 2 ) == f[ idx[ 0 ] ] );
TS_ASSERT( f( 0, 3, 2, 4 ) == f[ idx[ 1 ] ] );
TS_ASSERT( f( 0, 4, 4, 4 ) == f[ idx[ 2 ] ] );
TS_ASSERT( f( 4, 0, 4, 4 ) == f[ idx[ 2 ] ] );
TS_ASSERT( f( 0, 0, 0, 0 ) == f[ idx[ 3 ] ] );
TS_ASSERT( f( 0, 1, 3, 4 ) == f[ idx[ 4 ] ] );
TS_ASSERT( f( 2, 2, 2, 2 ) == f[ idx[ 5 ] ] );
TS_ASSERT( f( 4, 4, 4, 4 ) == f[ idx[ 6 ] ] );
TS_ASSERT( f( 2, 2, 3, 0 ) == f[ idx[ 7 ] ] );
TS_ASSERT( f( 2, 3, 0, 2 ) == f[ idx[ 7 ] ] );
F45 const& w = f;
TS_ASSERT( w( 0, 1, 2, 4 ) == w[ idx[ 0 ] ] );
TS_ASSERT( w( 1, 0, 2, 4 ) == w[ idx[ 0 ] ] );
TS_ASSERT( w( 4, 1, 0, 2 ) == w[ idx[ 0 ] ] );
TS_ASSERT( w( 0, 3, 2, 4 ) == w[ idx[ 1 ] ] );
TS_ASSERT( w( 0, 4, 4, 4 ) == w[ idx[ 2 ] ] );
TS_ASSERT( w( 4, 0, 4, 4 ) == w[ idx[ 2 ] ] );
TS_ASSERT( w( 0, 0, 0, 0 ) == w[ idx[ 3 ] ] );
TS_ASSERT( w( 0, 1, 3, 4 ) == w[ idx[ 4 ] ] );
TS_ASSERT( w( 2, 2, 2, 2 ) == w[ idx[ 5 ] ] );
TS_ASSERT( w( 4, 4, 4, 4 ) == w[ idx[ 6 ] ] );
TS_ASSERT( w( 2, 2, 3, 0 ) == w[ idx[ 7 ] ] );
TS_ASSERT( w( 2, 3, 0, 2 ) == w[ idx[ 7 ] ] );
}
};
/**
* Test all typecasts and copy operators that copy from another type.
*/
class WTensorTypesTest : public CxxTest::TestSuite
{
public:
/**
* Test constructing a WTensorBase from a WTensorBaseSym.
*/
void testCopyContructorBaseFromBaseSym()
{
typedef WTensorBaseSym< 2, 4, double > S24;
typedef WTensorBase< 2, 4, double > T24;
typedef WTensorBaseSym< 1, 4, double > S14;
typedef WTensorBase< 1, 4, double > T14;
typedef WTensorBaseSym< 0, 4, double > S04;
typedef WTensorBase< 0, 4, double > T04;
// construct a symmetric tensor and initialize an asymmetric tensor from it
{
S24 s;
std::size_t idx[ 2 ] = { 0, 3 };
s[ idx ] = -2.0;
idx[ 0 ] = 3;
idx[ 1 ] = 2;
s[ idx ] = 3.0;
TS_ASSERT_THROWS_NOTHING( T24 t = T24( s );
t.getOrder() );
T24 t = T24( s );
TS_ASSERT_EQUALS( t[ idx ], 3.0 );
idx[ 0 ] = 3;
idx[ 1 ] = 0;
TS_ASSERT_EQUALS( t[ idx ], -2.0 );
idx[ 0 ] = 1;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
}
// order = 1 is kind of a special case, as there is only one "permutation" of a single index
{
S14 s;
std::size_t idx[ 1 ] = { 0 };
s[ idx ] = -2.0;
idx[ 0 ] = 3;
s[ idx ] = 3.0;
TS_ASSERT_THROWS_NOTHING( T14 t = T14( s );
t.getOrder() );
T14 t = T14( s );
TS_ASSERT_EQUALS( t[ idx ], 3.0 );
idx[ 0 ] = 0;
TS_ASSERT_EQUALS( t[ idx ], -2.0 );
idx[ 0 ] = 1;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
idx[ 0 ] = 2;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
}
// now test the order = 0 version
{
S04 s;
std::size_t* idx = NULL;
s[ idx ] = 5.0;
TS_ASSERT_THROWS_NOTHING( T04 t = T04( s );
t.getOrder() );
T04 t = T04( s );
TS_ASSERT_EQUALS( t[ idx ], 5.0 );
}
}
/**
* Test assignment of a WTensorBaseSym to a WTensorBase.
*/
void testCopyOperatorBaseFromSym()
{
// same test as the last one, only this time we use the copy operator
typedef WTensorBaseSym< 2, 4, double > S24;
typedef WTensorBase< 2, 4, double > T24;
typedef WTensorBaseSym< 1, 4, double > S14;
typedef WTensorBase< 1, 4, double > T14;
typedef WTensorBaseSym< 0, 4, double > S04;
typedef WTensorBase< 0, 4, double > T04;
{
S24 s;
T24 t;
std::size_t idx[ 2 ] = { 0, 3 };
s[ idx ] = -2.0;
idx[ 0 ] = 3;
idx[ 1 ] = 2;
s[ idx ] = 3.0;
TS_ASSERT_THROWS_NOTHING( t = s );
t = s;
TS_ASSERT_EQUALS( t[ idx ], 3.0 );
idx[ 0 ] = 3;
idx[ 1 ] = 0;
TS_ASSERT_EQUALS( t[ idx ], -2.0 );
idx[ 0 ] = 1;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
}
// order = 1 is kind of a special case, as there is only one "permutation" of a single index
{
S14 s;
T14 t;
std::size_t idx[ 1 ] = { 0 };
s[ idx ] = -2.0;
idx[ 0 ] = 3;
s[ idx ] = 3.0;
TS_ASSERT_THROWS_NOTHING( t = s );
t = s;
TS_ASSERT_EQUALS( t[ idx ], 3.0 );
idx[ 0 ] = 0;
TS_ASSERT_EQUALS( t[ idx ], -2.0 );
idx[ 0 ] = 1;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
idx[ 0 ] = 2;
TS_ASSERT_EQUALS( t[ idx ], 0.0 );
}
// now test the order = 0 version
{
S04 s;
T04 t;
std::size_t* idx = NULL;
s[ idx ] = 5.0;
TS_ASSERT_THROWS_NOTHING( t = s );
t = s;
TS_ASSERT_EQUALS( t[ idx ], 5.0 );
}
}
/**
* Test casts from any tensorbase of order 0 to a value.
*/
void testCastTensorToValue()
{
// create some "scalar tensors" and cast them to their respective Data_T
{
// types
WTensorFunc< WTensorBase, 0, 1, double > td;
WTensorFunc< WTensorBase, 0, 0, float > tf;
WTensorFunc< WTensorBase, 0, 456, int > ti;
// implicitly cast to Data_T
td() = 3.0;
double d = td;
TS_ASSERT_EQUALS( d, 3.0 );
tf() = 3.0f;
float f = tf;
TS_ASSERT_EQUALS( f, 3.0f );
ti() = 3;
int i = ti;
TS_ASSERT_EQUALS( i, 3 );
}
// do the same test with symmetric tensors
{
WTensorFunc< WTensorBase, 0, 1, double > td;
WTensorFunc< WTensorBase, 0, 0, float > tf;
WTensorFunc< WTensorBase, 0, 456, int > ti;
td() = 3.0;
double d = td;
TS_ASSERT_EQUALS( d, 3.0 );
tf() = 3.0f;
float f = tf;
TS_ASSERT_EQUALS( f, 3.0f );
ti() = 3;
int i = ti;
TS_ASSERT_EQUALS( i, 3 );
}
}
/**
* Test casts from any tensorbase of order 1 to a WValue.
*/
void testCastTensorToVector()
{
{
WTensorFunc< WTensorBase, 1, 5, double > t;
t( 0 ) = -9.765;
t( 1 ) = 154.06;
t( 4 ) = -57.0;
WValue< double > v = t;
TS_ASSERT_EQUALS( v.size(), 5 );
TS_ASSERT_EQUALS( v[ 0 ], -9.765 );
TS_ASSERT_EQUALS( v[ 1 ], 154.06 );
TS_ASSERT_EQUALS( v[ 2 ], 0.0 );
TS_ASSERT_EQUALS( v[ 3 ], 0.0 );
TS_ASSERT_EQUALS( v[ 4 ], -57.0 );
}
{
WTensorFunc< WTensorBaseSym, 1, 5, double > t;
t( 0 ) = -9.765;
t( 1 ) = 154.06;
t( 4 ) = -57.0;
WValue< double > v = t;
TS_ASSERT_EQUALS( v.size(), 5 );
TS_ASSERT_EQUALS( v[ 0 ], -9.765 );
TS_ASSERT_EQUALS( v[ 1 ], 154.06 );
TS_ASSERT_EQUALS( v[ 2 ], 0.0 );
TS_ASSERT_EQUALS( v[ 3 ], 0.0 );
TS_ASSERT_EQUALS( v[ 4 ], -57.0 );
}
}
/**
* Test casts from any tensorbase of order 2 to a WMatrix.
*/
void testCastTensorToMatrix()
{
{
WTensorFunc< WTensorBase, 2, 3, double > t;
t( 0, 0 ) = -9.765;
t( 1, 0 ) = 154.06;
t( 2, 2 ) = -57.0;
WMatrix< double > m = t;
TS_ASSERT_EQUALS( m.getNbCols(), 3 );
TS_ASSERT_EQUALS( m.getNbRows(), 3 );
for( std::size_t i = 0; i < 3; ++i )
{
for( std::size_t j = 0; j < 3; ++j )
{
TS_ASSERT_EQUALS( m( i, j ), t( i, j ) );
}
}
}
{
WTensorFunc< WTensorBaseSym, 2, 3, double > t;
t( 0, 0 ) = -9.765;
t( 1, 0 ) = 154.06;
t( 2, 2 ) = -57.0;
WMatrix< double > m = t;
TS_ASSERT_EQUALS( m.getNbCols(), 3 );
TS_ASSERT_EQUALS( m.getNbRows(), 3 );
for( std::size_t i = 0; i < 3; ++i )
{
for( std::size_t j = 0; j < 3; ++j )
{
TS_ASSERT_EQUALS( m( i, j ), t( i, j ) );
}
}
}
}
};
/**
* Test some utility functions.
*/
class WTensorUtilityTest : public CxxTest::TestSuite
{
public:
// the functions testet here are needed for the initialization of the
// index permutation to array position mapping
// note that these functions do not check for errors and are meant for internal use
/**
* Test iteration of indices.
*/
void testIndexIteration()
{
boost::array< std::size_t, 3 > is;
is.assign( 0 ); // is == ( 0, 0, 0 )
std::vector< std::size_t > shouldBe( 3, 0 );
shouldBe[ 2 ] = 1; // shouldBe == ( 0, 0, 1 )
positionIterateOneStep< 3, 3 >( is );
TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
positionIterateOneStep< 3, 3 >( is );
positionIterateOneStep< 3, 3 >( is );
shouldBe[ 1 ] = 1;
shouldBe[ 2 ] = 0; // shouldBe == ( 0, 1, 0 )
TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
// the dim = 2 case is more interesting
positionIterateOneStep< 3, 2 >( is );
positionIterateOneStep< 3, 2 >( is );
shouldBe[ 0 ] = 1;
shouldBe[ 1 ] = 0; // shouldBe == ( 1, 0, 0 )
TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
positionIterateOneStep< 3, 2 >( is );
shouldBe[ 2 ] = 1;
TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
}
/**
* Test sorted iteration of indices.
*/
void testIndexIterationSorted()
{
boost::array< std::size_t, 3 > v;
v.assign( 0 );
std::size_t numIter = WBinom< 5, 3 >::value - 1;
// the indices should always be sorted
for( std::size_t k = 0; k < numIter; ++k )
{
positionIterateSortedOneStep< 3, 3 >( v );
TS_ASSERT( v[ 0 ] <= v[ 1 ] );
TS_ASSERT( v[ 1 ] <= v[ 2 ] );
}
//after iterating numIter times, v should be ( 2, 2, 2 )
TS_ASSERT_EQUALS( v[ 0 ], 2 );
TS_ASSERT_EQUALS( v[ 1 ], 2 );
TS_ASSERT_EQUALS( v[ 2 ], 2 );
// now test the dim = 2 case
v[ 0 ] = v[ 1 ] = v[ 2 ] = 0;
numIter = WBinom< 4, 3 >::value - 1;
// the indices should always be sorted
for( std::size_t k = 0; k < numIter; ++k )
{
positionIterateSortedOneStep< 3, 2 >( v );
TS_ASSERT( v[ 0 ] <= v[ 1 ] );
TS_ASSERT( v[ 1 ] <= v[ 2 ] );
}
//after iterating numIter times, v should be ( 1, 1, 1 )
TS_ASSERT_EQUALS( v[ 0 ], 1 );
TS_ASSERT_EQUALS( v[ 1 ], 1 );
TS_ASSERT_EQUALS( v[ 2 ], 1 );
}
};
// restore WASSERT_AS_CASSERT flag
#ifdef WASSERT_FLAG_CHANGED
#define WASSERT_AS_CASSERT
#undef WASSERT_FLAG_CHANGED
#endif
#endif // WTENSORBASE_TEST_H