OpenWalnut  1.5.0dev
WTensorBase_test.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WTENSORBASE_TEST_H
26 #define WTENSORBASE_TEST_H
27 
28 // unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
29 // note that this may be overwritten by defines in WTensorBase.h
30 // or any files included from there
31 #ifdef WASSERT_AS_CASSERT
32 #define WASSERT_FLAG_CHANGED
33 #undef WASSERT_AS_CASSERT
34 #endif
35 
36 #include <string>
37 #include <vector>
38 
39 #include <cxxtest/TestSuite.h>
40 #include "../WTensorBase.h"
41 #include "../WMatrix.h"
42 #include "../WValue.h"
43 #include "../../WException.h"
44 
45 /**
46  * Test class for WTensorBase.
47  *
48  * \note We cannot test invalid template parameters here, as these should lead to compiler errors.
49  */
50 class WTensorBaseTest : public CxxTest::TestSuite
51 {
52 public:
53  // remember we are testing class templates
54  // we'll need to instantiate every operation/member function at least once
55  // in order to verify that everything compiles
56  /**
57  * The standard constructor should allocate enough memory and set all elements to zero.
58  */
60  {
61  // define tensor types
62  typedef WTensorBase< 1, 2, double > T12;
63  typedef WTensorBase< 2, 3, float > T23;
64  typedef WTensorBase< 4, 2, int > T42;
65  typedef WTensorBase< 6, 3, double > T63;
66  typedef WTensorBase< 0, 0, int > T00;
67 
68  // standard constructor should never throw
69  TS_ASSERT_THROWS_NOTHING( T12 t12 );
70  T12 t12;
71 
72  // number of data elements should be 2
73  // note that dataSize is private, direct access is only for testing purposes
74  std::size_t ds = T12::dataSize;
75  TS_ASSERT_EQUALS( ds, 2 );
76 
77  // test if all elements were set to zero
78  // note that m_data is private
79  for( std::size_t k = 0; k < 2; ++k )
80  {
81  TS_ASSERT_EQUALS( t12.m_data[ k ], 0.0 );
82  }
83 
84  // do the same for some more tensors
85  TS_ASSERT_THROWS_NOTHING( T23 t23 );
86  T23 t23;
87  ds = T23::dataSize;
88  TS_ASSERT_EQUALS( ds, 9 );
89  for( std::size_t k = 0; k < 9; ++k )
90  {
91  TS_ASSERT_EQUALS( t23.m_data[ k ], 0.0f );
92  }
93 
94  TS_ASSERT_THROWS_NOTHING( T42 t42 );
95  T42 t42;
96  ds = T42::dataSize;
97  TS_ASSERT_EQUALS( ds, 16 );
98  for( std::size_t k = 0; k < 16; ++k )
99  {
100  TS_ASSERT_EQUALS( t42.m_data[ k ], 0 );
101  }
102 
103  TS_ASSERT_THROWS_NOTHING( T63 t63 );
104  T63 t63;
105  ds = T63::dataSize;
106  TS_ASSERT_EQUALS( ds, 729 );
107  for( std::size_t k = 0; k < 729; ++k )
108  {
109  TS_ASSERT_EQUALS( t63.m_data[ k ], 0.0 );
110  }
111 
112  TS_ASSERT_THROWS_NOTHING( T00 t00 );
113  T00 t00;
114  TS_ASSERT_EQUALS( t00.m_data, 0 );
115  }
116 
117  /**
118  * The copy constructor should copy all values.
119  */
121  {
122  typedef WTensorBase< 2, 3, int > T23;
123  typedef WTensorBase< 5, 4, double > T54;
124  typedef WTensorBase< 3, 3, float > T33;
125  typedef WTensorBase< 0, 2, int > T02;
126 
127  {
128  // create a tensor and fill in some values
129  T23 t;
130 
131  t.m_data[ 2 ] = 3;
132  t.m_data[ 3 ] = 2;
133  t.m_data[ 7 ] = -1;
134 
135  // also test the first and last elements to avoid off-by-one error
136  t.m_data[ 8 ] = -25;
137  t.m_data[ 0 ] = 26;
138 
139  TS_ASSERT_THROWS_NOTHING( T23 m( t ) );
140  T23 m( t );
141 
142  // the data arrays of t and m should be the same
143  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 9 * sizeof( int ) );
144 
145  // copy from a const ref
146  T23 const& w = t;
147  T23 const r( w );
148 
149  // the data arrays of r and t should be the same
150  TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 9 * sizeof( int ) );
151  }
152 
153  // now test some other tensors
154  {
155  T54 t;
156 
157  t.m_data[ 2 ] = 3.0;
158  t.m_data[ 3 ] = 2.4;
159  t.m_data[ 7 ] = -1.0;
160  t.m_data[ 675 ] = 20.0;
161  t.m_data[ 239 ] = -134.243;
162  t.m_data[ 964 ] = 567.534;
163  t.m_data[ 1001 ] = -5.4276;
164  t.m_data[ 543 ] = 1233.4;
165  t.m_data[ 827 ] = -9878.765;
166 
167  t.m_data[ 1023 ] = -265.63;
168  t.m_data[ 0 ] = 2453.0;
169 
170  TS_ASSERT_THROWS_NOTHING( T54 m( t ) );
171  T54 m( t );
172 
173  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 1024 * sizeof( double ) );
174  }
175 
176  {
177  T33 t;
178 
179  t.m_data[ 2 ] = 3.0f;
180  t.m_data[ 3 ] = 2.0f;
181  t.m_data[ 7 ] = -1.0f;
182  t.m_data[ 16 ] = 200.0f;
183  t.m_data[ 23 ] = -13.4243f;
184  t.m_data[ 19 ] = 5675.34f;
185  t.m_data[ 10 ] = -54276.0f;
186  t.m_data[ 24 ] = 123.34f;
187  t.m_data[ 18 ] = -98787.65f;
188 
189  t.m_data[ 26 ] = -26.563f;
190  t.m_data[ 0 ] = 245.3f;
191 
192  TS_ASSERT_THROWS_NOTHING( T33 m( t ) );
193  T33 m( t );
194 
195  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
196  }
197 
198  {
199  T02 t;
200  t.m_data = -5;
201 
202  TS_ASSERT_THROWS_NOTHING( T02 m( t ) );
203  T02 m( t );
204 
205  TS_ASSERT_EQUALS( m.m_data, t.m_data );
206  }
207  }
208 
209  /**
210  * Test the copy operator.
211  */
213  {
214  // this is essentially the same test as with the copy constructor,
215  // only this time we use the copy operator
216  typedef WTensorBase< 2, 3, int > T23;
217  typedef WTensorBase< 5, 4, double > T54;
218  typedef WTensorBase< 3, 3, float > T33;
219  typedef WTensorBase< 0, 3, double > T03;
220 
221  {
222  // create a tensor and fill in some values
223  T23 t, m;
224 
225  t.m_data[ 2 ] = 3;
226  t.m_data[ 3 ] = 2;
227  t.m_data[ 7 ] = -1;
228 
229  // also test the first and last elements to avoid off-by-one error
230  t.m_data[ 8 ] = -25;
231  t.m_data[ 0 ] = 26;
232 
233  // force operator =
234  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
235  m.operator = ( t );
236 
237  // the data arrays of t and m should be the same
238  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 9 * sizeof( int ) );
239 
240  // copy from a const ref
241  T23 const& w = t;
242  T23 r;
243  r.operator = ( w );
244 
245  // the data arrays of r and t should be the same
246  TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 9 * sizeof( int ) );
247  }
248 
249  // now test some other tensors
250  {
251  T54 t, m;
252 
253  t.m_data[ 2 ] = 3.0;
254  t.m_data[ 3 ] = 2.4;
255  t.m_data[ 7 ] = -1.0;
256  t.m_data[ 675 ] = 20.0;
257  t.m_data[ 239 ] = -134.243;
258  t.m_data[ 964 ] = 567.534;
259  t.m_data[ 1001 ] = -5.4276;
260  t.m_data[ 543 ] = 1233.4;
261  t.m_data[ 827 ] = -9878.765;
262 
263  t.m_data[ 1023 ] = -265.63;
264  t.m_data[ 0 ] = 2453.0;
265 
266  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
267  m.operator = ( t );
268 
269  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 1024 * sizeof( double ) );
270  }
271 
272  {
273  T33 t, m;
274 
275  t.m_data[ 2 ] = 3.0f;
276  t.m_data[ 3 ] = 2.0f;
277  t.m_data[ 7 ] = -1.0f;
278  t.m_data[ 16 ] = 200.0f;
279  t.m_data[ 23 ] = -13.4243f;
280  t.m_data[ 19 ] = 5675.34f;
281  t.m_data[ 10 ] = -54276.0f;
282  t.m_data[ 24 ] = 123.34f;
283  t.m_data[ 18 ] = -98787.65f;
284 
285  t.m_data[ 26 ] = -26.563f;
286  t.m_data[ 0 ] = 245.3f;
287 
288  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
289  m.operator = ( t );
290 
291  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
292  }
293 
294  {
295  T03 t;
296 
297  t.m_data = -4;
298 
299  TS_ASSERT_THROWS_NOTHING( T03 m( t ) );
300 
301  T03 m( t );
302 
303  TS_ASSERT_EQUALS( m.m_data, t.m_data );
304  }
305 
306  // test multiple assignments in one statement
307  {
308  T33 t, m, u, z;
309 
310  t.m_data[ 2 ] = 3.0f;
311  t.m_data[ 3 ] = 2.0f;
312  t.m_data[ 7 ] = -1.0f;
313  t.m_data[ 16 ] = 200.0f;
314  t.m_data[ 23 ] = -13.4243f;
315  t.m_data[ 19 ] = 5675.34f;
316  t.m_data[ 10 ] = -54276.0f;
317  t.m_data[ 24 ] = 123.34f;
318  t.m_data[ 18 ] = -98787.65f;
319 
320  t.m_data[ 26 ] = -26.563f;
321  t.m_data[ 0 ] = 245.3f;
322 
323  z = u = m = t;
324 
325  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( float ) );
326  TS_ASSERT_SAME_DATA( &m.m_data[ 0 ], &u.m_data[ 0 ], 27 * sizeof( float ) );
327  TS_ASSERT_SAME_DATA( &u.m_data[ 0 ], &z.m_data[ 0 ], 27 * sizeof( float ) );
328  }
329  }
330 
331  /**
332  * Test if the copy operator handles assignments of variables to themselves correctly.
333  */
335  {
336  typedef WTensorBase< 3, 3, double > T33;
337  typedef WTensorBase< 0, 0, int > T00;
338 
339  {
340  T33 t;
341 
342  // set some elements
343  t.m_data[ 0 ] = 347.856;
344  t.m_data[ 26 ] = -4.0;
345  t.m_data[ 4 ] = -564.4;
346 
347  // create a copy of t for comparison
348  T33 m( t );
349 
350  // now try copying t onto itself
351  // this should not throw anything, as the WTensor documentation states that Data_T
352  // ( in this case double ) shouldn't throw on assignment
353  // this is also the reason that there is no test with a datatype whose operator = throws
354  TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
355  t.operator = ( t );
356 
357  // t and m should still be equal
358  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 27 * sizeof( double ) );
359  }
360 
361  {
362  T00 t;
363 
364  t.m_data = -57;
365 
366  T00 m( t );
367 
368  TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
369  t.operator = ( t );
370 
371  TS_ASSERT_EQUALS( m.m_data, t.m_data );
372  }
373  }
374 
375  /**
376  * Test if the access operator correctly throws Exceptions only when the input indices are invalid.
377  */
379  {
380  typedef WTensorBase< 4, 4, double > T44;
381  typedef WTensorBase< 1, 4, int > T14;
382  typedef WTensorBase< 3, 2, float > T32;
383  typedef WTensorBase< 0, 654, int > T0;
384 
385  {
386  // instantiate a tensor
387  T44 t;
388 
389  // now create an index array
390  int idx[] = { 0, 1, 2, 3 };
391  // this should work
392  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
393 
394  // try some invalid indices, indices of a tensor of dimension 4 may only be 0, 1, 2 or 3
395  idx[ 3 ] = 4; // idx == [ 0, 1, 2, 4 ]
396  TS_ASSERT_THROWS( t[ idx ], const WException& );
397 
398  // indices are cast to std::size_t (which should be unsigned)
399  idx[ 3 ] = -1; // idx == [ 0, 1, 2, -1 ]
400  TS_ASSERT_THROWS( t[ idx ], const WException& );
401 
402  idx[ 3 ] = 2;
403  idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
404  TS_ASSERT_THROWS( t[ idx ], const WException& );
405 
406  idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
407  TS_ASSERT_THROWS( t[ idx ], const WException& );
408 
409  // some indices that should be valid
410  idx[ 0 ] = 3;
411  idx[ 1 ] = 3;
412  idx[ 2 ] = 3;
413  idx[ 3 ] = 3;
414  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
415 
416  idx[ 0 ] = 0;
417  idx[ 1 ] = 0;
418  idx[ 2 ] = 0;
419  idx[ 3 ] = 0;
420  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
421 
422  idx[ 0 ] = 1;
423  idx[ 1 ] = 3;
424  idx[ 2 ] = 2;
425  idx[ 3 ] = 1;
426  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
427 
428  idx[ 0 ] = 0;
429  idx[ 1 ] = 0;
430  idx[ 2 ] = 2;
431  idx[ 3 ] = 0;
432  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
433 
434  // a larger array should also work, all unneeded values should be ignored
435  std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
436  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
437 
438  // note that the length of the index array cannot be checked
439  }
440 
441  // now do the same for another tensor
442  {
443  T14 t;
444 
445  int idx[] = { 0 };
446  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
447 
448  idx[ 0 ] = 4;
449  TS_ASSERT_THROWS( t[ idx ], const WException& );
450 
451  idx[ 0 ] = 4537;
452  TS_ASSERT_THROWS( t[ idx ], const WException& );
453 
454  idx[ 0 ] = 1;
455  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
456 
457  idx[ 0 ] = 2;
458  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
459 
460  idx[ 0 ] = 3;
461  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
462 
463  std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
464  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
465  }
466 
467  // and another one
468  {
469  T32 t;
470 
471  // note that only values 0 and 1 are valid indices
472  int idx[] = { 0, 1, 1 };
473  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
474 
475  idx[ 2 ] = 3;
476  TS_ASSERT_THROWS( t[ idx ], const WException& );
477 
478  idx[ 0 ] = -1;
479  TS_ASSERT_THROWS( t[ idx ], const WException& );
480 
481  idx[ 2 ] = 2;
482  idx[ 0 ] = 4537;
483  TS_ASSERT_THROWS( t[ idx ], const WException& );
484 
485  idx[ 0 ] = 0;
486  idx[ 1 ] = 1;
487  idx[ 2 ] = 0;
488  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
489 
490  idx[ 0 ] = 0;
491  idx[ 1 ] = 0;
492  idx[ 2 ] = 0;
493  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
494 
495  idx[ 0 ] = 1;
496  idx[ 1 ] = 0;
497  idx[ 2 ] = 1;
498  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
499 
500  idx[ 0 ] = 0;
501  idx[ 1 ] = 0;
502  idx[ 2 ] = 1;
503  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
504 
505  std::size_t idx2[] = { 0, 1, 1, 3, 8, 54643 };
506  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
507  }
508 
509  {
510  T0 t;
511 
512  std::size_t idx[] = { 0, 1 };
513  std::size_t* idx2 = NULL;
514 
515  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
516  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
517  }
518  }
519 
520  /**
521  * Test if the array access operator returns the correct elements.
522  */
524  {
525  typedef WTensorBase< 2, 3, std::size_t > T23;
526  typedef WTensorBase< 3, 4, std::size_t > T34;
527  typedef WTensorBase< 0, 1, std::size_t > T01;
528 
529  // now test if operator [] returns the correct elements
530  {
531  // create a new tensor
532  T23 t;
533 
534  // enumerate all elements
535  for( std::size_t k = 0; k < T23::dataSize; ++k )
536  {
537  t.m_data[ k ] = k;
538  }
539 
540  // the order of elements should be
541  // 0 1 2
542  // 3 4 5
543  // 6 7 8
544  std::size_t idx[] = { 0, 0 };
545  TS_ASSERT_EQUALS( t[ idx ], 0 );
546  idx[ 1 ] = 1; // idx == [ 0, 1 ]
547  TS_ASSERT_EQUALS( t[ idx ], 1 );
548  idx[ 1 ] = 2; // idx == [ 0, 2 ]
549  TS_ASSERT_EQUALS( t[ idx ], 2 );
550  idx[ 0 ] = 1; // idx == [ 1, 2 ]
551  TS_ASSERT_EQUALS( t[ idx ], 5 );
552  idx[ 1 ] = 1; // idx == [ 1, 1 ]
553  TS_ASSERT_EQUALS( t[ idx ], 4 );
554  idx[ 1 ] = 0; // idx == [ 1, 0 ]
555  TS_ASSERT_EQUALS( t[ idx ], 3 );
556  idx[ 0 ] = 2; // idx == [ 2, 0 ]
557  TS_ASSERT_EQUALS( t[ idx ], 6 );
558  idx[ 1 ] = 1; // idx == [ 2, 1 ]
559  TS_ASSERT_EQUALS( t[ idx ], 7 );
560  idx[ 1 ] = 2; // idx == [ 2, 2 ]
561  TS_ASSERT_EQUALS( t[ idx ], 8 );
562 
563  // const refs should also work
564  T23 const& w = t;
565  idx[ 0 ] = idx[ 1 ] = 0;
566  TS_ASSERT_EQUALS( w[ idx ], 0 );
567  idx[ 1 ] = 1; // idx == [ 0, 1 ]
568  TS_ASSERT_EQUALS( w[ idx ], 1 );
569  idx[ 1 ] = 2; // idx == [ 0, 2 ]
570  TS_ASSERT_EQUALS( w[ idx ], 2 );
571  idx[ 0 ] = 1; // idx == [ 1, 2 ]
572  TS_ASSERT_EQUALS( w[ idx ], 5 );
573  idx[ 1 ] = 1; // idx == [ 1, 1 ]
574  TS_ASSERT_EQUALS( w[ idx ], 4 );
575  idx[ 1 ] = 0; // idx == [ 1, 0 ]
576  TS_ASSERT_EQUALS( w[ idx ], 3 );
577  idx[ 0 ] = 2; // idx == [ 2, 0 ]
578  TS_ASSERT_EQUALS( w[ idx ], 6 );
579  idx[ 1 ] = 1; // idx == [ 2, 1 ]
580  TS_ASSERT_EQUALS( w[ idx ], 7 );
581  idx[ 1 ] = 2; // idx == [ 2, 2 ]
582  TS_ASSERT_EQUALS( w[ idx ], 8 );
583  }
584  {
585  // create a new tensor
586  T34 t;
587 
588  // enumerate all elements
589  for( std::size_t k = 0; k < T34::dataSize; ++k )
590  {
591  t.m_data[ k ] = k;
592  }
593 
594  // order should be
595  //
596  // idx[0] == 0 idx[0] == 1 idx[0] == 2 idx[0] == 3
597  //
598  // 0 1 2 3 16 17 18 19 32 33 34 35 48 49 50 51 idx[1] == 0
599  // 4 5 6 7 20 21 22 23 36 37 38 39 52 53 54 55 idx[1] == 1
600  // 8 9 10 11 24 25 26 27 40 41 42 43 56 57 58 59 idx[1] == 2
601  //12 13 14 15 28 29 30 31 44 45 46 47 60 61 62 63 idx[1] == 3
602 
603  std::size_t idx[] = { 0, 0, 0 };
604  TS_ASSERT_EQUALS( t[ idx ], 0 );
605  idx[ 1 ] = 2; // idx == [ 0, 2, 0 ]
606  TS_ASSERT_EQUALS( t[ idx ], 8 );
607  idx[ 2 ] = 3; // idx == [ 0, 2, 3 ]
608  TS_ASSERT_EQUALS( t[ idx ], 11 );
609  idx[ 0 ] = 1; // idx == [ 1, 2, 3 ]
610  TS_ASSERT_EQUALS( t[ idx ], 27 );
611  idx[ 1 ] = 1; // idx == [ 1, 1, 3 ]
612  TS_ASSERT_EQUALS( t[ idx ], 23 );
613  idx[ 0 ] = 3; // idx == [ 3, 1, 3 ]
614  TS_ASSERT_EQUALS( t[ idx ], 55 );
615  idx[ 2 ] = 0; // idx == [ 3, 1, 0 ]
616  TS_ASSERT_EQUALS( t[ idx ], 52 );
617  idx[ 1 ] = 3; // idx == [ 3, 3, 0 ]
618  TS_ASSERT_EQUALS( t[ idx ], 60 );
619  idx[ 1 ] = 2; // idx == [ 3, 2, 0 ]
620  TS_ASSERT_EQUALS( t[ idx ], 56 );
621  }
622 
623  // zero order tensor
624  {
625  T01 t;
626  t.m_data = 65;
627 
628  std::size_t idx[] = { 0, 1 };
629  std::size_t* idx2 = NULL;
630 
631  TS_ASSERT_EQUALS( t[ idx ], 65 );
632  TS_ASSERT_EQUALS( t[ idx2 ], 65 );
633  }
634  }
635 
636  /**
637  * Test the std::vector version of operator [] for correct handling of
638  * various input vector sizes.
639  */
641  {
642  typedef WTensorBase< 4, 4, double > T44;
643  typedef WTensorBase< 1, 4, double > T14;
644  typedef WTensorBase< 6, 2, double > T62;
645  typedef WTensorBase< 0, 1, double > T01;
646 
647  {
648  T44 t;
649 
650  // test a vector of invalid size
651  std::vector< int > idx;
652 
653  // this should throw a WException (using the WAssert macro)
654  TS_ASSERT_THROWS( t[ idx ], const WException& );
655 
656  idx.push_back( 0 ); // idx == [ 0 ]
657  TS_ASSERT_THROWS( t[ idx ], const WException& );
658  idx.push_back( 1 ); // idx == [ 0, 1 ]
659  TS_ASSERT_THROWS( t[ idx ], const WException& );
660  idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
661  TS_ASSERT_THROWS( t[ idx ], const WException& );
662 
663  idx.push_back( 3 ); // idx == [ 0, 1, 2, 3 ]
664  // now idx has the correct size and all valid indices
665  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
666 
667  // a larger vector should also work
668  idx.push_back( 456 ); // idx == [ 0, 0, 2, 0, 456 ]
669 
670  // this should simply ignore all values after the 4th
671  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
672 
673  idx.push_back( -1 );
674  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
675 
676  // bounds checking on the indices is done by the array version of operator [],
677  // which is called by the vector version
678  // I'll add some tests here though, in case this changes in the future
679  idx[ 0 ] = -1;
680  TS_ASSERT_THROWS( t[ idx ], const WException& );
681 
682  idx[ 0 ] = 4;
683  TS_ASSERT_THROWS( t[ idx ], const WException& );
684 
685  idx[ 0 ] = 3;
686  idx[ 3 ] = -1;
687  TS_ASSERT_THROWS( t[ idx ], const WException& );
688 
689  idx[ 3 ] = 4;
690  TS_ASSERT_THROWS( t[ idx ], const WException& );
691 
692  idx[ 3 ] = 2;
693  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
694  }
695  {
696  T14 t;
697 
698  std::vector< int > idx;
699  TS_ASSERT_THROWS( t[ idx ], const WException& );
700 
701  idx.push_back( 0 ); // idx == [ 0 ]
702  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
703 
704  idx.push_back( 3 ); // idx == [ 0, 3 ]
705  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
706 
707  idx.push_back( 456 ); // idx == [ 0, 3, 456 ]
708  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
709 
710  idx.push_back( -1 );
711  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
712  }
713  {
714  T62 t;
715 
716  std::vector< int > idx;
717  TS_ASSERT_THROWS( t[ idx ], const WException& );
718 
719  idx.push_back( 0 ); // idx == [ 0 ]
720  TS_ASSERT_THROWS( t[ idx ], const WException& );
721  idx.push_back( 1 ); // idx == [ 0, 1 ]
722  TS_ASSERT_THROWS( t[ idx ], const WException& );
723  idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
724  TS_ASSERT_THROWS( t[ idx ], const WException& );
725  idx.push_back( 1 );
726  TS_ASSERT_THROWS( t[ idx ], const WException& );
727  idx.push_back( 1 );
728  TS_ASSERT_THROWS( t[ idx ], const WException& );
729  idx.push_back( 0 );
730  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
731 
732  idx.push_back( 456 );
733  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
734 
735  idx.push_back( -1 );
736  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
737  }
738  {
739  T01 t;
740 
741  std::vector< int > idx;
742 
743  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
744 
745  idx.push_back( 4 );
746  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
747 
748  T01 const w;
749  TS_ASSERT_THROWS_NOTHING( w[ idx ] );
750  }
751  }
752 
753  /**
754  * Test if operator == works correctly.
755  */
757  {
758  typedef WTensorBase< 1, 7, double > T17;
759  typedef WTensorBase< 3, 2, int > T32;
760  typedef WTensorBase< 0, 0, float > T00;
761 
762  {
763  T17 t, m;
764 
765  // two tensors of the same type should be initialized to the same values
766  TS_ASSERT( t == m );
767  TS_ASSERT( m == t );
768 
769  // a tensor should always be equal to itself
770  TS_ASSERT( t == t );
771  TS_ASSERT( m == m );
772 
773  // change some values
774  std::size_t idx[] = { 4 };
775  t[ idx ] = 5.0;
776 
777  TS_ASSERT( !( t == m ) );
778  TS_ASSERT( !( m == t ) );
779  TS_ASSERT( t == t );
780  TS_ASSERT( m == m );
781 
782  m[ idx ] = 5.0;
783 
784  TS_ASSERT( t == m );
785  TS_ASSERT( m == t );
786  TS_ASSERT( t == t );
787  TS_ASSERT( m == m );
788 
789  idx[ 0 ] = 2;
790  m[ idx ] = 543543.0;
791 
792  TS_ASSERT( !( t == m ) );
793  TS_ASSERT( !( m == t ) );
794  TS_ASSERT( t == t );
795  TS_ASSERT( m == m );
796 
797  // copying a tensor should lead to the respective tensors being equal
798  t = m;
799  TS_ASSERT( t == m );
800  TS_ASSERT( m == t );
801  TS_ASSERT( t == t );
802  TS_ASSERT( m == m );
803 
804  // test const
805  T17 const ct, cm;
806  TS_ASSERT( ct == cm );
807  TS_ASSERT( cm == ct );
808  TS_ASSERT( ct == ct );
809  TS_ASSERT( cm == cm );
810  }
811  {
812  T32 t, m;
813 
814  std::size_t idx[] = { 0, 0, 0 };
815 
816  // two tensors of the same type should be initialized to the same values
817  TS_ASSERT( t == m );
818  TS_ASSERT( m == t );
819 
820  // a tensor should always be equal to itself
821  TS_ASSERT( t == t );
822  TS_ASSERT( m == m );
823 
824  idx[ 1 ] = 1;
825 
826  m[ idx ] = -5643;
827 
828  TS_ASSERT( !( t == m ) );
829  TS_ASSERT( !( m == t ) );
830  TS_ASSERT( t == t );
831  TS_ASSERT( m == m );
832 
833  t = m;
834 
835  TS_ASSERT( t == m );
836  TS_ASSERT( m == t );
837  TS_ASSERT( t == t );
838  TS_ASSERT( m == m );
839 
840  idx[ 1 ] = 0;
841 
842  t[ idx ] = 564;
843 
844  TS_ASSERT( !( t == m ) );
845  TS_ASSERT( !( m == t ) );
846  TS_ASSERT( t == t );
847  TS_ASSERT( m == m );
848 
849  t.m_data[ 0 ] = 5;
850  t.m_data[ 1 ] = -65464;
851  t.m_data[ 2 ] = 89;
852  t.m_data[ 3 ] = 3276;
853  t.m_data[ 4 ] = -3276;
854  t.m_data[ 5 ] = 47;
855  t.m_data[ 6 ] = 68;
856  t.m_data[ 7 ] = -239;
857 
858  m.m_data[ 0 ] = -5;
859  m.m_data[ 1 ] = 65464;
860  m.m_data[ 2 ] = -89;
861  m.m_data[ 3 ] = -3276;
862  m.m_data[ 4 ] = 3276;
863  m.m_data[ 5 ] = -47;
864  m.m_data[ 6 ] = -68;
865  m.m_data[ 7 ] = 239;
866 
867  TS_ASSERT( !( t == m ) );
868  TS_ASSERT( !( m == t ) );
869  TS_ASSERT( t == t );
870  TS_ASSERT( m == m );
871  }
872  {
873  T00 t, m;
874 
875  // two tensors of the same type should be initialized to the same values
876  TS_ASSERT( t == m );
877  TS_ASSERT( m == t );
878 
879  // a tensor should always be equal to itself
880  TS_ASSERT( t == t );
881  TS_ASSERT( m == m );
882 
883  t.m_data = 2;
884 
885  TS_ASSERT( !( t == m ) );
886  TS_ASSERT( !( m == t ) );
887  TS_ASSERT( t == t );
888  TS_ASSERT( m == m );
889 
890  m.m_data = 2;
891 
892  TS_ASSERT( t == m );
893  TS_ASSERT( m == t );
894  TS_ASSERT( t == t );
895  TS_ASSERT( m == m );
896  }
897  }
898 
899  /**
900  * Test if operator != works correctly.
901  */
903  {
904  typedef WTensorBase< 3, 3, int > T33;
905  typedef WTensorBase< 0, 0, int > T00;
906 
907  {
908  T33 t, m;
909 
910  // two new instances should never not be equal
911  TS_ASSERT( !( t != m ) );
912  TS_ASSERT( !( m != t ) );
913 
914  // a tensor should never not be equal to itself
915  TS_ASSERT( !( t != t ) );
916  TS_ASSERT( !( m != m ) );
917 
918  // change some elements
919  t.m_data[ 23 ] = -23467;
920 
921  TS_ASSERT( t != m );
922  TS_ASSERT( m != t );
923  TS_ASSERT( !( t != t ) );
924  TS_ASSERT( !( m != m ) );
925 
926  t = m;
927  TS_ASSERT( !( t != m ) );
928  TS_ASSERT( !( m != t ) );
929 
930  t.m_data[ 0 ] = 1;
931  TS_ASSERT( t != m );
932  TS_ASSERT( m != t );
933  TS_ASSERT( !( t != t ) );
934  TS_ASSERT( !( m != m ) );
935 
936  t = m;
937  TS_ASSERT( !( t != m ) );
938  TS_ASSERT( !( m != t ) );
939  TS_ASSERT( !( t != t ) );
940  TS_ASSERT( !( m != m ) );
941 
942  t.m_data[ 26 ] = -1;
943  TS_ASSERT( t != m );
944  TS_ASSERT( m != t );
945  TS_ASSERT( !( t != t ) );
946  TS_ASSERT( !( m != m ) );
947 
948  // test const
949  T33 const ct, cm;
950  TS_ASSERT( !( ct != cm ) );
951  TS_ASSERT( !( cm != ct ) );
952  TS_ASSERT( !( ct != ct ) );
953  TS_ASSERT( !( cm != cm ) );
954  }
955  {
956  T00 t, m;
957 
958  TS_ASSERT( !( t != m ) );
959  TS_ASSERT( !( m != t ) );
960  TS_ASSERT( !( t != t ) );
961  TS_ASSERT( !( m != m ) );
962 
963  t.m_data = 2;
964 
965  TS_ASSERT( t != m );
966  TS_ASSERT( m != t );
967  TS_ASSERT( !( t != t ) );
968  TS_ASSERT( !( m != m ) );
969 
970  m.m_data = 2;
971 
972  TS_ASSERT( !( t != m ) );
973  TS_ASSERT( !( m != t ) );
974  TS_ASSERT( !( t != t ) );
975  TS_ASSERT( !( m != m ) );
976  }
977  }
978 };
979 
980 /**
981  * Test class for WTensorBaseSym.
982  *
983  * \note We cannot test invalid template parameters here, as these should lead to compiler errors.
984  */
985 class WTensorBaseSymTest : public CxxTest::TestSuite
986 {
987 public:
988  /**
989  * The standard constructor should allocate enough memory and set all elements to zero.
990  */
992  {
993  // define tensor types
994  typedef WTensorBaseSym< 1, 2, double > T12;
995  typedef WTensorBaseSym< 2, 3, float > T23;
996  typedef WTensorBaseSym< 4, 2, int > T42;
997  typedef WTensorBaseSym< 6, 3, double > T63;
998  typedef WTensorBaseSym< 0, 0, int > T00;
999 
1000  // standard constructor should never throw
1001  TS_ASSERT_THROWS_NOTHING( T12 t12 );
1002  T12 t12;
1003 
1004  // number of data elements should be 2
1005  // note that dataSize is private, direct access is only for testing purposes
1006  std::size_t ds = T12::dataSize;
1007  TS_ASSERT_EQUALS( ds, 2 );
1008 
1009  // test if all elements were set to zero
1010  // note that m_data is private
1011  for( std::size_t k = 0; k < 2; ++k )
1012  {
1013  TS_ASSERT_EQUALS( t12.m_data[ k ], 0.0 );
1014  }
1015 
1016  // do the same for some more tensors
1017  // symmetric tensors need less memory, 6 instead of 9 values in this case
1018  TS_ASSERT_THROWS_NOTHING( T23 t23 );
1019  T23 t23;
1020  ds = T23::dataSize;
1021  TS_ASSERT_EQUALS( ds, 6 );
1022  for( std::size_t k = 0; k < 6; ++k )
1023  {
1024  TS_ASSERT_EQUALS( t23.m_data[ k ], 0.0f );
1025  }
1026 
1027  TS_ASSERT_THROWS_NOTHING( T42 t42 );
1028  T42 t42;
1029  ds = T42::dataSize;
1030  TS_ASSERT_EQUALS( ds, 5 );
1031  for( std::size_t k = 0; k < 5; ++k )
1032  {
1033  TS_ASSERT_EQUALS( t42.m_data[ k ], 0 );
1034  }
1035 
1036  TS_ASSERT_THROWS_NOTHING( T63 t63 );
1037  T63 t63;
1038  ds = T63::dataSize;
1039  TS_ASSERT_EQUALS( ds, 28 );
1040  for( std::size_t k = 0; k < 28; ++k )
1041  {
1042  TS_ASSERT_EQUALS( t63.m_data[ k ], 0.0 );
1043  }
1044 
1045  TS_ASSERT_THROWS_NOTHING( T00 t00 );
1046  T00 t00;
1047  TS_ASSERT_EQUALS( t00.m_data, 0 );
1048  }
1049 
1050  /**
1051  * The copy constructor should copy all values.
1052  */
1054  {
1055  typedef WTensorBaseSym< 2, 3, int > T23;
1056  typedef WTensorBaseSym< 5, 4, double > T54;
1057  typedef WTensorBaseSym< 3, 3, float > T33;
1058  typedef WTensorBaseSym< 0, 2, int > T02;
1059 
1060  {
1061  // create a tensor and fill in some values
1062  // use direct access to the m_data array as access operators aren't tested yet
1063  T23 t;
1064 
1065  t.m_data[ 2 ] = 3;
1066  t.m_data[ 3 ] = 2;
1067  t.m_data[ 4 ] = -1;
1068 
1069  // also test the first and last elements to avoid off-by-one error
1070  t.m_data[ 5 ] = -25;
1071  t.m_data[ 0 ] = 26;
1072 
1073  TS_ASSERT_THROWS_NOTHING( T23 m( t ) );
1074  T23 m( t );
1075 
1076  // the data arrays of t and m should be the same
1077  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 6 * sizeof( int ) );
1078 
1079  // copy from a const ref
1080  T23 const& w = t;
1081  T23 const r( w );
1082 
1083  // the data arrays of r and t should be the same
1084  TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 6 * sizeof( int ) );
1085  }
1086 
1087  // now test some other tensors
1088  {
1089  T54 t;
1090 
1091  t.m_data[ 2 ] = 3.0;
1092  t.m_data[ 3 ] = 2.4;
1093  t.m_data[ 7 ] = -1.0;
1094  t.m_data[ 33 ] = 20.0;
1095  t.m_data[ 21 ] = -134.243;
1096  t.m_data[ 54 ] = 567.534;
1097  t.m_data[ 48 ] = -5.4276;
1098  t.m_data[ 34 ] = 1233.4;
1099  t.m_data[ 27 ] = -9878.765;
1100 
1101  t.m_data[ 55 ] = -265.63;
1102  t.m_data[ 0 ] = 2453.0;
1103 
1104  TS_ASSERT_THROWS_NOTHING( T54 m( t ) );
1105  T54 m( t );
1106 
1107  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 56 * sizeof( double ) );
1108  }
1109 
1110  {
1111  T33 t;
1112 
1113  t.m_data[ 2 ] = 3.0f;
1114  t.m_data[ 3 ] = 2.0f;
1115  t.m_data[ 7 ] = -1.0f;
1116  t.m_data[ 1 ] = -13.4243f;
1117  t.m_data[ 5 ] = 5675.34f;
1118  t.m_data[ 6 ] = -54276.0f;
1119  t.m_data[ 4 ] = 123.34f;
1120  t.m_data[ 8 ] = -98787.65f;
1121 
1122  t.m_data[ 9 ] = -26.563f;
1123  t.m_data[ 0 ] = 245.3f;
1124 
1125  TS_ASSERT_THROWS_NOTHING( T33 m( t ) );
1126  T33 m( t );
1127 
1128  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
1129  }
1130 
1131  // test multiple assignments in one statement
1132  {
1133  T33 t, m, u, z;
1134 
1135  t.m_data[ 2 ] = 3.0f;
1136  t.m_data[ 3 ] = 2.0f;
1137  t.m_data[ 7 ] = -1.0f;
1138  t.m_data[ 1 ] = -13.4243f;
1139  t.m_data[ 5 ] = 5675.34f;
1140  t.m_data[ 6 ] = -54276.0f;
1141  t.m_data[ 4 ] = 123.34f;
1142  t.m_data[ 8 ] = -98787.65f;
1143 
1144  t.m_data[ 9 ] = -26.563f;
1145  t.m_data[ 0 ] = 245.3f;
1146 
1147  z = u = m = t;
1148 
1149  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
1150  TS_ASSERT_SAME_DATA( &m.m_data[ 0 ], &u.m_data[ 0 ], 10 * sizeof( float ) );
1151  TS_ASSERT_SAME_DATA( &u.m_data[ 0 ], &z.m_data[ 0 ], 10 * sizeof( float ) );
1152  }
1153 
1154  {
1155  T02 t;
1156  t.m_data = -5;
1157 
1158  TS_ASSERT_THROWS_NOTHING( T02 m( t ) );
1159  T02 m( t );
1160 
1161  TS_ASSERT_EQUALS( m.m_data, t.m_data );
1162  }
1163  }
1164 
1165  /**
1166  * Test the copy operator.
1167  */
1169  {
1170  // this is essentially the same test as with the copy constructor,
1171  // only this time we use the copy operator
1172 
1173  typedef WTensorBaseSym< 2, 3, int > T23;
1174  typedef WTensorBaseSym< 5, 4, double > T54;
1175  typedef WTensorBaseSym< 3, 3, float > T33;
1176  typedef WTensorBaseSym< 0, 3, double > T03;
1177 
1178  {
1179  // create a tensor and fill in some values
1180  // use direct access to the m_data array as access operators aren't tested yet
1181  T23 t, m;
1182 
1183  t.m_data[ 2 ] = 3;
1184  t.m_data[ 3 ] = 2;
1185  t.m_data[ 1 ] = -1;
1186 
1187  // also test the first and last elements to avoid off-by-one error
1188  t.m_data[ 5 ] = -25;
1189  t.m_data[ 0 ] = 26;
1190 
1191  // force operator =
1192  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
1193  m.operator = ( t );
1194 
1195  // the data arrays of t and m should be the same
1196  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 6 * sizeof( int ) );
1197 
1198  // copy from a const ref
1199  T23 const& w = t;
1200  T23 r;
1201  r.operator = ( w );
1202 
1203  // the data arrays of r and t should be the same
1204  TS_ASSERT_SAME_DATA( &r.m_data[ 0 ], &t.m_data[ 0 ], 6 * sizeof( int ) );
1205  }
1206 
1207  // now test some other tensors
1208  {
1209  T54 t, m;
1210 
1211  t.m_data[ 2 ] = 3.0;
1212  t.m_data[ 3 ] = 2.4;
1213  t.m_data[ 7 ] = -1.0;
1214  t.m_data[ 33 ] = 20.0;
1215  t.m_data[ 21 ] = -134.243;
1216  t.m_data[ 54 ] = 567.534;
1217  t.m_data[ 48 ] = -5.4276;
1218  t.m_data[ 34 ] = 1233.4;
1219  t.m_data[ 27 ] = -9878.765;
1220 
1221  t.m_data[ 55 ] = -265.63;
1222  t.m_data[ 0 ] = 2453.0;
1223 
1224  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
1225  m.operator = ( t );
1226 
1227  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 56 * sizeof( double ) );
1228  }
1229 
1230  {
1231  T33 t, m;
1232 
1233  t.m_data[ 2 ] = 3.0f;
1234  t.m_data[ 3 ] = 2.0f;
1235  t.m_data[ 7 ] = -1.0f;
1236  t.m_data[ 1 ] = -13.4243f;
1237  t.m_data[ 5 ] = 5675.34f;
1238  t.m_data[ 6 ] = -54276.0f;
1239  t.m_data[ 4 ] = 123.34f;
1240  t.m_data[ 8 ] = -98787.65f;
1241 
1242  t.m_data[ 9 ] = -26.563f;
1243  t.m_data[ 0 ] = 245.3f;
1244 
1245  TS_ASSERT_THROWS_NOTHING( m.operator = ( t ) );
1246  m.operator = ( t );
1247 
1248  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( float ) );
1249  }
1250 
1251  {
1252  T03 t;
1253 
1254  t.m_data = -4;
1255 
1256  TS_ASSERT_THROWS_NOTHING( T03 m( t ) );
1257 
1258  T03 m( t );
1259 
1260  TS_ASSERT_EQUALS( m.m_data, t.m_data );
1261  }
1262  }
1263 
1264  /**
1265  * Test if the copy operator handles assignments of variables to themselves correctly.
1266  */
1268  {
1269  typedef WTensorBaseSym< 3, 3, double > T33;
1270  typedef WTensorBaseSym< 0, 0, int > T00;
1271 
1272  {
1273  T33 t;
1274 
1275  // set some elements
1276  t.m_data[ 0 ] = 347.856;
1277  t.m_data[ 9 ] = -4.0;
1278  t.m_data[ 4 ] = -564.4;
1279 
1280  // create a copy of t for comparison
1281  T33 m( t );
1282 
1283  // now try copying t onto itself
1284  // this should not throw anything, as the WTensorSym documentation states that Data_T
1285  // ( in this case double ) shouldn't throw on assignment
1286  // this is also the reason that there is no test with a datatype whose operator = throws
1287  TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
1288  t.operator = ( t );
1289 
1290  // t and m should still be equal
1291  TS_ASSERT_SAME_DATA( &t.m_data[ 0 ], &m.m_data[ 0 ], 10 * sizeof( double ) );
1292  }
1293 
1294  {
1295  T00 t;
1296 
1297  t.m_data = -57;
1298 
1299  T00 m( t );
1300 
1301  TS_ASSERT_THROWS_NOTHING( t.operator = ( t ) );
1302  t.operator = ( t );
1303 
1304  TS_ASSERT_EQUALS( m.m_data, t.m_data );
1305  }
1306  }
1307 
1308  /**
1309  * Test if the access operator correctly throws Exceptions only when the input indices are invalid.
1310  */
1312  {
1313  typedef WTensorBaseSym< 4, 4, double > T44;
1314  typedef WTensorBaseSym< 1, 4, int > T14;
1315  typedef WTensorBaseSym< 3, 2, float > T32;
1316  typedef WTensorBaseSym< 0, 654, int > T0;
1317 
1318  // first, we'll check some error conditions
1319  {
1320  // instantiate a tensor
1321  T44 t;
1322 
1323  // now create an index array
1324  int idx[] = { 0, 1, 2, 3 };
1325  // this should work
1326  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1327 
1328  // try some invalid indices, indices of a tensor of dimension 4 may only be 0, 1, 2 or 3
1329  idx[ 3 ] = 4; // idx == [ 0, 1, 2, 4 ]
1330  TS_ASSERT_THROWS( t[ idx ], const WException& );
1331 
1332  // indices are cast to std::size_t (which should be unsigned)
1333  idx[ 3 ] = -1; // idx == [ 0, 1, 2, -1 ]
1334  TS_ASSERT_THROWS( t[ idx ], const WException& );
1335 
1336  idx[ 3 ] = 2;
1337  idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
1338  TS_ASSERT_THROWS( t[ idx ], const WException& );
1339 
1340  idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
1341  TS_ASSERT_THROWS( t[ idx ], const WException& );
1342 
1343  // some indices that should be valid
1344  idx[ 0 ] = 3;
1345  idx[ 1 ] = 3;
1346  idx[ 2 ] = 3;
1347  idx[ 3 ] = 3;
1348  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1349 
1350  idx[ 0 ] = 0;
1351  idx[ 1 ] = 0;
1352  idx[ 2 ] = 0;
1353  idx[ 3 ] = 0;
1354  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1355 
1356  idx[ 0 ] = 1;
1357  idx[ 1 ] = 3;
1358  idx[ 2 ] = 2;
1359  idx[ 3 ] = 1;
1360  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1361 
1362  idx[ 0 ] = 0;
1363  idx[ 1 ] = 0;
1364  idx[ 2 ] = 2;
1365  idx[ 3 ] = 0;
1366  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1367 
1368  // a larger array should also work, all unneeded values should be ignored
1369  std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
1370  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
1371 
1372  // note that the length of the index array cannot be checked
1373  }
1374 
1375  // now do the same for another tensor
1376  {
1377  T14 t;
1378 
1379  int idx[] = { 0 };
1380  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1381 
1382  idx[ 0 ] = 4;
1383  TS_ASSERT_THROWS( t[ idx ], const WException& );
1384 
1385  idx[ 0 ] = 4537;
1386  TS_ASSERT_THROWS( t[ idx ], const WException& );
1387 
1388  idx[ 0 ] = 1;
1389  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1390 
1391  idx[ 0 ] = 2;
1392  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1393 
1394  idx[ 0 ] = 3;
1395  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1396 
1397  std::size_t idx2[] = { 0, 1, 2, 3, 8, 54643 };
1398  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
1399  }
1400 
1401  // and another one
1402  {
1403  T32 t;
1404 
1405  // note that only values 0 and 1 are valid indices
1406  int idx[] = { 0, 1, 1 };
1407  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1408 
1409  idx[ 2 ] = 3;
1410  TS_ASSERT_THROWS( t[ idx ], const WException& );
1411 
1412  idx[ 0 ] = -1;
1413  TS_ASSERT_THROWS( t[ idx ], const WException& );
1414 
1415  idx[ 2 ] = 2;
1416  idx[ 0 ] = 4537;
1417  TS_ASSERT_THROWS( t[ idx ], const WException& );
1418 
1419  idx[ 0 ] = 0;
1420  idx[ 1 ] = 1;
1421  idx[ 2 ] = 0;
1422  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1423 
1424  idx[ 0 ] = 0;
1425  idx[ 1 ] = 0;
1426  idx[ 2 ] = 0;
1427  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1428 
1429  idx[ 0 ] = 1;
1430  idx[ 1 ] = 0;
1431  idx[ 2 ] = 1;
1432  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1433 
1434  idx[ 0 ] = 0;
1435  idx[ 1 ] = 0;
1436  idx[ 2 ] = 1;
1437  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1438 
1439  std::size_t idx2[] = { 0, 1, 1, 3, 8, 54643 };
1440  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
1441  }
1442 
1443  {
1444  T0 t;
1445 
1446  std::size_t idx[] = { 0, 1 };
1447  std::size_t* idx2 = NULL;
1448 
1449  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1450  TS_ASSERT_THROWS_NOTHING( t[ idx2 ] );
1451  }
1452  }
1453 
1454  /**
1455  * Test if the array access operator returns the correct elements.
1456  */
1458  {
1459  typedef WTensorBaseSym< 2, 3, std::size_t > T23;
1460  typedef WTensorBaseSym< 3, 4, std::size_t > T34;
1461 
1462  // now test if operator [] returns the correct elements
1463  {
1464  // create a new tensor
1465  T23 t;
1466 
1467  // enumerate all elements
1468  for( std::size_t k = 0; k < T23::dataSize; ++k )
1469  {
1470  t.m_data[ k ] = k;
1471  }
1472 
1473  // the order of elements should be
1474  // 0 1 2
1475  // 3 4
1476  // 5
1477  std::size_t idx[] = { 0, 0 };
1478  TS_ASSERT_EQUALS( t[ idx ], 0 );
1479  idx[ 1 ] = 1; // idx == [ 0, 1 ]
1480  TS_ASSERT_EQUALS( t[ idx ], 1 );
1481  idx[ 1 ] = 2; // idx == [ 0, 2 ]
1482  TS_ASSERT_EQUALS( t[ idx ], 2 );
1483  idx[ 0 ] = 1; // idx == [ 1, 2 ]
1484  TS_ASSERT_EQUALS( t[ idx ], 4 );
1485  idx[ 1 ] = 1; // idx == [ 1, 1 ]
1486  TS_ASSERT_EQUALS( t[ idx ], 3 );
1487  idx[ 1 ] = 0; // idx == [ 1, 0 ]
1488  TS_ASSERT_EQUALS( t[ idx ], 1 );
1489  idx[ 0 ] = 2; // idx == [ 2, 0 ]
1490  TS_ASSERT_EQUALS( t[ idx ], 2 );
1491  idx[ 1 ] = 1; // idx == [ 2, 1 ]
1492  TS_ASSERT_EQUALS( t[ idx ], 4 );
1493  idx[ 1 ] = 2; // idx == [ 2, 2 ]
1494  TS_ASSERT_EQUALS( t[ idx ], 5 );
1495 
1496  // const refs should also work
1497  T23 const& w = t;
1498  idx[ 0 ] = idx[ 1 ] = 0;
1499  TS_ASSERT_EQUALS( w[ idx ], 0 );
1500  idx[ 1 ] = 1; // idx == [ 0, 1 ]
1501  TS_ASSERT_EQUALS( w[ idx ], 1 );
1502  idx[ 1 ] = 2; // idx == [ 0, 2 ]
1503  TS_ASSERT_EQUALS( w[ idx ], 2 );
1504  idx[ 0 ] = 1; // idx == [ 1, 2 ]
1505  TS_ASSERT_EQUALS( w[ idx ], 4 );
1506  idx[ 1 ] = 1; // idx == [ 1, 1 ]
1507  TS_ASSERT_EQUALS( w[ idx ], 3 );
1508  idx[ 1 ] = 0; // idx == [ 1, 0 ]
1509  TS_ASSERT_EQUALS( w[ idx ], 1 );
1510  idx[ 0 ] = 2; // idx == [ 2, 0 ]
1511  TS_ASSERT_EQUALS( w[ idx ], 2 );
1512  idx[ 1 ] = 1; // idx == [ 2, 1 ]
1513  TS_ASSERT_EQUALS( w[ idx ], 4 );
1514  idx[ 1 ] = 2; // idx == [ 2, 2 ]
1515  TS_ASSERT_EQUALS( w[ idx ], 5 );
1516  }
1517  {
1518  // create a new tensor
1519  T34 t;
1520 
1521  // enumerate all elements
1522  for( std::size_t k = 0; k < T34::dataSize; ++k )
1523  {
1524  t.m_data[ k ] = k;
1525  }
1526 
1527  // order should be
1528  //
1529  // idx[0] == 0 idx[0] == 1 idx[0] == 2 idx[0] == 3
1530  //
1531  // 0 1 2 3 idx[1] == 0
1532  // 4 5 6 10 11 12 idx[1] == 1
1533  // 7 8 13 14 16 17 idx[1] == 2
1534  // 9 15 18 19 idx[1] == 3
1535 
1536  std::size_t idx[] = { 0, 0, 0 };
1537  TS_ASSERT_EQUALS( t[ idx ], 0 );
1538  idx[ 1 ] = 2; // idx == [ 0, 2, 0 ]
1539  TS_ASSERT_EQUALS( t[ idx ], 2 );
1540  idx[ 2 ] = 3; // idx == [ 0, 2, 3 ]
1541  TS_ASSERT_EQUALS( t[ idx ], 8 );
1542  idx[ 0 ] = 1; // idx == [ 1, 2, 3 ]
1543  TS_ASSERT_EQUALS( t[ idx ], 14 );
1544  idx[ 1 ] = 1; // idx == [ 1, 1, 3 ]
1545  TS_ASSERT_EQUALS( t[ idx ], 12 );
1546  idx[ 0 ] = 3; // idx == [ 3, 1, 3 ]
1547  TS_ASSERT_EQUALS( t[ idx ], 15 );
1548  idx[ 2 ] = 0; // idx == [ 3, 1, 0 ]
1549  TS_ASSERT_EQUALS( t[ idx ], 6 );
1550  idx[ 1 ] = 3; // idx == [ 3, 3, 0 ]
1551  TS_ASSERT_EQUALS( t[ idx ], 9 );
1552  idx[ 1 ] = 2; // idx == [ 3, 2, 0 ]
1553  TS_ASSERT_EQUALS( t[ idx ], 8 );
1554  }
1555  }
1556 
1557  /**
1558  * Test if operator [] correctly maps permutations of the same set of indices to
1559  * the same array positions.
1560  */
1562  {
1563  typedef WTensorBaseSym< 3, 4, std::size_t > T34;
1564 
1565  T34 t;
1566 
1567  // enumerate all elements
1568  for( std::size_t k = 0; k < T34::dataSize; ++k )
1569  {
1570  t.m_data[ k ] = k;
1571  }
1572 
1573  // create some index set permutations
1574  std::size_t idx1[ 3 ][ 3 ] = { { 0, 0, 1 }, // NOLINT no extra lines for { or } in an array initialization
1575  { 0, 1, 0 }, // NOLINT
1576  { 1, 0, 0 } }; // NOLINT
1577 
1578  std::size_t idx2[ 6 ][ 3 ] = { { 0, 1, 2 }, // NOLINT
1579  { 0, 2, 1 }, // NOLINT
1580  { 1, 2, 0 }, // NOLINT
1581  { 2, 1, 0 }, // NOLINT
1582  { 1, 0, 2 }, // NOLINT
1583  { 2, 1, 0 } }; // NOLINT
1584 
1585  std::size_t idx3[ 3 ][ 3 ] = { { 0, 0, 3 }, // NOLINT
1586  { 0, 3, 0 }, // NOLINT
1587  { 3, 0, 0 } }; // NOLINT
1588 
1589  std::size_t idx4[ 6 ][ 3 ] = { { 0, 3, 2 }, // NOLINT
1590  { 0, 2, 3 }, // NOLINT
1591  { 3, 2, 0 }, // NOLINT
1592  { 2, 3, 0 }, // NOLINT
1593  { 3, 0, 2 }, // NOLINT
1594  { 2, 3, 0 } }; // NOLINT
1595 
1596  // operator [] should map any permutation of a set of indices onto the same array position
1597  TS_ASSERT_EQUALS( t[ idx1[ 0 ] ], t[ idx1[ 1 ] ] );
1598  TS_ASSERT_EQUALS( t[ idx1[ 1 ] ], t[ idx1[ 2 ] ] );
1599 
1600  TS_ASSERT_EQUALS( t[ idx2[ 0 ] ], t[ idx2[ 1 ] ] );
1601  TS_ASSERT_EQUALS( t[ idx2[ 1 ] ], t[ idx2[ 2 ] ] );
1602  TS_ASSERT_EQUALS( t[ idx2[ 2 ] ], t[ idx2[ 3 ] ] );
1603  TS_ASSERT_EQUALS( t[ idx2[ 3 ] ], t[ idx2[ 4 ] ] );
1604  TS_ASSERT_EQUALS( t[ idx2[ 4 ] ], t[ idx2[ 5 ] ] );
1605 
1606  TS_ASSERT_EQUALS( t[ idx3[ 0 ] ], t[ idx3[ 1 ] ] );
1607  TS_ASSERT_EQUALS( t[ idx3[ 1 ] ], t[ idx3[ 2 ] ] );
1608 
1609  TS_ASSERT_EQUALS( t[ idx4[ 0 ] ], t[ idx4[ 1 ] ] );
1610  TS_ASSERT_EQUALS( t[ idx4[ 1 ] ], t[ idx4[ 2 ] ] );
1611  TS_ASSERT_EQUALS( t[ idx4[ 2 ] ], t[ idx4[ 3 ] ] );
1612  TS_ASSERT_EQUALS( t[ idx4[ 3 ] ], t[ idx4[ 4 ] ] );
1613  TS_ASSERT_EQUALS( t[ idx4[ 4 ] ], t[ idx4[ 5 ] ] );
1614 
1615  // permutations of different index sets may never map onto the same position
1616  TS_ASSERT_DIFFERS( t[ idx1[ 0 ] ], t[ idx2[ 0 ] ] );
1617  TS_ASSERT_DIFFERS( t[ idx1[ 1 ] ], t[ idx2[ 5 ] ] );
1618  TS_ASSERT_DIFFERS( t[ idx2[ 0 ] ], t[ idx4[ 4 ] ] );
1619  TS_ASSERT_DIFFERS( t[ idx2[ 0 ] ], t[ idx3[ 2 ] ] );
1620  TS_ASSERT_DIFFERS( t[ idx2[ 3 ] ], t[ idx3[ 1 ] ] );
1621  TS_ASSERT_DIFFERS( t[ idx3[ 0 ] ], t[ idx2[ 0 ] ] );
1622  TS_ASSERT_DIFFERS( t[ idx3[ 1 ] ], t[ idx4[ 3 ] ] );
1623  TS_ASSERT_DIFFERS( t[ idx3[ 0 ] ], t[ idx1[ 2 ] ] );
1624  TS_ASSERT_DIFFERS( t[ idx4[ 2 ] ], t[ idx1[ 0 ] ] );
1625  TS_ASSERT_DIFFERS( t[ idx4[ 5 ] ], t[ idx3[ 2 ] ] );
1626  }
1627 
1628  /**
1629  * Test the std::vector version of operator [] for correct handling of
1630  * various input vector sizes.
1631  */
1633  {
1634  typedef WTensorBaseSym< 4, 4, double > T44;
1635  typedef WTensorBaseSym< 1, 4, double > T14;
1636  typedef WTensorBaseSym< 6, 2, double > T62;
1637 
1638  {
1639  T44 t;
1640 
1641  // test a vector of invalid size
1642  std::vector< int > idx;
1643 
1644  // this should throw a WException (using the WAssert macro)
1645  TS_ASSERT_THROWS( t[ idx ], const WException& );
1646 
1647  idx.push_back( 0 ); // idx == [ 0 ]
1648  TS_ASSERT_THROWS( t[ idx ], const WException& );
1649  idx.push_back( 1 ); // idx == [ 0, 1 ]
1650  TS_ASSERT_THROWS( t[ idx ], const WException& );
1651  idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
1652  TS_ASSERT_THROWS( t[ idx ], const WException& );
1653 
1654  idx.push_back( 3 ); // idx == [ 0, 1, 2, 3 ]
1655  // now idx has the correct size and all valid indices
1656  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1657 
1658  // a larger vector should also work
1659  idx.push_back( 456 ); // idx == [ 0, 0, 2, 0, 456 ]
1660 
1661  // this should simply ignore all values after the 4th
1662  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1663 
1664  idx.push_back( -1 );
1665  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1666 
1667  // bounds checking on the indices is done by the array version of operator [],
1668  // which is called by the vector version
1669  // I'll add some tests here though, in case this changes in the future
1670  idx[ 0 ] = -1;
1671  TS_ASSERT_THROWS( t[ idx ], const WException& );
1672 
1673  idx[ 0 ] = 4;
1674  TS_ASSERT_THROWS( t[ idx ], const WException& );
1675 
1676  idx[ 0 ] = 3;
1677  idx[ 3 ] = -1;
1678  TS_ASSERT_THROWS( t[ idx ], const WException& );
1679 
1680  idx[ 3 ] = 4;
1681  TS_ASSERT_THROWS( t[ idx ], const WException& );
1682 
1683  idx[ 3 ] = 2;
1684  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1685  }
1686  {
1687  T14 t;
1688 
1689  std::vector< int > idx;
1690  TS_ASSERT_THROWS( t[ idx ], const WException& );
1691 
1692  idx.push_back( 0 ); // idx == [ 0 ]
1693  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1694 
1695  idx.push_back( 3 ); // idx == [ 0, 3 ]
1696  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1697 
1698  idx.push_back( 456 ); // idx == [ 0, 3, 456 ]
1699  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1700 
1701  idx.push_back( -1 );
1702  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1703  }
1704  {
1705  T62 t;
1706 
1707  std::vector< int > idx;
1708  TS_ASSERT_THROWS( t[ idx ], const WException& );
1709 
1710  idx.push_back( 0 ); // idx == [ 0 ]
1711  TS_ASSERT_THROWS( t[ idx ], const WException& );
1712  idx.push_back( 1 ); // idx == [ 0, 1 ]
1713  TS_ASSERT_THROWS( t[ idx ], const WException& );
1714  idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
1715  TS_ASSERT_THROWS( t[ idx ], const WException& );
1716  idx.push_back( 1 );
1717  TS_ASSERT_THROWS( t[ idx ], const WException& );
1718  idx.push_back( 1 );
1719  TS_ASSERT_THROWS( t[ idx ], const WException& );
1720  idx.push_back( 0 );
1721  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1722 
1723  idx.push_back( 456 );
1724  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1725 
1726  idx.push_back( -1 );
1727  TS_ASSERT_THROWS_NOTHING( t[ idx ] );
1728 
1729  T62 const w;
1730  TS_ASSERT_THROWS_NOTHING( w[ idx ] );
1731  }
1732  }
1733 
1734  /**
1735  * Test if operator == works correctly.
1736  */
1738  {
1739  typedef WTensorBaseSym< 1, 7, double > T17;
1740  typedef WTensorBaseSym< 3, 2, int > T32;
1741  typedef WTensorBaseSym< 0, 0, float > T00;
1742 
1743  {
1744  T17 t, m;
1745 
1746  // two tensors of the same type should be initialized to the same values
1747  TS_ASSERT( t == m );
1748  TS_ASSERT( m == t );
1749 
1750  // a tensor should always be equal to itself
1751  TS_ASSERT( t == t );
1752  TS_ASSERT( m == m );
1753 
1754  // change some values
1755  std::size_t idx[] = { 4 };
1756  t[ idx ] = 5.0;
1757 
1758  TS_ASSERT( !( t == m ) );
1759  TS_ASSERT( !( m == t ) );
1760  TS_ASSERT( t == t );
1761  TS_ASSERT( m == m );
1762 
1763  m[ idx ] = 5.0;
1764 
1765  TS_ASSERT( t == m );
1766  TS_ASSERT( m == t );
1767  TS_ASSERT( t == t );
1768  TS_ASSERT( m == m );
1769 
1770  idx[ 0 ] = 2;
1771  m[ idx ] = 543543.0;
1772 
1773  TS_ASSERT( !( t == m ) );
1774  TS_ASSERT( !( m == t ) );
1775  TS_ASSERT( t == t );
1776  TS_ASSERT( m == m );
1777 
1778  // copying a tensor should lead to the respective tensors being equal
1779  t = m;
1780  TS_ASSERT( t == m );
1781  TS_ASSERT( m == t );
1782  TS_ASSERT( t == t );
1783  TS_ASSERT( m == m );
1784 
1785  // test const
1786  T17 const ct, cm;
1787  TS_ASSERT( ct == cm );
1788  TS_ASSERT( cm == ct );
1789  TS_ASSERT( ct == ct );
1790  TS_ASSERT( cm == cm );
1791  }
1792  {
1793  T32 t, m;
1794 
1795  std::size_t idx[] = { 0, 0, 0 };
1796 
1797  // two tensors of the same type should be initialized to the same values
1798  TS_ASSERT( t == m );
1799  TS_ASSERT( m == t );
1800 
1801  // a tensor should always be equal to itself
1802  TS_ASSERT( t == t );
1803  TS_ASSERT( m == m );
1804 
1805  idx[ 1 ] = 1;
1806 
1807  m[ idx ] = -5643;
1808 
1809  TS_ASSERT( !( t == m ) );
1810  TS_ASSERT( !( m == t ) );
1811  TS_ASSERT( t == t );
1812  TS_ASSERT( m == m );
1813 
1814  t = m;
1815 
1816  TS_ASSERT( t == m );
1817  TS_ASSERT( m == t );
1818  TS_ASSERT( t == t );
1819  TS_ASSERT( m == m );
1820 
1821  idx[ 1 ] = 0;
1822 
1823  t[ idx ] = 564;
1824 
1825  TS_ASSERT( !( t == m ) );
1826  TS_ASSERT( !( m == t ) );
1827  TS_ASSERT( t == t );
1828  TS_ASSERT( m == m );
1829 
1830  t.m_data[ 0 ] = 5;
1831  t.m_data[ 1 ] = -65464;
1832  t.m_data[ 2 ] = 89;
1833  t.m_data[ 3 ] = 3276;
1834 
1835  m.m_data[ 0 ] = -5;
1836  m.m_data[ 1 ] = 65464;
1837  m.m_data[ 2 ] = -89;
1838  m.m_data[ 3 ] = -3276;
1839 
1840  TS_ASSERT( !( t == m ) );
1841  TS_ASSERT( !( m == t ) );
1842  TS_ASSERT( t == t );
1843  TS_ASSERT( m == m );
1844  }
1845  {
1846  T00 t, m;
1847 
1848  // two tensors of the same type should be initialized to the same values
1849  TS_ASSERT( t == m );
1850  TS_ASSERT( m == t );
1851 
1852  // a tensor should always be equal to itself
1853  TS_ASSERT( t == t );
1854  TS_ASSERT( m == m );
1855 
1856  t.m_data = 2;
1857 
1858  TS_ASSERT( !( t == m ) );
1859  TS_ASSERT( !( m == t ) );
1860  TS_ASSERT( t == t );
1861  TS_ASSERT( m == m );
1862 
1863  m.m_data = 2;
1864 
1865  TS_ASSERT( t == m );
1866  TS_ASSERT( m == t );
1867  TS_ASSERT( t == t );
1868  TS_ASSERT( m == m );
1869  }
1870  }
1871 
1872  /**
1873  * Test if operator != works correctly.
1874  */
1876  {
1877  typedef WTensorBaseSym< 3, 3, int > T33;
1878  typedef WTensorBaseSym< 0, 0, int > T00;
1879 
1880  {
1881  T33 t, m;
1882 
1883  // two new instances should never not be equal
1884  TS_ASSERT( !( t != m ) );
1885  TS_ASSERT( !( m != t ) );
1886 
1887  // a tensor should never not be equal to itself
1888  TS_ASSERT( !( t != t ) );
1889  TS_ASSERT( !( m != m ) );
1890 
1891  // change some elements
1892  t.m_data[ 4 ] = -23467;
1893 
1894  TS_ASSERT( t != m );
1895  TS_ASSERT( m != t );
1896  TS_ASSERT( !( t != t ) );
1897  TS_ASSERT( !( m != m ) );
1898 
1899  t = m;
1900  TS_ASSERT( !( t != m ) );
1901  TS_ASSERT( !( m != t ) );
1902 
1903  t.m_data[ 0 ] = 1;
1904  TS_ASSERT( t != m );
1905  TS_ASSERT( m != t );
1906  TS_ASSERT( !( t != t ) );
1907  TS_ASSERT( !( m != m ) );
1908 
1909  t = m;
1910  TS_ASSERT( !( t != m ) );
1911  TS_ASSERT( !( m != t ) );
1912  TS_ASSERT( !( t != t ) );
1913  TS_ASSERT( !( m != m ) );
1914 
1915  t.m_data[ 9 ] = -1;
1916  TS_ASSERT( t != m );
1917  TS_ASSERT( m != t );
1918  TS_ASSERT( !( t != t ) );
1919  TS_ASSERT( !( m != m ) );
1920 
1921  // test const
1922  T33 const ct, cm;
1923  TS_ASSERT( !( ct != cm ) );
1924  TS_ASSERT( !( cm != ct ) );
1925  TS_ASSERT( !( ct != ct ) );
1926  TS_ASSERT( !( cm != cm ) );
1927  }
1928 
1929  {
1930  T00 t, m;
1931 
1932  TS_ASSERT( !( t != m ) );
1933  TS_ASSERT( !( m != t ) );
1934  TS_ASSERT( !( t != t ) );
1935  TS_ASSERT( !( m != m ) );
1936 
1937  t.m_data = 2;
1938 
1939  TS_ASSERT( t != m );
1940  TS_ASSERT( m != t );
1941  TS_ASSERT( !( t != t ) );
1942  TS_ASSERT( !( m != m ) );
1943 
1944  m.m_data = 2;
1945 
1946  TS_ASSERT( !( t != m ) );
1947  TS_ASSERT( !( m != t ) );
1948  TS_ASSERT( !( t != t ) );
1949  TS_ASSERT( !( m != m ) );
1950  }
1951  }
1952 };
1953 
1954 /**
1955  * A class that tests the WTensorFunc template.
1956  */
1957 class WTensorFuncTest : public CxxTest::TestSuite
1958 {
1959 public:
1960  /**
1961  * Test operator () error conditions.
1962  */
1964  {
1965  // first test with an asymmetric tensor base
1966  typedef WTensorFunc< WTensorBase, 3, 3, double > F33;
1967  typedef WTensorFunc< WTensorBase, 1, 5, int > F15;
1968 
1969  {
1970  F33 f;
1971 
1972  // try some valid indices
1973  TS_ASSERT_THROWS_NOTHING( f( 0, 0, 0 ) );
1974  TS_ASSERT_THROWS_NOTHING( f( 1, 0, 0 ) );
1975  TS_ASSERT_THROWS_NOTHING( f( 2, 2, 2 ) );
1976  TS_ASSERT_THROWS_NOTHING( f( 1, 1, 1 ) );
1977  TS_ASSERT_THROWS_NOTHING( f( 1, 0, 2 ) );
1978  TS_ASSERT_THROWS_NOTHING( f( 0, 2, 0 ) );
1979 
1980  // try some invalid indices
1981  // negative indices are not allowed as the parameters are of type std::size_t
1982  TS_ASSERT_THROWS( f( 0, 0, 3 ), const WException& );
1983  TS_ASSERT_THROWS( f( 0, 654465, 0 ), const WException& );
1984  TS_ASSERT_THROWS( f( 4, 0, 0 ), const WException& );
1985  TS_ASSERT_THROWS( f( 0, 0, 45 ), const WException& );
1986  TS_ASSERT_THROWS( f( 0, 64, 0 ), const WException& );
1987  TS_ASSERT_THROWS( f( 792, 981, 5645 ), const WException& );
1988  }
1989  {
1990  F15 f;
1991 
1992  TS_ASSERT_THROWS_NOTHING( f( 0 ) );
1993  TS_ASSERT_THROWS_NOTHING( f( 1 ) );
1994  TS_ASSERT_THROWS_NOTHING( f( 2 ) );
1995  TS_ASSERT_THROWS_NOTHING( f( 3 ) );
1996  TS_ASSERT_THROWS_NOTHING( f( 4 ) );
1997 
1998  TS_ASSERT_THROWS( f( 5 ), const WException& );
1999  TS_ASSERT_THROWS( f( 5436 ), const WException& );
2000  }
2001 
2002  // now try a symmetric tensor base
2003  typedef WTensorFunc< WTensorBaseSym, 2, 4, double > F24;
2004 
2005  {
2006  F24 f;
2007 
2008  TS_ASSERT_THROWS_NOTHING( f( 0, 0 ) );
2009  TS_ASSERT_THROWS_NOTHING( f( 3, 0 ) );
2010  TS_ASSERT_THROWS_NOTHING( f( 2, 3 ) );
2011  TS_ASSERT_THROWS_NOTHING( f( 3, 3 ) );
2012  TS_ASSERT_THROWS_NOTHING( f( 0, 1 ) );
2013 
2014  TS_ASSERT_THROWS( f( 4, 0 ), const WException& );
2015  TS_ASSERT_THROWS( f( 3, 457 ), const WException& );
2016  }
2017  }
2018 
2019  /**
2020  * Test if operator () returns the correct elements.
2021  */
2023  {
2024  typedef WTensorFunc< WTensorBase, 6, 2, std::size_t > F62;
2025  typedef WTensorBase< 6, 2, std::size_t > Base62;
2026 
2027  F62 f;
2028  Base62& b = f;
2029 
2030  for( std::size_t k = 0; k < 64; ++k )
2031  {
2032  b.m_data[ k ] = k;
2033  }
2034 
2035  TS_ASSERT_EQUALS( f( 0, 0, 0, 0, 0, 0 ), 0 );
2036  TS_ASSERT_EQUALS( f( 0, 0, 0, 1, 0, 1 ), 5 );
2037  TS_ASSERT_EQUALS( f( 1, 1, 1, 0, 0, 0 ), 56 );
2038  TS_ASSERT_EQUALS( f( 0, 1, 0, 0, 0, 1 ), 17 );
2039  TS_ASSERT_EQUALS( f( 0, 0, 1, 0, 1, 0 ), 10 );
2040  TS_ASSERT_EQUALS( f( 1, 0, 1, 0, 0, 1 ), 41 );
2041  TS_ASSERT_EQUALS( f( 1, 1, 1, 1, 1, 1 ), 63 );
2042 
2043  F62 const& w = f;
2044  TS_ASSERT_EQUALS( w( 0, 0, 0, 0, 0, 0 ), 0 );
2045  TS_ASSERT_EQUALS( w( 0, 0, 0, 1, 0, 1 ), 5 );
2046  TS_ASSERT_EQUALS( w( 1, 1, 1, 0, 0, 0 ), 56 );
2047  TS_ASSERT_EQUALS( w( 0, 1, 0, 0, 0, 1 ), 17 );
2048  TS_ASSERT_EQUALS( w( 0, 0, 1, 0, 1, 0 ), 10 );
2049  TS_ASSERT_EQUALS( w( 1, 0, 1, 0, 0, 1 ), 41 );
2050  TS_ASSERT_EQUALS( w( 1, 1, 1, 1, 1, 1 ), 63 );
2051  }
2052 
2053  /**
2054  * Test if operator () keeps the symmetry of a WTensorBaseSym intact.
2055  */
2057  {
2058  typedef WTensorFunc< WTensorBaseSym, 4, 5, std::size_t > F45;
2059  typedef WTensorBaseSym< 4, 5, std::size_t > Base45;
2060 
2061  F45 f;
2062  Base45& b = f;
2063 
2064  for( std::size_t k = 0; k < 70; ++k )
2065  {
2066  b.m_data[ k ] = k;
2067  }
2068 
2069  std::size_t idx[ 8 ][ 6 ] = { { 0, 1, 2, 4 }, // NOLINT no extra line per { or }
2070  { 3, 2, 4, 0 }, // NOLINT
2071  { 4, 4, 4, 0 }, // NOLINT
2072  { 0, 0, 0, 0 }, // NOLINT
2073  { 3, 4, 0, 1 }, // NOLINT
2074  { 2, 2, 2, 2 }, // NOLINT
2075  { 4, 4, 4, 4 }, // NOLINT
2076  { 2, 2, 0, 3 } }; // NOLINT
2077 
2078  TS_ASSERT( f( 0, 1, 2, 4 ) == f[ idx[ 0 ] ] );
2079  TS_ASSERT( f( 1, 0, 2, 4 ) == f[ idx[ 0 ] ] );
2080  TS_ASSERT( f( 4, 1, 0, 2 ) == f[ idx[ 0 ] ] );
2081  TS_ASSERT( f( 0, 3, 2, 4 ) == f[ idx[ 1 ] ] );
2082  TS_ASSERT( f( 0, 4, 4, 4 ) == f[ idx[ 2 ] ] );
2083  TS_ASSERT( f( 4, 0, 4, 4 ) == f[ idx[ 2 ] ] );
2084  TS_ASSERT( f( 0, 0, 0, 0 ) == f[ idx[ 3 ] ] );
2085  TS_ASSERT( f( 0, 1, 3, 4 ) == f[ idx[ 4 ] ] );
2086  TS_ASSERT( f( 2, 2, 2, 2 ) == f[ idx[ 5 ] ] );
2087  TS_ASSERT( f( 4, 4, 4, 4 ) == f[ idx[ 6 ] ] );
2088  TS_ASSERT( f( 2, 2, 3, 0 ) == f[ idx[ 7 ] ] );
2089  TS_ASSERT( f( 2, 3, 0, 2 ) == f[ idx[ 7 ] ] );
2090 
2091  F45 const& w = f;
2092  TS_ASSERT( w( 0, 1, 2, 4 ) == w[ idx[ 0 ] ] );
2093  TS_ASSERT( w( 1, 0, 2, 4 ) == w[ idx[ 0 ] ] );
2094  TS_ASSERT( w( 4, 1, 0, 2 ) == w[ idx[ 0 ] ] );
2095  TS_ASSERT( w( 0, 3, 2, 4 ) == w[ idx[ 1 ] ] );
2096  TS_ASSERT( w( 0, 4, 4, 4 ) == w[ idx[ 2 ] ] );
2097  TS_ASSERT( w( 4, 0, 4, 4 ) == w[ idx[ 2 ] ] );
2098  TS_ASSERT( w( 0, 0, 0, 0 ) == w[ idx[ 3 ] ] );
2099  TS_ASSERT( w( 0, 1, 3, 4 ) == w[ idx[ 4 ] ] );
2100  TS_ASSERT( w( 2, 2, 2, 2 ) == w[ idx[ 5 ] ] );
2101  TS_ASSERT( w( 4, 4, 4, 4 ) == w[ idx[ 6 ] ] );
2102  TS_ASSERT( w( 2, 2, 3, 0 ) == w[ idx[ 7 ] ] );
2103  TS_ASSERT( w( 2, 3, 0, 2 ) == w[ idx[ 7 ] ] );
2104  }
2105 };
2106 
2107 /**
2108  * Test all typecasts and copy operators that copy from another type.
2109  */
2110 class WTensorTypesTest : public CxxTest::TestSuite
2111 {
2112 public:
2113  /**
2114  * Test constructing a WTensorBase from a WTensorBaseSym.
2115  */
2117  {
2118  typedef WTensorBaseSym< 2, 4, double > S24;
2119  typedef WTensorBase< 2, 4, double > T24;
2120  typedef WTensorBaseSym< 1, 4, double > S14;
2121  typedef WTensorBase< 1, 4, double > T14;
2122  typedef WTensorBaseSym< 0, 4, double > S04;
2123  typedef WTensorBase< 0, 4, double > T04;
2124 
2125  // construct a symmetric tensor and initialize an asymmetric tensor from it
2126  {
2127  S24 s;
2128 
2129  std::size_t idx[ 2 ] = { 0, 3 };
2130 
2131  s[ idx ] = -2.0;
2132 
2133  idx[ 0 ] = 3;
2134  idx[ 1 ] = 2;
2135 
2136  s[ idx ] = 3.0;
2137 
2138  TS_ASSERT_THROWS_NOTHING( T24 t = T24( s );
2139  t.getOrder() );
2140  T24 t = T24( s );
2141 
2142  TS_ASSERT_EQUALS( t[ idx ], 3.0 );
2143 
2144  idx[ 0 ] = 3;
2145  idx[ 1 ] = 0;
2146 
2147  TS_ASSERT_EQUALS( t[ idx ], -2.0 );
2148 
2149  idx[ 0 ] = 1;
2150 
2151  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2152  }
2153  // order = 1 is kind of a special case, as there is only one "permutation" of a single index
2154  {
2155  S14 s;
2156 
2157  std::size_t idx[ 1 ] = { 0 };
2158 
2159  s[ idx ] = -2.0;
2160 
2161  idx[ 0 ] = 3;
2162 
2163  s[ idx ] = 3.0;
2164 
2165  TS_ASSERT_THROWS_NOTHING( T14 t = T14( s );
2166  t.getOrder() );
2167  T14 t = T14( s );
2168 
2169  TS_ASSERT_EQUALS( t[ idx ], 3.0 );
2170  idx[ 0 ] = 0;
2171  TS_ASSERT_EQUALS( t[ idx ], -2.0 );
2172  idx[ 0 ] = 1;
2173  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2174  idx[ 0 ] = 2;
2175  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2176  }
2177  // now test the order = 0 version
2178  {
2179  S04 s;
2180 
2181  std::size_t* idx = NULL;
2182  s[ idx ] = 5.0;
2183 
2184  TS_ASSERT_THROWS_NOTHING( T04 t = T04( s );
2185  t.getOrder() );
2186  T04 t = T04( s );
2187 
2188  TS_ASSERT_EQUALS( t[ idx ], 5.0 );
2189  }
2190  }
2191 
2192  /**
2193  * Test assignment of a WTensorBaseSym to a WTensorBase.
2194  */
2196  {
2197  // same test as the last one, only this time we use the copy operator
2198  typedef WTensorBaseSym< 2, 4, double > S24;
2199  typedef WTensorBase< 2, 4, double > T24;
2200  typedef WTensorBaseSym< 1, 4, double > S14;
2201  typedef WTensorBase< 1, 4, double > T14;
2202  typedef WTensorBaseSym< 0, 4, double > S04;
2203  typedef WTensorBase< 0, 4, double > T04;
2204 
2205  {
2206  S24 s;
2207  T24 t;
2208 
2209  std::size_t idx[ 2 ] = { 0, 3 };
2210 
2211  s[ idx ] = -2.0;
2212 
2213  idx[ 0 ] = 3;
2214  idx[ 1 ] = 2;
2215 
2216  s[ idx ] = 3.0;
2217 
2218  TS_ASSERT_THROWS_NOTHING( t = s );
2219  t = s;
2220 
2221  TS_ASSERT_EQUALS( t[ idx ], 3.0 );
2222 
2223  idx[ 0 ] = 3;
2224  idx[ 1 ] = 0;
2225 
2226  TS_ASSERT_EQUALS( t[ idx ], -2.0 );
2227 
2228  idx[ 0 ] = 1;
2229 
2230  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2231  }
2232  // order = 1 is kind of a special case, as there is only one "permutation" of a single index
2233  {
2234  S14 s;
2235  T14 t;
2236 
2237  std::size_t idx[ 1 ] = { 0 };
2238 
2239  s[ idx ] = -2.0;
2240 
2241  idx[ 0 ] = 3;
2242 
2243  s[ idx ] = 3.0;
2244 
2245  TS_ASSERT_THROWS_NOTHING( t = s );
2246  t = s;
2247 
2248  TS_ASSERT_EQUALS( t[ idx ], 3.0 );
2249  idx[ 0 ] = 0;
2250  TS_ASSERT_EQUALS( t[ idx ], -2.0 );
2251  idx[ 0 ] = 1;
2252  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2253  idx[ 0 ] = 2;
2254  TS_ASSERT_EQUALS( t[ idx ], 0.0 );
2255  }
2256  // now test the order = 0 version
2257  {
2258  S04 s;
2259  T04 t;
2260 
2261  std::size_t* idx = NULL;
2262  s[ idx ] = 5.0;
2263 
2264  TS_ASSERT_THROWS_NOTHING( t = s );
2265  t = s;
2266 
2267  TS_ASSERT_EQUALS( t[ idx ], 5.0 );
2268  }
2269  }
2270 
2271  /**
2272  * Test casts from any tensorbase of order 0 to a value.
2273  */
2275  {
2276  // create some "scalar tensors" and cast them to their respective Data_T
2277  {
2278  // types
2279  WTensorFunc< WTensorBase, 0, 1, double > td;
2280  WTensorFunc< WTensorBase, 0, 0, float > tf;
2281  WTensorFunc< WTensorBase, 0, 456, int > ti;
2282 
2283  // implicitly cast to Data_T
2284  td() = 3.0;
2285  double d = td;
2286  TS_ASSERT_EQUALS( d, 3.0 );
2287 
2288  tf() = 3.0f;
2289  float f = tf;
2290  TS_ASSERT_EQUALS( f, 3.0f );
2291 
2292  ti() = 3;
2293  int i = ti;
2294  TS_ASSERT_EQUALS( i, 3 );
2295  }
2296  // do the same test with symmetric tensors
2297  {
2298  WTensorFunc< WTensorBase, 0, 1, double > td;
2299  WTensorFunc< WTensorBase, 0, 0, float > tf;
2300  WTensorFunc< WTensorBase, 0, 456, int > ti;
2301 
2302  td() = 3.0;
2303  double d = td;
2304  TS_ASSERT_EQUALS( d, 3.0 );
2305 
2306  tf() = 3.0f;
2307  float f = tf;
2308  TS_ASSERT_EQUALS( f, 3.0f );
2309 
2310  ti() = 3;
2311  int i = ti;
2312  TS_ASSERT_EQUALS( i, 3 );
2313  }
2314  }
2315 
2316  /**
2317  * Test casts from any tensorbase of order 1 to a WValue.
2318  */
2320  {
2321  {
2322  WTensorFunc< WTensorBase, 1, 5, double > t;
2323  t( 0 ) = -9.765;
2324  t( 1 ) = 154.06;
2325  t( 4 ) = -57.0;
2326 
2327  WValue< double > v = t;
2328 
2329  TS_ASSERT_EQUALS( v.size(), 5 );
2330 
2331  TS_ASSERT_EQUALS( v[ 0 ], -9.765 );
2332  TS_ASSERT_EQUALS( v[ 1 ], 154.06 );
2333  TS_ASSERT_EQUALS( v[ 2 ], 0.0 );
2334  TS_ASSERT_EQUALS( v[ 3 ], 0.0 );
2335  TS_ASSERT_EQUALS( v[ 4 ], -57.0 );
2336  }
2337  {
2338  WTensorFunc< WTensorBaseSym, 1, 5, double > t;
2339  t( 0 ) = -9.765;
2340  t( 1 ) = 154.06;
2341  t( 4 ) = -57.0;
2342 
2343  WValue< double > v = t;
2344 
2345  TS_ASSERT_EQUALS( v.size(), 5 );
2346 
2347  TS_ASSERT_EQUALS( v[ 0 ], -9.765 );
2348  TS_ASSERT_EQUALS( v[ 1 ], 154.06 );
2349  TS_ASSERT_EQUALS( v[ 2 ], 0.0 );
2350  TS_ASSERT_EQUALS( v[ 3 ], 0.0 );
2351  TS_ASSERT_EQUALS( v[ 4 ], -57.0 );
2352  }
2353  }
2354 
2355  /**
2356  * Test casts from any tensorbase of order 2 to a WMatrix.
2357  */
2359  {
2360  {
2361  WTensorFunc< WTensorBase, 2, 3, double > t;
2362  t( 0, 0 ) = -9.765;
2363  t( 1, 0 ) = 154.06;
2364  t( 2, 2 ) = -57.0;
2365 
2366  WMatrix< double > m = t;
2367 
2368  TS_ASSERT_EQUALS( m.getNbCols(), 3 );
2369  TS_ASSERT_EQUALS( m.getNbRows(), 3 );
2370 
2371  for( std::size_t i = 0; i < 3; ++i )
2372  {
2373  for( std::size_t j = 0; j < 3; ++j )
2374  {
2375  TS_ASSERT_EQUALS( m( i, j ), t( i, j ) );
2376  }
2377  }
2378  }
2379  {
2380  WTensorFunc< WTensorBaseSym, 2, 3, double > t;
2381  t( 0, 0 ) = -9.765;
2382  t( 1, 0 ) = 154.06;
2383  t( 2, 2 ) = -57.0;
2384 
2385  WMatrix< double > m = t;
2386 
2387  TS_ASSERT_EQUALS( m.getNbCols(), 3 );
2388  TS_ASSERT_EQUALS( m.getNbRows(), 3 );
2389 
2390  for( std::size_t i = 0; i < 3; ++i )
2391  {
2392  for( std::size_t j = 0; j < 3; ++j )
2393  {
2394  TS_ASSERT_EQUALS( m( i, j ), t( i, j ) );
2395  }
2396  }
2397  }
2398  }
2399 };
2400 
2401 /**
2402  * Test some utility functions.
2403  */
2404 class WTensorUtilityTest : public CxxTest::TestSuite
2405 {
2406 public:
2407  // the functions testet here are needed for the initialization of the
2408  // index permutation to array position mapping
2409  // note that these functions do not check for errors and are meant for internal use
2410  /**
2411  * Test iteration of indices.
2412  */
2414  {
2415  boost::array< std::size_t, 3 > is;
2416  is.assign( 0 ); // is == ( 0, 0, 0 )
2417  std::vector< std::size_t > shouldBe( 3, 0 );
2418  shouldBe[ 2 ] = 1; // shouldBe == ( 0, 0, 1 )
2419 
2420  positionIterateOneStep< 3, 3 >( is );
2421  TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
2422 
2423  positionIterateOneStep< 3, 3 >( is );
2424  positionIterateOneStep< 3, 3 >( is );
2425  shouldBe[ 1 ] = 1;
2426  shouldBe[ 2 ] = 0; // shouldBe == ( 0, 1, 0 )
2427 
2428  TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
2429 
2430  // the dim = 2 case is more interesting
2431  positionIterateOneStep< 3, 2 >( is );
2432  positionIterateOneStep< 3, 2 >( is );
2433  shouldBe[ 0 ] = 1;
2434  shouldBe[ 1 ] = 0; // shouldBe == ( 1, 0, 0 )
2435 
2436  TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
2437 
2438  positionIterateOneStep< 3, 2 >( is );
2439  shouldBe[ 2 ] = 1;
2440 
2441  TS_ASSERT_SAME_DATA( &is[ 0 ], &shouldBe[ 0 ], 3 * sizeof( std::size_t ) );
2442  }
2443 
2444  /**
2445  * Test sorted iteration of indices.
2446  */
2448  {
2449  boost::array< std::size_t, 3 > v;
2450  v.assign( 0 );
2451 
2452  std::size_t numIter = WBinom< 5, 3 >::value - 1;
2453 
2454  // the indices should always be sorted
2455  for( std::size_t k = 0; k < numIter; ++k )
2456  {
2457  positionIterateSortedOneStep< 3, 3 >( v );
2458  TS_ASSERT( v[ 0 ] <= v[ 1 ] );
2459  TS_ASSERT( v[ 1 ] <= v[ 2 ] );
2460  }
2461 
2462  //after iterating numIter times, v should be ( 2, 2, 2 )
2463  TS_ASSERT_EQUALS( v[ 0 ], 2 );
2464  TS_ASSERT_EQUALS( v[ 1 ], 2 );
2465  TS_ASSERT_EQUALS( v[ 2 ], 2 );
2466 
2467  // now test the dim = 2 case
2468  v[ 0 ] = v[ 1 ] = v[ 2 ] = 0;
2469  numIter = WBinom< 4, 3 >::value - 1;
2470 
2471  // the indices should always be sorted
2472  for( std::size_t k = 0; k < numIter; ++k )
2473  {
2474  positionIterateSortedOneStep< 3, 2 >( v );
2475  TS_ASSERT( v[ 0 ] <= v[ 1 ] );
2476  TS_ASSERT( v[ 1 ] <= v[ 2 ] );
2477  }
2478 
2479  //after iterating numIter times, v should be ( 1, 1, 1 )
2480  TS_ASSERT_EQUALS( v[ 0 ], 1 );
2481  TS_ASSERT_EQUALS( v[ 1 ], 1 );
2482  TS_ASSERT_EQUALS( v[ 2 ], 1 );
2483  }
2484 };
2485 
2486 // restore WASSERT_AS_CASSERT flag
2487 #ifdef WASSERT_FLAG_CHANGED
2488 #define WASSERT_AS_CASSERT
2489 #undef WASSERT_FLAG_CHANGED
2490 #endif
2491 
2492 #endif // WTENSORBASE_TEST_H
Basic exception handler.
Definition: WException.h:39
size_t getNbRows() const
Get number of rows.
Definition: WMatrix.h:375
size_t getNbCols() const
Get number of columns.
Definition: WMatrix.h:383
Test class for WTensorBaseSym.
void testTensorBaseSymConstructor()
The standard constructor should allocate enough memory and set all elements to zero.
void testWTensorBaseSymCopyOperatorSelfCopy()
Test if the copy operator handles assignments of variables to themselves correctly.
void testWTensorBaseSymCopyConstructor()
The copy constructor should copy all values.
void testWTensorBaseSymAccessOperatorPermutations()
Test if operator [] correctly maps permutations of the same set of indices to the same array position...
void testWTensorBaseSymCompareOperator2()
Test if operator != works correctly.
void testWTensorBaseSymArrayAccess()
Test if the array access operator returns the correct elements.
void testWTensorBaseSymArrayAccessErrorConditions()
Test if the access operator correctly throws Exceptions only when the input indices are invalid.
void testWTensorBaseSymVectorAccess()
Test the std::vector version of operator [] for correct handling of various input vector sizes.
void testWTensorBaseSymCompareOperator()
Test if operator == works correctly.
void testWTensorBaseSymCopyOperatorSimple()
Test the copy operator.
Test class for WTensorBase.
void testWTensorBaseArrayAccessErrorConditions()
Test if the access operator correctly throws Exceptions only when the input indices are invalid.
void testWTensorBaseCopyOperatorSelfCopy()
Test if the copy operator handles assignments of variables to themselves correctly.
void testWTensorBaseVectorAccess()
Test the std::vector version of operator [] for correct handling of various input vector sizes.
void testWTensorBaseArrayAccess()
Test if the array access operator returns the correct elements.
void testWTensorBaseCompareOperator2()
Test if operator != works correctly.
void testWTensorBaseCopyConstructor()
The copy constructor should copy all values.
void testTensorBaseConstructor()
The standard constructor should allocate enough memory and set all elements to zero.
void testWTensorBaseCompareOperator()
Test if operator == works correctly.
void testWTensorBaseCopyOperatorSimple()
Test the copy operator.
A class that tests the WTensorFunc template.
void testAccessOperator()
Test if operator () returns the correct elements.
void testAccessOperatorSymmetry()
Test if operator () keeps the symmetry of a WTensorBaseSym intact.
void testAccessOperatorErrors()
Test operator () error conditions.
Test all typecasts and copy operators that copy from another type.
void testCastTensorToMatrix()
Test casts from any tensorbase of order 2 to a WMatrix.
void testCastTensorToValue()
Test casts from any tensorbase of order 0 to a value.
void testCopyContructorBaseFromBaseSym()
Test constructing a WTensorBase from a WTensorBaseSym.
void testCopyOperatorBaseFromSym()
Test assignment of a WTensorBaseSym to a WTensorBase.
void testCastTensorToVector()
Test casts from any tensorbase of order 1 to a WValue.
Test some utility functions.
void testIndexIteration()
Test iteration of indices.
void testIndexIterationSorted()
Test sorted iteration of indices.
Base class for all higher level values like tensors, vectors, matrices and so on.
Definition: WValue.h:41
size_t size() const
Get number of components the value consists of.
Definition: WValue.h:116
Implements compile-time calculation of binomial coefficients.