Line data Source code
1 : /**
2 : * @file test_DataContainer.cpp
3 : *
4 : * @brief Tests for DataContainer class
5 : *
6 : * @author Matthias Wieczorek - initial code
7 : * @author David Frank - rewrite to use doctest and BDD
8 : * @author Tobias Lasser - rewrite and added code coverage
9 : */
10 :
11 : #include "doctest/doctest.h"
12 : #include "DataContainer.h"
13 : #include "IdenticalBlocksDescriptor.h"
14 : #include "testHelpers.h"
15 : #include "VolumeDescriptor.h"
16 :
17 : #include <type_traits>
18 :
19 : using namespace elsa;
20 : using namespace doctest;
21 :
22 : // Provides object to be used with TEMPLATE_PRODUCT_TEST_CASE, necessary because enum cannot be
23 : // passed directly
24 : template <typename T>
25 : struct TestHelperGPU {
26 : static const DataHandlerType handler_t = DataHandlerType::GPU;
27 : using data_t = T;
28 : };
29 :
30 : // Provides object to be used with TEMPLATE_PRODUCT_TEST_CASE, necessary because enum cannot be
31 : // passed directly
32 : template <typename T>
33 : struct TestHelperCPU {
34 : static const DataHandlerType handler_t = DataHandlerType::CPU;
35 : using data_t = T;
36 : };
37 :
38 : using CPUTypeTuple =
39 : std::tuple<TestHelperCPU<float>, TestHelperCPU<double>, TestHelperCPU<complex<float>>,
40 : TestHelperCPU<complex<double>>, TestHelperCPU<index_t>>;
41 :
42 : TYPE_TO_STRING(TestHelperCPU<float>);
43 : TYPE_TO_STRING(TestHelperCPU<double>);
44 : TYPE_TO_STRING(TestHelperCPU<index_t>);
45 : TYPE_TO_STRING(TestHelperCPU<complex<float>>);
46 : TYPE_TO_STRING(TestHelperCPU<complex<double>>);
47 :
48 : TYPE_TO_STRING(DataContainer<float>);
49 : TYPE_TO_STRING(DataContainer<double>);
50 : TYPE_TO_STRING(DataContainer<index_t>);
51 : TYPE_TO_STRING(DataContainer<complex<float>>);
52 : TYPE_TO_STRING(DataContainer<complex<double>>);
53 :
54 : TYPE_TO_STRING(complex<float>);
55 : TYPE_TO_STRING(complex<double>);
56 :
57 : #ifdef ELSA_CUDA_VECTOR
58 : using GPUTypeTuple =
59 : std::tuple<TestHelperGPU<float>, TestHelperGPU<double>, TestHelperGPU<complex<float>>,
60 : TestHelperGPU<complex<double>>, TestHelperGPU<index_t>>;
61 :
62 : TYPE_TO_STRING(TestHelperGPU<float>);
63 : TYPE_TO_STRING(TestHelperGPU<double>);
64 : TYPE_TO_STRING(TestHelperGPU<index_t>);
65 : TYPE_TO_STRING(TestHelperGPU<complex<float>>);
66 : TYPE_TO_STRING(TestHelperGPU<complex<double>>);
67 : #endif
68 :
69 : TEST_SUITE_BEGIN("core");
70 :
71 : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing construction", TestType,
72 : datacontainer_construction)
73 50 : {
74 50 : using data_t = typename TestType::data_t;
75 :
76 50 : INFO("Testing type: " << TypeName_v<const data_t>);
77 :
78 50 : GIVEN("a DataDescriptor")
79 50 : {
80 20 : IndexVector_t numCoeff(3);
81 20 : numCoeff << 17, 47, 91;
82 20 : VolumeDescriptor desc(numCoeff);
83 :
84 20 : WHEN("constructing an empty DataContainer")
85 20 : {
86 10 : DataContainer<data_t> dc(desc, TestType::handler_t);
87 :
88 10 : THEN("it has the correct DataDescriptor") { REQUIRE_EQ(dc.getDataDescriptor(), desc); }
89 :
90 10 : THEN("it has a data vector of correct size")
91 10 : {
92 5 : REQUIRE_EQ(dc.getSize(), desc.getNumberOfCoefficients());
93 5 : }
94 10 : }
95 :
96 20 : WHEN("constructing an initialized DataContainer")
97 20 : {
98 10 : auto data = generateRandomMatrix<data_t>(desc.getNumberOfCoefficients());
99 :
100 10 : DataContainer<data_t> dc(desc, data, TestType::handler_t);
101 :
102 10 : THEN("it has the correct DataDescriptor") { REQUIRE_EQ(dc.getDataDescriptor(), desc); }
103 :
104 10 : THEN("it has correctly initialized data")
105 10 : {
106 5 : REQUIRE_EQ(dc.getSize(), desc.getNumberOfCoefficients());
107 :
108 363550 : for (index_t i = 0; i < dc.getSize(); ++i)
109 5 : REQUIRE_UNARY(checkApproxEq(dc[i], data[i]));
110 5 : }
111 10 : }
112 20 : }
113 :
114 50 : GIVEN("another DataContainer")
115 50 : {
116 30 : IndexVector_t numCoeff(2);
117 30 : numCoeff << 32, 57;
118 30 : VolumeDescriptor desc(numCoeff);
119 :
120 30 : DataContainer<data_t> otherDc(desc, TestType::handler_t);
121 :
122 30 : auto randVec = generateRandomMatrix<data_t>(otherDc.getSize());
123 54750 : for (index_t i = 0; i < otherDc.getSize(); ++i)
124 54720 : otherDc[i] = randVec(i);
125 :
126 30 : WHEN("copy constructing")
127 30 : {
128 5 : DataContainer dc(otherDc);
129 :
130 5 : THEN("it copied correctly")
131 5 : {
132 5 : REQUIRE_EQ(dc.getDataDescriptor(), otherDc.getDataDescriptor());
133 5 : REQUIRE_NE(&dc.getDataDescriptor(), &otherDc.getDataDescriptor());
134 :
135 5 : REQUIRE_EQ(dc, otherDc);
136 5 : }
137 5 : }
138 :
139 30 : WHEN("copy assigning")
140 30 : {
141 5 : DataContainer<data_t> dc(desc, TestType::handler_t);
142 5 : dc = otherDc;
143 :
144 5 : THEN("it copied correctly")
145 5 : {
146 5 : REQUIRE_EQ(dc.getDataDescriptor(), otherDc.getDataDescriptor());
147 5 : REQUIRE_NE(&dc.getDataDescriptor(), &otherDc.getDataDescriptor());
148 :
149 5 : REQUIRE_EQ(dc, otherDc);
150 5 : }
151 5 : }
152 :
153 30 : WHEN("move constructing")
154 30 : {
155 10 : DataContainer oldOtherDc(otherDc);
156 :
157 10 : DataContainer dc(std::move(otherDc));
158 :
159 10 : THEN("it moved correctly")
160 10 : {
161 5 : REQUIRE_EQ(dc.getDataDescriptor(), oldOtherDc.getDataDescriptor());
162 :
163 5 : REQUIRE_EQ(dc, oldOtherDc);
164 5 : }
165 :
166 10 : THEN("the moved from object is still valid (but empty)") { otherDc = dc; }
167 10 : }
168 :
169 30 : WHEN("move assigning")
170 30 : {
171 10 : DataContainer oldOtherDc(otherDc);
172 :
173 10 : DataContainer<data_t> dc(desc, TestType::handler_t);
174 10 : dc = std::move(otherDc);
175 :
176 10 : THEN("it moved correctly")
177 10 : {
178 5 : REQUIRE_EQ(dc.getDataDescriptor(), oldOtherDc.getDataDescriptor());
179 :
180 5 : REQUIRE_EQ(dc, oldOtherDc);
181 5 : }
182 :
183 10 : THEN("the moved from object is still valid (but empty)") { otherDc = dc; }
184 10 : }
185 30 : }
186 50 : }
187 :
188 : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing the reduction operations", TestType,
189 : datacontainer_reduction)
190 5 : {
191 5 : using data_t = typename TestType::data_t;
192 :
193 5 : INFO("Testing type: " << TypeName_v<const data_t>);
194 :
195 5 : GIVEN("a DataContainer")
196 5 : {
197 5 : IndexVector_t numCoeff(3);
198 5 : numCoeff << 11, 73, 45;
199 5 : VolumeDescriptor desc(numCoeff);
200 :
201 5 : WHEN("putting in some random data")
202 5 : {
203 5 : auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
204 :
205 5 : THEN("the reductions work a expected")
206 5 : {
207 5 : REQUIRE_UNARY(checkApproxEq(dc.sum(), randVec.sum()));
208 5 : REQUIRE_UNARY(checkApproxEq(
209 5 : dc.l0PseudoNorm(),
210 5 : (randVec.array().cwiseAbs()
211 5 : >= std::numeric_limits<GetFloatingPointType_t<data_t>>::epsilon())
212 5 : .count()));
213 5 : REQUIRE_UNARY(checkApproxEq(dc.l1Norm(), randVec.array().abs().sum()));
214 5 : REQUIRE_UNARY(checkApproxEq(dc.lInfNorm(), randVec.array().abs().maxCoeff()));
215 5 : REQUIRE_UNARY(checkApproxEq(dc.squaredL2Norm(), randVec.squaredNorm()));
216 :
217 5 : auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
218 :
219 5 : REQUIRE_UNARY(checkApproxEq(dc.dot(dc2), randVec.dot(randVec2)));
220 :
221 5 : if constexpr (isComplex<data_t>) {
222 3 : CHECK_THROWS(dc.minElement());
223 3 : CHECK_THROWS(dc.maxElement());
224 3 : } else {
225 3 : REQUIRE_UNARY(checkApproxEq(dc.minElement(), randVec.array().minCoeff()));
226 3 : REQUIRE_UNARY(checkApproxEq(dc.maxElement(), randVec.array().maxCoeff()));
227 3 : }
228 5 : }
229 5 : }
230 5 : }
231 5 : }
232 :
233 : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing element-wise access", TestType,
234 : datacontainer_elemwise)
235 75 : {
236 75 : using data_t = typename TestType::data_t;
237 :
238 75 : INFO("Testing type: " << TypeName_v<const data_t>);
239 :
240 75 : GIVEN("a DataContainer")
241 75 : {
242 5 : IndexVector_t numCoeff(2);
243 5 : numCoeff << 47, 11;
244 5 : VolumeDescriptor desc(numCoeff);
245 5 : DataContainer<data_t> dc(desc, TestType::handler_t);
246 :
247 5 : WHEN("accessing the elements")
248 5 : {
249 5 : IndexVector_t coord(2);
250 5 : coord << 17, 4;
251 5 : index_t index = desc.getIndexFromCoordinate(coord);
252 :
253 5 : THEN("it works as expected when using indices/coordinates")
254 5 : {
255 : // For integral typeps don't have a floating point value
256 5 : if constexpr (std::is_integral_v<data_t>) {
257 4 : dc[index] = data_t(2);
258 4 : REQUIRE_UNARY(checkApproxEq(dc[index], 2));
259 4 : REQUIRE_UNARY(checkApproxEq(dc(coord), 2));
260 4 : REQUIRE_UNARY(checkApproxEq(dc(17, 4), 2));
261 :
262 4 : dc(coord) = data_t(3);
263 4 : REQUIRE_UNARY(checkApproxEq(dc[index], 3));
264 4 : REQUIRE_UNARY(checkApproxEq(dc(coord), 3));
265 4 : REQUIRE_UNARY(checkApproxEq(dc(17, 4), 3));
266 4 : } else {
267 4 : dc[index] = data_t(2.2f);
268 4 : REQUIRE_UNARY(checkApproxEq(dc[index], 2.2f));
269 4 : REQUIRE_UNARY(checkApproxEq(dc(coord), 2.2f));
270 4 : REQUIRE_UNARY(checkApproxEq(dc(17, 4), 2.2f));
271 :
272 4 : dc(coord) = data_t(3.3f);
273 4 : REQUIRE_UNARY(checkApproxEq(dc[index], 3.3f));
274 4 : REQUIRE_UNARY(checkApproxEq(dc(coord), 3.3f));
275 4 : REQUIRE_UNARY(checkApproxEq(dc(17, 4), 3.3f));
276 4 : }
277 5 : }
278 5 : }
279 5 : }
280 :
281 75 : GIVEN("a DataContainer")
282 75 : {
283 70 : IndexVector_t numCoeff(2);
284 70 : numCoeff << 47, 11;
285 70 : VolumeDescriptor desc(numCoeff);
286 :
287 70 : WHEN("putting in some random data")
288 70 : {
289 30 : auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
290 :
291 30 : THEN("the element-wise unary operations work as expected")
292 30 : {
293 5 : DataContainer dcAbs = cwiseAbs(dc);
294 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
295 5 : REQUIRE_UNARY(checkApproxEq(dcAbs[i], randVec.array().abs()[i]));
296 :
297 5 : DataContainer dcSquare = square(dc);
298 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
299 5 : REQUIRE_UNARY(checkApproxEq(dcSquare[i], randVec.array().square()[i]));
300 5 : DataContainer dcSqrt = sqrt(dcSquare);
301 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
302 5 : REQUIRE_UNARY(checkApproxEq(dcSqrt[i], randVec.array().square().sqrt()[i]));
303 :
304 : // do exponent check only for floating point types as for integer will likely
305 : // lead to overflow due to random init over full value range
306 5 : if constexpr (!std::is_integral_v<data_t>) {
307 4 : DataContainer dcExp = exp(dc);
308 2072 : for (index_t i = 0; i < dc.getSize(); ++i)
309 4 : REQUIRE_UNARY(checkApproxEq(dcExp[i], randVec.array().exp()[i]));
310 4 : }
311 :
312 5 : DataContainer dcLog = log(dcSquare);
313 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
314 5 : REQUIRE_UNARY(checkApproxEq(dcLog[i], randVec.array().square().log()[i]));
315 :
316 5 : DataContainer dcReal = real(dc);
317 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
318 5 : REQUIRE_UNARY(checkApproxEq(dcReal[i], randVec.array().real()[i]));
319 :
320 5 : DataContainer dcImag = imag(dc);
321 :
322 5 : if constexpr (isComplex<data_t>) {
323 1036 : for (index_t i = 0; i < dc.getSize(); ++i)
324 3 : REQUIRE_UNARY(checkApproxEq(dcImag[i], randVec.array().imag()[i]));
325 3 : } else {
326 1554 : for (index_t i = 0; i < dc.getSize(); ++i)
327 3 : REQUIRE_UNARY(checkApproxEq(dcImag[i], 0));
328 3 : }
329 5 : }
330 :
331 30 : auto scalar = static_cast<data_t>(923.41f);
332 :
333 30 : THEN("the binary in-place addition of a scalar work as expected")
334 30 : {
335 5 : dc += scalar;
336 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
337 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) + scalar));
338 5 : }
339 :
340 30 : THEN("the binary in-place subtraction of a scalar work as expected")
341 30 : {
342 5 : dc -= scalar;
343 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
344 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) - scalar));
345 5 : }
346 :
347 30 : THEN("the binary in-place multiplication with a scalar work as expected")
348 30 : {
349 5 : dc *= scalar;
350 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
351 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) * scalar));
352 5 : }
353 :
354 30 : THEN("the binary in-place division by a scalar work as expected")
355 30 : {
356 5 : dc /= scalar;
357 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
358 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) / scalar));
359 5 : }
360 :
361 30 : THEN("the element-wise assignment of a scalar works as expected")
362 30 : {
363 5 : dc = scalar;
364 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
365 5 : REQUIRE_UNARY(checkApproxEq(dc[i], scalar));
366 5 : }
367 30 : }
368 :
369 70 : WHEN("having two containers with random data")
370 70 : {
371 20 : auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
372 20 : auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
373 :
374 20 : THEN("the element-wise in-place addition works as expected")
375 20 : {
376 5 : dc += dc2;
377 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
378 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) + randVec2(i)));
379 5 : }
380 :
381 20 : THEN("the element-wise in-place subtraction works as expected")
382 20 : {
383 5 : dc -= dc2;
384 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
385 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) - randVec2(i)));
386 5 : }
387 :
388 20 : THEN("the element-wise in-place multiplication works as expected")
389 20 : {
390 5 : dc *= dc2;
391 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
392 5 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) * randVec2(i)));
393 5 : }
394 :
395 20 : THEN("the element-wise in-place division works as expected")
396 20 : {
397 5 : dc /= dc2;
398 2590 : for (index_t i = 0; i < dc.getSize(); ++i)
399 2585 : if (dc2[i] != data_t(0))
400 2585 : REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) / randVec2(i)));
401 5 : }
402 20 : }
403 :
404 70 : WHEN("having two containers with real and complex data each")
405 70 : {
406 20 : auto [dcReals1, realsVec1] = generateRandomContainer<real_t>(desc, TestType::handler_t);
407 20 : auto [dcComps1, compsVec1] =
408 20 : generateRandomContainer<complex<real_t>>(desc, TestType::handler_t);
409 :
410 20 : THEN("the element-wise maximum operation works as expected for two real "
411 20 : "DataContainers")
412 20 : {
413 5 : auto [dcReals2, realsVec2] =
414 5 : generateRandomContainer<real_t>(desc, TestType::handler_t);
415 :
416 5 : DataContainer dcCWiseMax = cwiseMax(dcReals1, dcReals2);
417 2590 : for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
418 5 : REQUIRE_UNARY(
419 5 : checkApproxEq(dcCWiseMax[i], realsVec1.array().max(realsVec2.array())[i]));
420 5 : }
421 :
422 20 : THEN("the element-wise maximum operation works as expected for a real and a complex "
423 20 : "DataContainer")
424 20 : {
425 5 : auto [dcComps2, compsVec2] =
426 5 : generateRandomContainer<complex<real_t>>(desc, TestType::handler_t);
427 :
428 5 : DataContainer dcCWiseMax = cwiseMax(dcReals1, dcComps2);
429 2590 : for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
430 5 : REQUIRE_UNARY(checkApproxEq(dcCWiseMax[i],
431 5 : realsVec1.array().max(compsVec2.array().abs())[i]));
432 5 : }
433 :
434 20 : THEN("the element-wise maximum operation works as expected for a complex and a real "
435 20 : "DataContainer")
436 20 : {
437 5 : auto [dcComps2, compsVec2] =
438 5 : generateRandomContainer<complex<real_t>>(desc, TestType::handler_t);
439 :
440 5 : DataContainer dcCWiseMax = cwiseMax(dcComps2, dcReals1);
441 2590 : for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
442 5 : REQUIRE_UNARY(checkApproxEq(dcCWiseMax[i],
443 5 : compsVec2.array().abs().max(realsVec1.array())[i]));
444 5 : }
445 :
446 20 : THEN("the element-wise maximum operation works as expected for two DataContainers")
447 20 : {
448 5 : auto [dcComps2, compsVec2] =
449 5 : generateRandomContainer<complex<real_t>>(desc, TestType::handler_t);
450 :
451 5 : DataContainer dcCWiseMax = cwiseMax(dcComps1, dcComps2);
452 2590 : for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
453 5 : REQUIRE_UNARY(checkApproxEq(
454 5 : dcCWiseMax[i], compsVec1.array().abs().max(compsVec2.array().abs())[i]));
455 5 : }
456 20 : }
457 70 : }
458 75 : }
459 :
460 : TEST_CASE_TEMPLATE_DEFINE(
461 : "DataContainer: Testing the arithmetic operations with DataContainers arguments", TestType,
462 : datacontainer_arithmetic)
463 10 : {
464 10 : using data_t = typename TestType::data_t;
465 :
466 10 : INFO("Testing type: " << TypeName_v<const data_t>);
467 :
468 10 : GIVEN("some DataContainers")
469 10 : {
470 10 : IndexVector_t numCoeff(3);
471 10 : numCoeff << 52, 7, 29;
472 10 : VolumeDescriptor desc(numCoeff);
473 :
474 10 : auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
475 10 : auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
476 :
477 10 : THEN("the binary element-wise operations work as expected")
478 10 : {
479 5 : DataContainer resultPlus = dc + dc2;
480 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
481 5 : REQUIRE_UNARY(checkApproxEq(resultPlus[i], dc[i] + dc2[i]));
482 :
483 5 : DataContainer resultMinus = dc - dc2;
484 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
485 5 : REQUIRE_UNARY(checkApproxEq(resultMinus[i], dc[i] - dc2[i]));
486 :
487 5 : DataContainer resultMult = dc * dc2;
488 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
489 5 : REQUIRE_UNARY(checkApproxEq(resultMult[i], dc[i] * dc2[i]));
490 :
491 5 : DataContainer resultDiv = dc / dc2;
492 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
493 52780 : if (dc2[i] != data_t(0))
494 52780 : REQUIRE_UNARY(checkApproxEq(resultDiv[i], dc[i] / dc2[i]));
495 5 : }
496 :
497 10 : THEN("the operations with a scalar work as expected")
498 10 : {
499 5 : data_t scalar = static_cast<data_t>(4.92f);
500 :
501 5 : DataContainer resultScalarPlus = scalar + dc;
502 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
503 5 : REQUIRE_UNARY(checkApproxEq(resultScalarPlus[i], scalar + dc[i]));
504 :
505 5 : DataContainer resultPlusScalar = dc + scalar;
506 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
507 5 : REQUIRE_UNARY(checkApproxEq(resultPlusScalar[i], dc[i] + scalar));
508 :
509 5 : DataContainer resultScalarMinus = scalar - dc;
510 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
511 5 : REQUIRE_UNARY(checkApproxEq(resultScalarMinus[i], scalar - dc[i]));
512 :
513 5 : DataContainer resultMinusScalar = dc - scalar;
514 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
515 5 : REQUIRE_UNARY(checkApproxEq(resultMinusScalar[i], dc[i] - scalar));
516 :
517 5 : DataContainer resultScalarMult = scalar * dc;
518 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
519 5 : REQUIRE_UNARY(checkApproxEq(resultScalarMult[i], scalar * dc[i]));
520 :
521 5 : DataContainer resultMultScalar = dc * scalar;
522 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
523 5 : REQUIRE_UNARY(checkApproxEq(resultMultScalar[i], dc[i] * scalar));
524 :
525 5 : DataContainer resultScalarDiv = scalar / dc;
526 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
527 52780 : if (dc[i] != data_t(0))
528 52780 : REQUIRE_UNARY(checkApproxEq(resultScalarDiv[i], scalar / dc[i]));
529 :
530 5 : DataContainer resultDivScalar = dc / scalar;
531 52785 : for (index_t i = 0; i < dc.getSize(); ++i)
532 5 : REQUIRE_UNARY(checkApproxEq(resultDivScalar[i], dc[i] / scalar));
533 5 : }
534 10 : }
535 10 : }
536 :
537 : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing creation of Maps through DataContainer", TestType,
538 : datacontainer_maps)
539 20 : {
540 20 : using data_t = typename TestType::data_t;
541 :
542 20 : INFO("Testing type: " << TypeName_v<const data_t>);
543 :
544 20 : GIVEN("a non-blocked container")
545 20 : {
546 10 : IndexVector_t numCoeff(3);
547 10 : numCoeff << 52, 7, 29;
548 10 : VolumeDescriptor desc(numCoeff);
549 :
550 10 : DataContainer<data_t> dc(desc, TestType::handler_t);
551 10 : const DataContainer<data_t> constDc(desc, TestType::handler_t);
552 :
553 10 : WHEN("trying to reference a block")
554 10 : {
555 5 : THEN("an exception occurs")
556 5 : {
557 5 : REQUIRE_THROWS(dc.getBlock(0));
558 5 : REQUIRE_THROWS(constDc.getBlock(0));
559 5 : }
560 5 : }
561 :
562 10 : WHEN("creating a view")
563 10 : {
564 5 : IndexVector_t numCoeff(1);
565 5 : numCoeff << desc.getNumberOfCoefficients();
566 5 : VolumeDescriptor linearDesc(numCoeff);
567 5 : auto linearDc = dc.viewAs(linearDesc);
568 5 : auto linearConstDc = constDc.viewAs(linearDesc);
569 :
570 5 : THEN("view has the correct descriptor and data")
571 5 : {
572 5 : REQUIRE_EQ(linearDesc, linearDc.getDataDescriptor());
573 5 : REQUIRE_EQ(&linearDc[0], &dc[0]);
574 :
575 5 : REQUIRE_EQ(linearDesc, linearConstDc.getDataDescriptor());
576 5 : REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
577 :
578 5 : AND_THEN("view is not a shallow copy")
579 5 : {
580 5 : const auto dcCopy = dc;
581 5 : const auto constDcCopy = constDc;
582 :
583 5 : linearDc[0] = 1;
584 5 : REQUIRE_EQ(&linearDc[0], &dc[0]);
585 5 : REQUIRE_NE(&linearDc[0], &dcCopy[0]);
586 :
587 5 : linearConstDc[0] = 1;
588 5 : REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
589 5 : REQUIRE_NE(&linearConstDc[0], &constDcCopy[0]);
590 5 : }
591 5 : }
592 5 : }
593 10 : }
594 :
595 20 : GIVEN("a blocked container")
596 20 : {
597 10 : IndexVector_t numCoeff(2);
598 10 : numCoeff << 52, 29;
599 10 : VolumeDescriptor desc(numCoeff);
600 10 : index_t numBlocks = 7;
601 10 : IdenticalBlocksDescriptor blockDesc(numBlocks, desc);
602 :
603 10 : DataContainer<data_t> dc(blockDesc, TestType::handler_t);
604 10 : const DataContainer<data_t> constDc(blockDesc, TestType::handler_t);
605 :
606 10 : WHEN("referencing a block")
607 10 : {
608 5 : THEN("block has the correct descriptor and data")
609 5 : {
610 40 : for (index_t i = 0; i < numBlocks; i++) {
611 35 : auto dcBlock = dc.getBlock(i);
612 35 : const auto constDcBlock = constDc.getBlock(i);
613 :
614 35 : REQUIRE_EQ(dcBlock.getDataDescriptor(), blockDesc.getDescriptorOfBlock(i));
615 35 : REQUIRE_EQ(&dcBlock[0], &dc[0] + blockDesc.getOffsetOfBlock(i));
616 :
617 35 : REQUIRE_EQ(constDcBlock.getDataDescriptor(), blockDesc.getDescriptorOfBlock(i));
618 35 : REQUIRE_EQ(&constDcBlock[0], &constDc[0] + blockDesc.getOffsetOfBlock(i));
619 35 : }
620 5 : }
621 5 : }
622 :
623 10 : WHEN("creating a view")
624 10 : {
625 5 : IndexVector_t numCoeff(1);
626 5 : numCoeff << blockDesc.getNumberOfCoefficients();
627 5 : VolumeDescriptor linearDesc(numCoeff);
628 5 : auto linearDc = dc.viewAs(linearDesc);
629 5 : auto linearConstDc = constDc.viewAs(linearDesc);
630 :
631 5 : THEN("view has the correct descriptor and data")
632 5 : {
633 5 : REQUIRE_EQ(linearDesc, linearDc.getDataDescriptor());
634 5 : REQUIRE_EQ(&linearDc[0], &dc[0]);
635 :
636 5 : REQUIRE_EQ(linearDesc, linearConstDc.getDataDescriptor());
637 5 : REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
638 :
639 5 : AND_THEN("view is not a shallow copy")
640 5 : {
641 5 : const auto dcCopy = dc;
642 5 : const auto constDcCopy = constDc;
643 :
644 5 : linearDc[0] = 1;
645 5 : REQUIRE_EQ(&linearDc[0], &dc[0]);
646 5 : REQUIRE_NE(&linearDc[0], &dcCopy[0]);
647 :
648 5 : linearConstDc[0] = 1;
649 5 : REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
650 5 : REQUIRE_NE(&linearConstDc[0], &constDcCopy[0]);
651 5 : }
652 5 : }
653 5 : }
654 10 : }
655 20 : }
656 :
657 : #ifdef ELSA_CUDA_VECTOR
658 : TEST_CASE_TEMPLATE("DataContainer: Testing load data to GPU and vice versa", TestType, float,
659 : double, complex<float>, complex<double>, index_t)
660 : {
661 : GIVEN("A CPU DataContainer with random data")
662 : {
663 : IndexVector_t numCoeff(3);
664 : numCoeff << 52, 7, 29;
665 : VolumeDescriptor desc(numCoeff);
666 :
667 : DataContainer<TestType> dcCPU(desc, DataHandlerType::CPU);
668 : DataContainer<TestType> dcGPU(desc, DataHandlerType::GPU);
669 :
670 : auto randVec = generateRandomMatrix<TestType>(dcCPU.getSize());
671 :
672 : for (index_t i = 0; i < dcCPU.getSize(); ++i) {
673 : dcCPU[i] = randVec(i);
674 : dcGPU[i] = randVec(i);
675 : }
676 :
677 : WHEN("Trying to call loadToCPU on CPU container")
678 : {
679 : THEN("Throws") { REQUIRE_THROWS(dcCPU.loadToCPU()); }
680 : }
681 :
682 : WHEN("Trying to call loadToGPU on GPU container")
683 : {
684 : THEN("Throws") { REQUIRE_THROWS(dcGPU.loadToGPU()); }
685 : }
686 :
687 : WHEN("Loading to GPU from CPU")
688 : {
689 : DataContainer dcGPU2 = dcCPU.loadToGPU();
690 :
691 : REQUIRE_EQ(dcGPU2.getDataHandlerType(), DataHandlerType::GPU);
692 :
693 : THEN("all elements have to be the same")
694 : {
695 : for (index_t i = 0; i < dcCPU.getSize(); ++i) {
696 : REQUIRE_UNARY(checkApproxEq(dcGPU2[i], dcGPU[i]));
697 : }
698 : }
699 : }
700 :
701 : WHEN("Loading to CPU from GPU")
702 : {
703 : DataContainer dcCPU2 = dcGPU.loadToCPU();
704 :
705 : REQUIRE_EQ(dcCPU2.getDataHandlerType(), DataHandlerType::CPU);
706 :
707 : THEN("all elements have to be the same")
708 : {
709 : for (index_t i = 0; i < dcCPU.getSize(); ++i) {
710 : REQUIRE_UNARY(checkApproxEq(dcCPU2[i], dcGPU[i]));
711 : }
712 : }
713 : }
714 :
715 : WHEN("copy-assigning a GPU to a CPU container")
716 : {
717 : dcCPU = dcGPU;
718 :
719 : THEN("it should be a GPU container")
720 : {
721 : REQUIRE_EQ(dcCPU.getDataHandlerType(), DataHandlerType::GPU);
722 : }
723 :
724 : AND_THEN("they should be equal")
725 : {
726 : REQUIRE_EQ(dcCPU, dcGPU);
727 : REQUIRE_EQ(dcCPU.getSize(), dcGPU.getSize());
728 :
729 : for (index_t i = 0; i < dcCPU.getSize(); ++i) {
730 : REQUIRE_UNARY(checkApproxEq(dcCPU[i], dcGPU[i]));
731 : }
732 : }
733 : }
734 :
735 : WHEN("copy-assigning a CPU to a GPU container")
736 : {
737 : dcGPU = dcCPU;
738 :
739 : THEN("it should be a GPU container")
740 : {
741 : REQUIRE_EQ(dcGPU.getDataHandlerType(), DataHandlerType::CPU);
742 : }
743 :
744 : AND_THEN("they should be equal")
745 : {
746 : REQUIRE_EQ(dcCPU, dcGPU);
747 : REQUIRE_EQ(dcCPU.getSize(), dcGPU.getSize());
748 :
749 : for (index_t i = 0; i < dcCPU.getSize(); ++i) {
750 : REQUIRE_UNARY(checkApproxEq(dcCPU[i], dcGPU[i]));
751 : }
752 : }
753 : }
754 : }
755 : }
756 : #endif
757 :
758 : TEST_CASE("DataContainer: Testing iterators for DataContainer")
759 12 : {
760 12 : GIVEN("A 1D container")
761 12 : {
762 4 : constexpr index_t size = 20;
763 4 : IndexVector_t numCoeff(1);
764 4 : numCoeff << size;
765 4 : VolumeDescriptor desc(numCoeff);
766 :
767 4 : DataContainer dc1(desc);
768 4 : DataContainer dc2(desc);
769 :
770 4 : Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size);
771 4 : Eigen::VectorXf randVec2 = Eigen::VectorXf::Random(size);
772 :
773 84 : for (index_t i = 0; i < size; ++i) {
774 80 : dc1[i] = randVec1(i);
775 80 : dc2[i] = randVec2(i);
776 80 : }
777 :
778 4 : THEN("We can iterate forward")
779 4 : {
780 1 : int i = 0;
781 21 : for (auto v = dc1.cbegin(); v != dc1.cend(); v++) {
782 20 : REQUIRE_UNARY(checkApproxEq(*v, randVec1[i++]));
783 20 : }
784 1 : REQUIRE_EQ(i, size);
785 1 : }
786 :
787 4 : THEN("We can iterate backward")
788 4 : {
789 1 : int i = size;
790 21 : for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
791 20 : REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
792 20 : }
793 1 : REQUIRE_EQ(i, 0);
794 1 : }
795 :
796 4 : THEN("We can iterate and mutate")
797 4 : {
798 1 : int i = 0;
799 20 : for (auto& v : dc1) {
800 20 : v = v * 2;
801 20 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
802 20 : }
803 1 : REQUIRE_EQ(i, size);
804 :
805 1 : i = 0;
806 20 : for (auto v : dc1) {
807 20 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
808 20 : }
809 1 : REQUIRE_EQ(i, size);
810 1 : }
811 :
812 4 : THEN("We can use STL algorithms")
813 4 : {
814 1 : REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
815 1 : REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
816 1 : }
817 4 : }
818 12 : GIVEN("A 2D container")
819 12 : {
820 4 : constexpr index_t size = 20;
821 4 : IndexVector_t numCoeff(2);
822 4 : numCoeff << size, size;
823 4 : VolumeDescriptor desc(numCoeff);
824 :
825 4 : DataContainer dc1(desc);
826 :
827 4 : Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size);
828 :
829 1604 : for (index_t i = 0; i < dc1.getSize(); ++i) {
830 1600 : dc1[i] = randVec1[i];
831 1600 : }
832 :
833 4 : THEN("We can iterate forward")
834 4 : {
835 1 : int i = 0;
836 400 : for (auto v : dc1) {
837 400 : REQUIRE_UNARY(checkApproxEq(v, randVec1[i++]));
838 400 : }
839 1 : REQUIRE_EQ(i, size * size);
840 1 : }
841 :
842 4 : THEN("We can iterate backward")
843 4 : {
844 1 : int i = size * size;
845 401 : for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
846 400 : REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
847 400 : }
848 1 : REQUIRE_EQ(i, 0);
849 1 : }
850 :
851 4 : THEN("We can iterate and mutate")
852 4 : {
853 1 : int i = 0;
854 400 : for (auto& v : dc1) {
855 400 : v = v * 2;
856 400 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
857 400 : }
858 1 : REQUIRE_EQ(i, size * size);
859 :
860 1 : i = 0;
861 400 : for (auto v : dc1) {
862 400 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
863 400 : }
864 1 : REQUIRE_EQ(i, size * size);
865 1 : }
866 :
867 4 : THEN("We can use STL algorithms")
868 4 : {
869 1 : REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
870 1 : REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
871 1 : }
872 4 : }
873 12 : GIVEN("A 3D container")
874 12 : {
875 4 : constexpr index_t size = 20;
876 4 : IndexVector_t numCoeff(3);
877 4 : numCoeff << size, size, size;
878 4 : VolumeDescriptor desc(numCoeff);
879 :
880 4 : DataContainer dc1(desc);
881 :
882 4 : Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size * size);
883 :
884 32004 : for (index_t i = 0; i < dc1.getSize(); ++i) {
885 32000 : dc1[i] = randVec1[i];
886 32000 : }
887 :
888 4 : THEN("We can iterate forward")
889 4 : {
890 1 : int i = 0;
891 8000 : for (auto v : dc1) {
892 8000 : REQUIRE_UNARY(checkApproxEq(v, randVec1[i++]));
893 8000 : }
894 1 : REQUIRE_EQ(i, size * size * size);
895 1 : }
896 :
897 4 : THEN("We can iterate backward")
898 4 : {
899 1 : int i = size * size * size;
900 8001 : for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
901 8000 : REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
902 8000 : }
903 1 : REQUIRE_EQ(i, 0);
904 1 : }
905 :
906 4 : THEN("We can iterate and mutate")
907 4 : {
908 1 : int i = 0;
909 8000 : for (auto& v : dc1) {
910 8000 : v = v * 2;
911 8000 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
912 8000 : }
913 1 : REQUIRE_EQ(i, size * size * size);
914 :
915 1 : i = 0;
916 8000 : for (auto v : dc1) {
917 8000 : REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
918 8000 : }
919 1 : REQUIRE_EQ(i, size * size * size);
920 1 : }
921 :
922 4 : THEN("We can use STL algorithms")
923 4 : {
924 1 : REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
925 1 : REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
926 1 : }
927 4 : }
928 12 : }
929 :
930 : TEST_CASE_TEMPLATE("DataContainer: Clip a DataContainer", data_t, float, double)
931 20 : {
932 20 : GIVEN("some 1D vectors")
933 20 : {
934 16 : index_t size = 7;
935 16 : IndexVector_t numCoeff(1);
936 16 : numCoeff << size;
937 16 : VolumeDescriptor desc(numCoeff);
938 :
939 16 : data_t min = 6;
940 16 : data_t max = 19;
941 :
942 16 : Vector_t<data_t> dataVec1(desc.getNumberOfCoefficients());
943 16 : dataVec1 << 6, 10, 7, 18, 10, 11, 9;
944 16 : Vector_t<data_t> expectedDataVec1(desc.getNumberOfCoefficients());
945 16 : expectedDataVec1 << 6, 10, 7, 18, 10, 11, 9;
946 :
947 16 : Vector_t<data_t> dataVec2(desc.getNumberOfCoefficients());
948 16 : dataVec2 << 4, -23, 7, 18, 18, 10, 10;
949 16 : Vector_t<data_t> expectedDataVec2(desc.getNumberOfCoefficients());
950 16 : expectedDataVec2 << min, min, 7, 18, 18, 10, 10;
951 :
952 16 : Vector_t<data_t> dataVec3(desc.getNumberOfCoefficients());
953 16 : dataVec3 << 14, 23, 7, 18, 20, 10, 10;
954 16 : Vector_t<data_t> expectedDataVec3(desc.getNumberOfCoefficients());
955 16 : expectedDataVec3 << 14, max, 7, 18, max, 10, 10;
956 :
957 16 : Vector_t<data_t> dataVec4(desc.getNumberOfCoefficients());
958 16 : dataVec4 << 1, 23, 5, 28, 20, 30, 0;
959 16 : Vector_t<data_t> expectedDataVec4(desc.getNumberOfCoefficients());
960 16 : expectedDataVec4 << min, max, min, max, max, max, min;
961 :
962 16 : WHEN("creating a data container out of a vector within bounds")
963 16 : {
964 4 : DataContainer dc(desc, dataVec1);
965 4 : auto clipped = clip(dc, min, max);
966 :
967 4 : THEN("the size of the clipped DataContainer is equal to that of the original container")
968 4 : {
969 2 : REQUIRE_EQ(clipped.getSize(), size);
970 2 : }
971 :
972 4 : THEN("the values correspond to the original DataContainers")
973 4 : {
974 16 : for (int i = 0; i < size; ++i) {
975 14 : INFO("Error at position: ", i);
976 14 : REQUIRE_EQ(clipped[i], expectedDataVec1[i]);
977 14 : }
978 2 : }
979 4 : }
980 :
981 16 : WHEN("creating a data container out of a vector within or lower than the bounds")
982 16 : {
983 4 : DataContainer dc(desc, dataVec2);
984 4 : auto clipped = clip(dc, min, max);
985 :
986 4 : THEN("the size of the clipped DataContainer is equal to that of the original container")
987 4 : {
988 2 : REQUIRE_EQ(clipped.getSize(), size);
989 2 : }
990 :
991 4 : THEN("the values correspond to the original DataContainers")
992 4 : {
993 16 : for (int i = 0; i < size; ++i) {
994 14 : INFO("Error at position: ", i);
995 14 : REQUIRE_EQ(clipped[i], expectedDataVec2[i]);
996 14 : }
997 2 : }
998 4 : }
999 :
1000 16 : WHEN("creating a data container out of a vector within or higher than the bounds")
1001 16 : {
1002 4 : DataContainer dc(desc, dataVec3);
1003 4 : auto clipped = clip(dc, min, max);
1004 :
1005 4 : THEN("the size of the clipped DataContainer is equal to that of the original container")
1006 4 : {
1007 2 : REQUIRE_EQ(clipped.getSize(), size);
1008 2 : }
1009 :
1010 4 : THEN("the values correspond to the original DataContainers")
1011 4 : {
1012 16 : for (int i = 0; i < size; ++i) {
1013 14 : INFO("Error at position: ", i);
1014 14 : REQUIRE_EQ(clipped[i], expectedDataVec3[i]);
1015 14 : }
1016 2 : }
1017 4 : }
1018 :
1019 16 : WHEN("creating a data container out of a vector outside the bounds")
1020 16 : {
1021 4 : DataContainer dc(desc, dataVec4);
1022 4 : auto clipped = clip(dc, min, max);
1023 :
1024 4 : THEN("the size of the clipped DataContainer is equal to that of the original container")
1025 4 : {
1026 2 : REQUIRE_EQ(clipped.getSize(), size);
1027 2 : }
1028 :
1029 4 : THEN("the values correspond to the original DataContainers")
1030 4 : {
1031 16 : for (int i = 0; i < size; ++i) {
1032 14 : INFO("Error at position: ", i);
1033 14 : REQUIRE_EQ(clipped[i], expectedDataVec4[i]);
1034 14 : }
1035 2 : }
1036 4 : }
1037 16 : }
1038 :
1039 20 : GIVEN("a 2D data container")
1040 20 : {
1041 4 : IndexVector_t numCoeff(2);
1042 4 : numCoeff << 3, 2;
1043 4 : VolumeDescriptor desc(numCoeff);
1044 :
1045 4 : data_t min = 0;
1046 4 : data_t max = 8;
1047 :
1048 4 : Vector_t<data_t> dataVec(desc.getNumberOfCoefficients());
1049 4 : dataVec << -19, -23, 7, 8, 20, 1;
1050 4 : Vector_t<data_t> expectedDataVec(desc.getNumberOfCoefficients());
1051 4 : expectedDataVec << min, min, 7, 8, max, 1;
1052 :
1053 4 : WHEN("creating a data container out of a vector within and outside of both bounds")
1054 4 : {
1055 4 : DataContainer dc(desc, dataVec);
1056 4 : auto clipped = clip(dc, min, max);
1057 :
1058 4 : THEN("the size of the clipped DataContainer is equal to that of the original container")
1059 4 : {
1060 2 : REQUIRE_EQ(clipped.getSize(), desc.getNumberOfCoefficients());
1061 2 : }
1062 :
1063 4 : THEN("the values correspond to the original DataContainers")
1064 4 : {
1065 14 : for (int i = 0; i < desc.getNumberOfCoefficients(); ++i) {
1066 12 : INFO("Error at position: ", i);
1067 12 : REQUIRE_EQ(clipped[i], expectedDataVec[i]);
1068 12 : }
1069 2 : }
1070 4 : }
1071 4 : }
1072 20 : }
1073 :
1074 : TEST_CASE_TEMPLATE("DataContainer: Concatenate two DataContainers", data_t, float, double,
1075 : complex<float>, complex<double>)
1076 28 : {
1077 28 : GIVEN("Two equally sized 1D data containers")
1078 28 : {
1079 8 : constexpr index_t size = 20;
1080 8 : IndexVector_t numCoeff(1);
1081 8 : numCoeff << size;
1082 8 : VolumeDescriptor desc(numCoeff);
1083 :
1084 8 : Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size);
1085 8 : Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size);
1086 :
1087 8 : DataContainer dc1(desc, randVec1);
1088 8 : DataContainer dc2(desc, randVec2);
1089 :
1090 8 : auto concated = concatenate(dc1, dc2);
1091 8 : THEN("The size of the concatenated DataContainer is twice the original one")
1092 8 : {
1093 4 : REQUIRE_EQ(concated.getSize(), 2 * size);
1094 4 : }
1095 :
1096 8 : THEN("The values correspond to the original DataContainers")
1097 8 : {
1098 84 : for (int i = 0; i < size; ++i) {
1099 80 : INFO("Error at position: ", i);
1100 80 : REQUIRE_EQ(concated[i], randVec1[i]);
1101 80 : }
1102 :
1103 84 : for (int i = 0; i < size; ++i) {
1104 80 : INFO("Error at position: ", i + size);
1105 80 : REQUIRE_EQ(concated[i + size], randVec2[i]);
1106 80 : }
1107 4 : }
1108 8 : }
1109 :
1110 28 : GIVEN("Two differently sized 1D data containers")
1111 28 : {
1112 8 : IndexVector_t numCoeff(1);
1113 :
1114 8 : constexpr index_t size1 = 20;
1115 8 : numCoeff[0] = size1;
1116 8 : VolumeDescriptor desc1(numCoeff);
1117 :
1118 8 : constexpr index_t size2 = 10;
1119 8 : numCoeff[0] = size2;
1120 8 : VolumeDescriptor desc2(numCoeff);
1121 :
1122 8 : Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size1);
1123 8 : Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size2);
1124 :
1125 8 : DataContainer dc1(desc1, randVec1);
1126 8 : DataContainer dc2(desc2, randVec2);
1127 :
1128 8 : auto concated = concatenate(dc1, dc2);
1129 :
1130 8 : THEN("The size of the concatenated DataContainer is twice the original one")
1131 8 : {
1132 4 : REQUIRE_EQ(concated.getSize(), size1 + size2);
1133 4 : }
1134 :
1135 8 : THEN("The values correspond to the original DataContainers")
1136 8 : {
1137 84 : for (int i = 0; i < size1; ++i) {
1138 80 : INFO("Error at position: ", i);
1139 80 : REQUIRE_EQ(concated[i], randVec1[i]);
1140 80 : }
1141 :
1142 44 : for (int i = 0; i < size2; ++i) {
1143 40 : INFO("Error at position: ", i + size1);
1144 40 : REQUIRE_EQ(concated[i + size1], randVec2[i]);
1145 40 : }
1146 4 : }
1147 8 : }
1148 :
1149 28 : GIVEN("Two equally sized 2D data containers")
1150 28 : {
1151 8 : constexpr index_t size = 20;
1152 8 : IndexVector_t numCoeff(2);
1153 8 : numCoeff << size, size;
1154 8 : VolumeDescriptor desc(numCoeff);
1155 :
1156 8 : Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size * size);
1157 8 : Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size * size);
1158 :
1159 8 : DataContainer dc1(desc, randVec1);
1160 8 : DataContainer dc2(desc, randVec2);
1161 :
1162 8 : auto concated = concatenate(dc1, dc2);
1163 8 : THEN("The size of the concatenated DataContainer is twice the original one")
1164 8 : {
1165 4 : REQUIRE_EQ(concated.getSize(), 2 * (size * size));
1166 4 : }
1167 :
1168 8 : THEN("The values correspond to the original DataContainers")
1169 8 : {
1170 1604 : for (int i = 0; i < size * size; ++i) {
1171 1600 : INFO("Error at position: ", i);
1172 1600 : REQUIRE_EQ(concated[i], randVec1[i]);
1173 1600 : }
1174 :
1175 1604 : for (int i = 0; i < size * size; ++i) {
1176 1600 : INFO("Error at position: ", i + size);
1177 1600 : REQUIRE_EQ(concated[i + size * size], randVec2[i]);
1178 1600 : }
1179 4 : }
1180 8 : }
1181 :
1182 28 : GIVEN("DataContainers of different dimension")
1183 28 : {
1184 4 : IndexVector_t numCoeff1D(1);
1185 4 : numCoeff1D << 20;
1186 4 : VolumeDescriptor desc1D(numCoeff1D);
1187 :
1188 4 : IndexVector_t numCoeff2D(2);
1189 4 : numCoeff2D << 20, 20;
1190 4 : VolumeDescriptor desc2D(numCoeff2D);
1191 :
1192 4 : DataContainer dc1(desc1D);
1193 4 : DataContainer dc2(desc2D);
1194 :
1195 4 : THEN("The concatenation throws") { REQUIRE_THROWS_AS(concatenate(dc1, dc2), LogicError); }
1196 4 : }
1197 28 : }
1198 :
1199 : TEST_CASE_TEMPLATE("DataContainer: Slice a DataContainer", data_t, float, double, complex<float>,
1200 : complex<double>)
1201 72 : {
1202 : // Set seed for Eigen Matrices!
1203 72 : srand((unsigned int) 666);
1204 :
1205 72 : GIVEN("A non 3D DataContainer")
1206 72 : {
1207 16 : constexpr index_t size = 20;
1208 16 : IndexVector_t numCoeff2D(2);
1209 16 : numCoeff2D << size, size;
1210 :
1211 16 : const VolumeDescriptor desc(numCoeff2D);
1212 16 : const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size);
1213 16 : const DataContainer<data_t> dc(desc, randVec);
1214 :
1215 16 : THEN("Accessing an out of bounds slice throws")
1216 16 : {
1217 4 : REQUIRE_THROWS_AS(dc.slice(20), LogicError);
1218 4 : }
1219 :
1220 16 : WHEN("Accessing all the slices")
1221 16 : {
1222 252 : for (int i = 0; i < size; ++i) {
1223 240 : auto slice = dc.slice(i);
1224 :
1225 240 : THEN("The the slice is a 2D slice of \"thickness\" 1")
1226 240 : {
1227 4 : REQUIRE_EQ(slice.getDataDescriptor().getNumberOfDimensions(), 2);
1228 :
1229 4 : auto coeffs = slice.getDataDescriptor().getNumberOfCoefficientsPerDimension();
1230 4 : auto expectedCoeffs = IndexVector_t(2);
1231 4 : expectedCoeffs << size, 1;
1232 4 : REQUIRE_EQ(coeffs, expectedCoeffs);
1233 4 : }
1234 :
1235 240 : THEN("All values are the same as of the original DataContainer")
1236 240 : {
1237 : // Check that it's read correctly
1238 4 : auto vecSlice = randVec.segment(i * size, size);
1239 84 : for (int j = 0; j < size; ++j) {
1240 80 : REQUIRE_UNARY(checkApproxEq(slice(j, 0), vecSlice[j]));
1241 80 : }
1242 4 : }
1243 240 : }
1244 12 : }
1245 16 : }
1246 :
1247 72 : GIVEN("A const 3D DataContainer")
1248 72 : {
1249 16 : constexpr index_t size = 20;
1250 :
1251 16 : const VolumeDescriptor desc({size, size, size});
1252 16 : const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * size);
1253 16 : const DataContainer<data_t> dc(desc, randVec);
1254 :
1255 16 : THEN("Accessing an out of bounds slice throws")
1256 16 : {
1257 4 : REQUIRE_THROWS_AS(dc.slice(20), LogicError);
1258 4 : }
1259 :
1260 16 : WHEN("Accessing all the slices")
1261 16 : {
1262 252 : for (int i = 0; i < size; ++i) {
1263 240 : auto slice = dc.slice(i);
1264 :
1265 240 : THEN("The the slice is a 3D slice of \"thickness\" 1")
1266 240 : {
1267 4 : REQUIRE_EQ(slice.getDataDescriptor().getNumberOfDimensions(), 3);
1268 :
1269 4 : auto coeffs = slice.getDataDescriptor().getNumberOfCoefficientsPerDimension();
1270 4 : auto expectedCoeffs = IndexVector_t(3);
1271 4 : expectedCoeffs << size, size, 1;
1272 4 : REQUIRE_EQ(coeffs, expectedCoeffs);
1273 4 : }
1274 :
1275 240 : THEN("All values are the same as of the original DataContainer")
1276 240 : {
1277 : // Check that it's read correctly
1278 4 : auto vecSlice = randVec.segment(i * size * size, size * size);
1279 84 : for (int j = 0; j < size; ++j) {
1280 1680 : for (int k = 0; k < size; ++k) {
1281 1600 : REQUIRE_UNARY(checkApproxEq(slice(k, j, 0), vecSlice[k + j * size]));
1282 1600 : }
1283 80 : }
1284 4 : }
1285 240 : }
1286 12 : }
1287 16 : }
1288 :
1289 72 : GIVEN("A non-const 3D DataContainer")
1290 72 : {
1291 32 : constexpr index_t size = 20;
1292 32 : IndexVector_t numCoeff(3);
1293 32 : numCoeff << size, size, size;
1294 :
1295 32 : const VolumeDescriptor desc(numCoeff);
1296 32 : DataContainer<data_t> dc(desc);
1297 32 : dc = 0;
1298 :
1299 32 : THEN("Accessing an out of bounds slice throws")
1300 32 : {
1301 4 : REQUIRE_THROWS_AS(dc.slice(20), LogicError);
1302 4 : }
1303 :
1304 32 : WHEN("Setting the first slice to 1")
1305 32 : {
1306 8 : dc.slice(0) = 1;
1307 :
1308 8 : THEN("Only the first slice is set to 1")
1309 8 : {
1310 84 : for (int j = 0; j < size; ++j) {
1311 1680 : for (int i = 0; i < size; ++i) {
1312 1600 : data_t val = dc(i, j, 0);
1313 1600 : INFO("Expected slice 0 to be ", data_t{1}, " but it's ", val, " (at (", i,
1314 1600 : ", ", j, ", 0))");
1315 1600 : REQUIRE_UNARY(checkApproxEq(val, 1));
1316 1600 : }
1317 80 : }
1318 4 : }
1319 :
1320 8 : THEN("The other slices are still set to 0")
1321 8 : {
1322 80 : for (int k = 1; k < size; ++k) {
1323 1596 : for (int j = 0; j < size; ++j) {
1324 31920 : for (int i = 0; i < size; ++i) {
1325 30400 : data_t val = dc(i, j, k);
1326 30400 : INFO("Expected all slices but the first to be ", data_t{0},
1327 30400 : " but it's ", val, " (at (", i, ", ", j, ", 0))");
1328 30400 : REQUIRE_UNARY(checkApproxEq(val, 0));
1329 30400 : }
1330 1520 : }
1331 76 : }
1332 4 : }
1333 8 : }
1334 :
1335 32 : WHEN("Setting the fifth slice to some random data using a 3D DataContainer")
1336 32 : {
1337 12 : Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * 1);
1338 12 : const DataContainer slice(VolumeDescriptor({size, size, 1}), randVec);
1339 :
1340 12 : dc.slice(5) = slice;
1341 12 : THEN("The first 4 slices are still zero")
1342 12 : {
1343 24 : for (int k = 0; k < 5; ++k) {
1344 420 : for (int j = 0; j < size; ++j) {
1345 8400 : for (int i = 0; i < size; ++i) {
1346 8000 : data_t val = dc(i, j, k);
1347 :
1348 8000 : INFO("Expected all slices but the first to be ", data_t{0},
1349 8000 : " but it's ", val, " (at (", i, ", ", j, ", 0))");
1350 8000 : REQUIRE_UNARY(checkApproxEq(val, 0));
1351 8000 : }
1352 400 : }
1353 20 : }
1354 4 : }
1355 :
1356 12 : THEN("The fifth slices set correctly")
1357 12 : {
1358 84 : for (int j = 0; j < size; ++j) {
1359 1680 : for (int i = 0; i < size; ++i) {
1360 1600 : data_t val = dc(i, j, 5);
1361 1600 : auto expected = randVec[i + j * size];
1362 1600 : INFO("Expected slice 0 to be ", expected, " but it's ", val, " (at (", i,
1363 1600 : ", ", j, ", 0))");
1364 1600 : REQUIRE_UNARY(checkApproxEq(val, expected));
1365 1600 : }
1366 80 : }
1367 4 : }
1368 :
1369 12 : THEN("The last 14 slices are still zero")
1370 12 : {
1371 : // Check last slices
1372 60 : for (int k = 6; k < size; ++k) {
1373 1176 : for (int j = 0; j < size; ++j) {
1374 23520 : for (int i = 0; i < size; ++i) {
1375 22400 : data_t val = dc(i, j, k);
1376 :
1377 22400 : INFO("Expected all slices but the first to be ", data_t{0},
1378 22400 : " but it's ", val, " (at (", i, ", ", j, ", 0))");
1379 22400 : REQUIRE_UNARY(checkApproxEq(val, 0));
1380 22400 : }
1381 1120 : }
1382 56 : }
1383 4 : }
1384 12 : }
1385 :
1386 32 : WHEN("Setting the first slice to some random data using a 2D DataContainer")
1387 32 : {
1388 8 : Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size);
1389 8 : const DataContainer slice(VolumeDescriptor({size, size}), randVec);
1390 :
1391 8 : dc.slice(0) = slice;
1392 8 : THEN("The fifth slices set correctly")
1393 8 : {
1394 84 : for (int j = 0; j < size; ++j) {
1395 1680 : for (int i = 0; i < size; ++i) {
1396 1600 : data_t val = dc(i, j, 0);
1397 1600 : auto expected = randVec[i + j * size];
1398 1600 : INFO("Expected slice 0 to be ", expected, " but it's ", val, " (at (", i,
1399 1600 : ", ", j, ", 0))");
1400 1600 : REQUIRE_UNARY(checkApproxEq(val, expected));
1401 1600 : }
1402 80 : }
1403 4 : }
1404 8 : THEN("The other slices are still zero")
1405 8 : {
1406 80 : for (int k = 1; k < size; ++k) {
1407 1596 : for (int j = 0; j < size; ++j) {
1408 31920 : for (int i = 0; i < size; ++i) {
1409 30400 : data_t val = dc(i, j, k);
1410 30400 : INFO("Expected all slices but the first to be ", data_t{0},
1411 30400 : " but it's ", val, " (at (", i, ", ", j, ", 0))");
1412 30400 : REQUIRE_UNARY(checkApproxEq(val, 0));
1413 30400 : }
1414 1520 : }
1415 76 : }
1416 4 : }
1417 8 : }
1418 32 : }
1419 :
1420 72 : GIVEN("a 3D DataDescriptor and a 3D random Vector")
1421 72 : {
1422 8 : constexpr index_t size = 28;
1423 8 : constexpr index_t one = 1;
1424 8 : IndexVector_t numCoeff3D(3);
1425 8 : numCoeff3D << size, size, one;
1426 :
1427 8 : const VolumeDescriptor desc(numCoeff3D);
1428 8 : const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * one);
1429 :
1430 8 : WHEN("slicing a non-const DataContainer with the size of the last dimension of 1")
1431 8 : {
1432 4 : DataContainer<data_t> dc(desc, randVec);
1433 :
1434 4 : DataContainer<data_t> res = dc.slice(0);
1435 :
1436 4 : THEN("the DataContainers match") { REQUIRE_EQ(dc, res); }
1437 4 : }
1438 :
1439 8 : WHEN("slicing a const DataContainer with the size of the last dimension of 1")
1440 8 : {
1441 4 : const DataContainer<data_t> dc(desc, randVec);
1442 :
1443 4 : const DataContainer<data_t> res = dc.slice(0);
1444 :
1445 4 : THEN("the DataContainers match") { REQUIRE_EQ(dc, res); }
1446 4 : }
1447 8 : }
1448 72 : }
1449 :
1450 : TEST_CASE_TEMPLATE("DataContainer: FFT shift and IFFT shift a DataContainer", data_t, float, double,
1451 : complex<float>, complex<double>)
1452 48 : {
1453 48 : GIVEN("a one-element 2D data container")
1454 48 : {
1455 16 : DataContainer<data_t> dc(VolumeDescriptor{{1, 1}});
1456 16 : dc[0] = 8;
1457 16 : WHEN("running the FFT shift operation to the container")
1458 16 : {
1459 8 : DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
1460 8 : THEN("the data descriptors match")
1461 8 : {
1462 4 : REQUIRE_EQ(dc.getDataDescriptor(), fftShiftedDC.getDataDescriptor());
1463 4 : }
1464 8 : THEN("the data containers match") { REQUIRE_UNARY(fftShiftedDC == dc); }
1465 8 : }
1466 :
1467 16 : WHEN("running the IFFT shift operation to the container")
1468 16 : {
1469 8 : DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
1470 8 : THEN("the data descriptors match")
1471 8 : {
1472 4 : REQUIRE_EQ(dc.getDataDescriptor(), ifftShiftedDC.getDataDescriptor());
1473 4 : }
1474 8 : THEN("the data containers match") { REQUIRE_UNARY(ifftShiftedDC == dc); }
1475 8 : }
1476 16 : }
1477 :
1478 48 : GIVEN("a 3x3 2D data container")
1479 48 : {
1480 16 : DataContainer<data_t> dc(VolumeDescriptor{{3, 3}});
1481 16 : dc(0, 0) = 0;
1482 16 : dc(0, 1) = 1;
1483 16 : dc(0, 2) = 2;
1484 16 : dc(1, 0) = 3;
1485 16 : dc(1, 1) = 4;
1486 16 : dc(1, 2) = -4;
1487 16 : dc(2, 0) = -3;
1488 16 : dc(2, 1) = -2;
1489 16 : dc(2, 2) = -1;
1490 :
1491 16 : DataContainer<data_t> expectedFFTShiftDC(VolumeDescriptor{{3, 3}});
1492 16 : expectedFFTShiftDC(0, 0) = -1;
1493 16 : expectedFFTShiftDC(0, 1) = -3;
1494 16 : expectedFFTShiftDC(0, 2) = -2;
1495 16 : expectedFFTShiftDC(1, 0) = 2;
1496 16 : expectedFFTShiftDC(1, 1) = 0;
1497 16 : expectedFFTShiftDC(1, 2) = 1;
1498 16 : expectedFFTShiftDC(2, 0) = -4;
1499 16 : expectedFFTShiftDC(2, 1) = 3;
1500 16 : expectedFFTShiftDC(2, 2) = 4;
1501 :
1502 16 : WHEN("running the FFT shift operation to the container")
1503 16 : {
1504 8 : DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
1505 8 : THEN("the data descriptors match")
1506 8 : {
1507 4 : REQUIRE_EQ(fftShiftedDC.getDataDescriptor(),
1508 4 : expectedFFTShiftDC.getDataDescriptor());
1509 4 : }
1510 8 : THEN("the data containers match") { REQUIRE_UNARY(fftShiftedDC == expectedFFTShiftDC); }
1511 8 : }
1512 :
1513 16 : DataContainer<data_t> expectedIFFTShiftDC(VolumeDescriptor{{3, 3}});
1514 16 : expectedIFFTShiftDC(0, 0) = 4;
1515 16 : expectedIFFTShiftDC(0, 1) = -4;
1516 16 : expectedIFFTShiftDC(0, 2) = 3;
1517 16 : expectedIFFTShiftDC(1, 0) = -2;
1518 16 : expectedIFFTShiftDC(1, 1) = -1;
1519 16 : expectedIFFTShiftDC(1, 2) = -3;
1520 16 : expectedIFFTShiftDC(2, 0) = 1;
1521 16 : expectedIFFTShiftDC(2, 1) = 2;
1522 16 : expectedIFFTShiftDC(2, 2) = 0;
1523 :
1524 16 : WHEN("running the IFFT shift operation to the container")
1525 16 : {
1526 8 : DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
1527 8 : THEN("the data descriptors match")
1528 8 : {
1529 4 : REQUIRE_EQ(ifftShiftedDC.getDataDescriptor(),
1530 4 : expectedIFFTShiftDC.getDataDescriptor());
1531 4 : }
1532 8 : THEN("the data containers match")
1533 8 : {
1534 4 : REQUIRE_UNARY(ifftShiftedDC == expectedIFFTShiftDC);
1535 4 : }
1536 8 : }
1537 16 : }
1538 :
1539 48 : GIVEN("a 5x5 2D data container")
1540 48 : {
1541 16 : DataContainer<data_t> dc(VolumeDescriptor{{5, 5}});
1542 16 : dc(0, 0) = 28;
1543 16 : dc(0, 1) = 1;
1544 16 : dc(0, 2) = 5;
1545 16 : dc(0, 3) = -18;
1546 16 : dc(0, 4) = 8;
1547 16 : dc(1, 0) = 5;
1548 16 : dc(1, 1) = 6;
1549 16 : dc(1, 2) = 50;
1550 16 : dc(1, 3) = -8;
1551 16 : dc(1, 4) = 9;
1552 16 : dc(2, 0) = 8;
1553 16 : dc(2, 1) = 9;
1554 16 : dc(2, 2) = 10;
1555 16 : dc(2, 3) = 11;
1556 16 : dc(2, 4) = 12;
1557 16 : dc(3, 0) = -12;
1558 16 : dc(3, 1) = -41;
1559 16 : dc(3, 2) = -10;
1560 16 : dc(3, 3) = -9;
1561 16 : dc(3, 4) = -8;
1562 16 : dc(4, 0) = -70;
1563 16 : dc(4, 1) = -6;
1564 16 : dc(4, 2) = 22;
1565 16 : dc(4, 3) = -10;
1566 16 : dc(4, 4) = -3;
1567 :
1568 16 : DataContainer<data_t> expectedFFTShiftDC(VolumeDescriptor{{5, 5}});
1569 16 : expectedFFTShiftDC(0, 0) = -9;
1570 16 : expectedFFTShiftDC(0, 1) = -8;
1571 16 : expectedFFTShiftDC(0, 2) = -12;
1572 16 : expectedFFTShiftDC(0, 3) = -41;
1573 16 : expectedFFTShiftDC(0, 4) = -10;
1574 16 : expectedFFTShiftDC(1, 0) = -10;
1575 16 : expectedFFTShiftDC(1, 1) = -3;
1576 16 : expectedFFTShiftDC(1, 2) = -70;
1577 16 : expectedFFTShiftDC(1, 3) = -6;
1578 16 : expectedFFTShiftDC(1, 4) = 22;
1579 16 : expectedFFTShiftDC(2, 0) = -18;
1580 16 : expectedFFTShiftDC(2, 1) = 8;
1581 16 : expectedFFTShiftDC(2, 2) = 28;
1582 16 : expectedFFTShiftDC(2, 3) = 1;
1583 16 : expectedFFTShiftDC(2, 4) = 5;
1584 16 : expectedFFTShiftDC(3, 0) = -8;
1585 16 : expectedFFTShiftDC(3, 1) = 9;
1586 16 : expectedFFTShiftDC(3, 2) = 5;
1587 16 : expectedFFTShiftDC(3, 3) = 6;
1588 16 : expectedFFTShiftDC(3, 4) = 50;
1589 16 : expectedFFTShiftDC(4, 0) = 11;
1590 16 : expectedFFTShiftDC(4, 1) = 12;
1591 16 : expectedFFTShiftDC(4, 2) = 8;
1592 16 : expectedFFTShiftDC(4, 3) = 9;
1593 16 : expectedFFTShiftDC(4, 4) = 10;
1594 :
1595 16 : WHEN("running the FFT shift operation to the container")
1596 16 : {
1597 8 : DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
1598 8 : THEN("the data descriptors match")
1599 8 : {
1600 4 : REQUIRE_EQ(fftShiftedDC.getDataDescriptor(),
1601 4 : expectedFFTShiftDC.getDataDescriptor());
1602 4 : }
1603 8 : THEN("the data containers match") { REQUIRE_UNARY(fftShiftedDC == expectedFFTShiftDC); }
1604 8 : }
1605 :
1606 16 : DataContainer<data_t> expectedIFFTShiftDC(VolumeDescriptor{{5, 5}});
1607 16 : expectedIFFTShiftDC(0, 0) = 10;
1608 16 : expectedIFFTShiftDC(0, 1) = 11;
1609 16 : expectedIFFTShiftDC(0, 2) = 12;
1610 16 : expectedIFFTShiftDC(0, 3) = 8;
1611 16 : expectedIFFTShiftDC(0, 4) = 9;
1612 16 : expectedIFFTShiftDC(1, 0) = -10;
1613 16 : expectedIFFTShiftDC(1, 1) = -9;
1614 16 : expectedIFFTShiftDC(1, 2) = -8;
1615 16 : expectedIFFTShiftDC(1, 3) = -12;
1616 16 : expectedIFFTShiftDC(1, 4) = -41;
1617 16 : expectedIFFTShiftDC(2, 0) = 22;
1618 16 : expectedIFFTShiftDC(2, 1) = -10;
1619 16 : expectedIFFTShiftDC(2, 2) = -3;
1620 16 : expectedIFFTShiftDC(2, 3) = -70;
1621 16 : expectedIFFTShiftDC(2, 4) = -6;
1622 16 : expectedIFFTShiftDC(3, 0) = 5;
1623 16 : expectedIFFTShiftDC(3, 1) = -18;
1624 16 : expectedIFFTShiftDC(3, 2) = 8;
1625 16 : expectedIFFTShiftDC(3, 3) = 28;
1626 16 : expectedIFFTShiftDC(3, 4) = 1;
1627 16 : expectedIFFTShiftDC(4, 0) = 50;
1628 16 : expectedIFFTShiftDC(4, 1) = -8;
1629 16 : expectedIFFTShiftDC(4, 2) = 9;
1630 16 : expectedIFFTShiftDC(4, 3) = 5;
1631 16 : expectedIFFTShiftDC(4, 4) = 6;
1632 :
1633 16 : WHEN("running the IFFT shift operation to the container")
1634 16 : {
1635 8 : DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
1636 8 : THEN("the data descriptors match")
1637 8 : {
1638 4 : REQUIRE_EQ(ifftShiftedDC.getDataDescriptor(),
1639 4 : expectedIFFTShiftDC.getDataDescriptor());
1640 4 : }
1641 8 : THEN("the data containers match")
1642 8 : {
1643 4 : REQUIRE_UNARY(ifftShiftedDC == expectedIFFTShiftDC);
1644 4 : }
1645 8 : }
1646 16 : }
1647 48 : }
1648 :
1649 : // "instantiate" the test templates for CPU types
1650 : TEST_CASE_TEMPLATE_APPLY(datacontainer_construction, CPUTypeTuple);
1651 : TEST_CASE_TEMPLATE_APPLY(datacontainer_reduction, CPUTypeTuple);
1652 : TEST_CASE_TEMPLATE_APPLY(datacontainer_elemwise, CPUTypeTuple);
1653 : TEST_CASE_TEMPLATE_APPLY(datacontainer_arithmetic, CPUTypeTuple);
1654 : TEST_CASE_TEMPLATE_APPLY(datacontainer_maps, CPUTypeTuple);
1655 :
1656 : #ifdef ELSA_CUDA_VECTOR
1657 : // "instantiate" the test templates for GPU types
1658 : TEST_CASE_TEMPLATE_APPLY(datacontainer_construction, GPUTypeTuple);
1659 : TEST_CASE_TEMPLATE_APPLY(datacontainer_reduction, GPUTypeTuple);
1660 : TEST_CASE_TEMPLATE_APPLY(datacontainer_elemwise, GPUTypeTuple);
1661 : TEST_CASE_TEMPLATE_APPLY(datacontainer_arithmetic, GPUTypeTuple);
1662 : TEST_CASE_TEMPLATE_APPLY(datacontainer_maps, GPUTypeTuple);
1663 : #endif
1664 :
1665 : TEST_SUITE_END();
|