OpenWalnut  1.4.0
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 #undefine 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 ], 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 ], WException );
401 
402  idx[ 3 ] = 2;
403  idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
404  TS_ASSERT_THROWS( t[ idx ], WException );
405 
406  idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
407  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
450 
451  idx[ 0 ] = 4537;
452  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
477 
478  idx[ 0 ] = -1;
479  TS_ASSERT_THROWS( t[ idx ], WException );
480 
481  idx[ 2 ] = 2;
482  idx[ 0 ] = 4537;
483  TS_ASSERT_THROWS( t[ idx ], 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  {
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 ], WException );
655 
656  idx.push_back( 0 ); // idx == [ 0 ]
657  TS_ASSERT_THROWS( t[ idx ], WException );
658  idx.push_back( 1 ); // idx == [ 0, 1 ]
659  TS_ASSERT_THROWS( t[ idx ], WException );
660  idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
661  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
681 
682  idx[ 0 ] = 4;
683  TS_ASSERT_THROWS( t[ idx ], WException );
684 
685  idx[ 0 ] = 3;
686  idx[ 3 ] = -1;
687  TS_ASSERT_THROWS( t[ idx ], WException );
688 
689  idx[ 3 ] = 4;
690  TS_ASSERT_THROWS( t[ idx ], 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 ], 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 ], WException );
718 
719  idx.push_back( 0 ); // idx == [ 0 ]
720  TS_ASSERT_THROWS( t[ idx ], WException );
721  idx.push_back( 1 ); // idx == [ 0, 1 ]
722  TS_ASSERT_THROWS( t[ idx ], WException );
723  idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
724  TS_ASSERT_THROWS( t[ idx ], WException );
725  idx.push_back( 1 );
726  TS_ASSERT_THROWS( t[ idx ], WException );
727  idx.push_back( 1 );
728  TS_ASSERT_THROWS( t[ idx ], 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 ], 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 ], WException );
1335 
1336  idx[ 3 ] = 2;
1337  idx[ 0 ] = 4537; // idx == [ 4537, 1, 2, 2 ]
1338  TS_ASSERT_THROWS( t[ idx ], WException );
1339 
1340  idx[ 0 ] = -434; // idx == [ -434, 1, 2, 2 ]
1341  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
1384 
1385  idx[ 0 ] = 4537;
1386  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
1411 
1412  idx[ 0 ] = -1;
1413  TS_ASSERT_THROWS( t[ idx ], WException );
1414 
1415  idx[ 2 ] = 2;
1416  idx[ 0 ] = 4537;
1417  TS_ASSERT_THROWS( t[ idx ], 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  {
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  {
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 ], WException );
1646 
1647  idx.push_back( 0 ); // idx == [ 0 ]
1648  TS_ASSERT_THROWS( t[ idx ], WException );
1649  idx.push_back( 1 ); // idx == [ 0, 1 ]
1650  TS_ASSERT_THROWS( t[ idx ], WException );
1651  idx.push_back( 2 ); // idx == [ 0, 1, 2 ]
1652  TS_ASSERT_THROWS( t[ idx ], 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 ], WException );
1672 
1673  idx[ 0 ] = 4;
1674  TS_ASSERT_THROWS( t[ idx ], WException );
1675 
1676  idx[ 0 ] = 3;
1677  idx[ 3 ] = -1;
1678  TS_ASSERT_THROWS( t[ idx ], WException );
1679 
1680  idx[ 3 ] = 4;
1681  TS_ASSERT_THROWS( t[ idx ], 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 ], 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 ], WException );
1709 
1710  idx.push_back( 0 ); // idx == [ 0 ]
1711  TS_ASSERT_THROWS( t[ idx ], WException );
1712  idx.push_back( 1 ); // idx == [ 0, 1 ]
1713  TS_ASSERT_THROWS( t[ idx ], WException );
1714  idx.push_back( 0 ); // idx == [ 0, 1, 0 ]
1715  TS_ASSERT_THROWS( t[ idx ], WException );
1716  idx.push_back( 1 );
1717  TS_ASSERT_THROWS( t[ idx ], WException );
1718  idx.push_back( 1 );
1719  TS_ASSERT_THROWS( t[ idx ], 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
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 ), WException );
1983  TS_ASSERT_THROWS( f( 0, 654465, 0 ), WException );
1984  TS_ASSERT_THROWS( f( 4, 0, 0 ), WException );
1985  TS_ASSERT_THROWS( f( 0, 0, 45 ), WException );
1986  TS_ASSERT_THROWS( f( 0, 64, 0 ), WException );
1987  TS_ASSERT_THROWS( f( 792, 981, 5645 ), 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 ), WException );
1999  TS_ASSERT_THROWS( f( 5436 ), WException );
2000  }
2001 
2002  // now try a symmetric tensor base
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 ), WException );
2015  TS_ASSERT_THROWS( f( 3, 457 ), WException );
2016  }
2017  }
2018 
2019  /**
2020  * Test if operator () returns the correct elements.
2021  */
2023  {
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  {
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
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  {
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  {
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  {
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  {
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  {
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 #undefine WASSERT_FLAG_CHANGED
2490 #endif
2491 
2492 #endif // WTENSORBASE_TEST_H