21.10.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

test_DataContainer.cpp 27 KB
Newer Older
Tobias Lasser's avatar
Tobias Lasser committed
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * \file test_DataContainer.cpp
 *
 * \brief Tests for DataContainer class
 *
 * \author Matthias Wieczorek - initial code
 * \author David Frank - rewrite to use Catch and BDD
 * \author Tobias Lasser - rewrite and added code coverage
 */

#include <catch2/catch.hpp>
#include "DataContainer.h"
13
#include "IdenticalBlocksDescriptor.h"
14
#include "testHelpers.h"
Jens Petit's avatar
Jens Petit committed
15

16
17
#include <type_traits>

Tobias Lasser's avatar
Tobias Lasser committed
18
19
20
using namespace elsa;
using namespace Catch::literals; // to enable 0.0_a approximate floats

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Provides object to be used with TEMPLATE_PRODUCT_TEST_CASE, necessary because enum cannot be
// passed directly
template <typename T>
struct TestHelperGPU {
    static const DataHandlerType handler_t = DataHandlerType::GPU;
    using data_t = T;
};

// Provides object to be used with TEMPLATE_PRODUCT_TEST_CASE, necessary because enum cannot be
// passed directly
template <typename T>
struct TestHelperCPU {
    static const DataHandlerType handler_t = DataHandlerType::CPU;
    using data_t = T;
};

#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Constructing DataContainers", "",
                           (TestHelperCPU, TestHelperGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Constructing DataContainers", "", (TestHelperCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
45
{
46
47
    using data_t = typename TestType::data_t;

48
49
    INFO("Testing type: " << TypeName_v<const data_t>);

Jens Petit's avatar
Jens Petit committed
50
51
    GIVEN("a DataDescriptor")
    {
Tobias Lasser's avatar
Tobias Lasser committed
52
53
54
55
        IndexVector_t numCoeff(3);
        numCoeff << 17, 47, 91;
        DataDescriptor desc(numCoeff);

Jens Petit's avatar
Jens Petit committed
56
57
        WHEN("constructing an empty DataContainer")
        {
58
            DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
59

Jens Petit's avatar
Jens Petit committed
60
            THEN("it has the correct DataDescriptor") { REQUIRE(dc.getDataDescriptor() == desc); }
Tobias Lasser's avatar
Tobias Lasser committed
61

62
            THEN("it has a data vector of correct size")
Jens Petit's avatar
Jens Petit committed
63
            {
Tobias Lasser's avatar
Tobias Lasser committed
64
65
66
67
                REQUIRE(dc.getSize() == desc.getNumberOfCoefficients());
            }
        }

Jens Petit's avatar
Jens Petit committed
68
69
        WHEN("constructing an initialized DataContainer")
        {
70
            auto data = generateRandomMatrix<data_t>(desc.getNumberOfCoefficients());
Tobias Lasser's avatar
Tobias Lasser committed
71

72
            DataContainer<data_t> dc(desc, data, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
73

Jens Petit's avatar
Jens Petit committed
74
            THEN("it has the correct DataDescriptor") { REQUIRE(dc.getDataDescriptor() == desc); }
Tobias Lasser's avatar
Tobias Lasser committed
75

Jens Petit's avatar
Jens Petit committed
76
77
            THEN("it has correctly initialized data")
            {
Tobias Lasser's avatar
Tobias Lasser committed
78
79
80
81
82
83
84
85
                REQUIRE(dc.getSize() == desc.getNumberOfCoefficients());

                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == data[i]);
            }
        }
    }

Jens Petit's avatar
Jens Petit committed
86
87
    GIVEN("another DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
88
89
90
91
        IndexVector_t numCoeff(2);
        numCoeff << 32, 57;
        DataDescriptor desc(numCoeff);

92
        DataContainer<data_t> otherDc(desc, TestType::handler_t);
93
94

        auto randVec = generateRandomMatrix<data_t>(otherDc.getSize());
Tobias Lasser's avatar
Tobias Lasser committed
95
96
97
        for (index_t i = 0; i < otherDc.getSize(); ++i)
            otherDc[i] = randVec(i);

Jens Petit's avatar
Jens Petit committed
98
99
        WHEN("copy constructing")
        {
Tobias Lasser's avatar
Tobias Lasser committed
100
101
            DataContainer dc(otherDc);

Jens Petit's avatar
Jens Petit committed
102
103
            THEN("it copied correctly")
            {
Tobias Lasser's avatar
Tobias Lasser committed
104
105
106
107
108
109
110
                REQUIRE(dc.getDataDescriptor() == otherDc.getDataDescriptor());
                REQUIRE(&dc.getDataDescriptor() != &otherDc.getDataDescriptor());

                REQUIRE(dc == otherDc);
            }
        }

Jens Petit's avatar
Jens Petit committed
111
112
        WHEN("copy assigning")
        {
113
            DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
114
115
            dc = otherDc;

Jens Petit's avatar
Jens Petit committed
116
117
            THEN("it copied correctly")
            {
Tobias Lasser's avatar
Tobias Lasser committed
118
119
120
121
122
123
124
                REQUIRE(dc.getDataDescriptor() == otherDc.getDataDescriptor());
                REQUIRE(&dc.getDataDescriptor() != &otherDc.getDataDescriptor());

                REQUIRE(dc == otherDc);
            }
        }

Jens Petit's avatar
Jens Petit committed
125
126
        WHEN("move constructing")
        {
Tobias Lasser's avatar
Tobias Lasser committed
127
128
129
130
            DataContainer oldOtherDc(otherDc);

            DataContainer dc(std::move(otherDc));

Jens Petit's avatar
Jens Petit committed
131
132
            THEN("it moved correctly")
            {
Tobias Lasser's avatar
Tobias Lasser committed
133
134
135
136
137
                REQUIRE(dc.getDataDescriptor() == oldOtherDc.getDataDescriptor());

                REQUIRE(dc == oldOtherDc);
            }

Jens Petit's avatar
Jens Petit committed
138
            THEN("the moved from object is still valid (but empty)") { otherDc = dc; }
Tobias Lasser's avatar
Tobias Lasser committed
139
140
        }

Jens Petit's avatar
Jens Petit committed
141
142
        WHEN("move assigning")
        {
Tobias Lasser's avatar
Tobias Lasser committed
143
144
            DataContainer oldOtherDc(otherDc);

145
            DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
146
147
            dc = std::move(otherDc);

Jens Petit's avatar
Jens Petit committed
148
149
            THEN("it moved correctly")
            {
Tobias Lasser's avatar
Tobias Lasser committed
150
151
152
153
154
                REQUIRE(dc.getDataDescriptor() == oldOtherDc.getDataDescriptor());

                REQUIRE(dc == oldOtherDc);
            }

Jens Petit's avatar
Jens Petit committed
155
            THEN("the moved from object is still valid (but empty)") { otherDc = dc; }
Tobias Lasser's avatar
Tobias Lasser committed
156
157
158
159
        }
    }
}

160
161
162
163
164
165
166
167
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Element-wise access of DataContainers", "",
                           (TestHelperCPU, TestHelperGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Element-wise access of DataContainers", "", (TestHelperCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
168
{
169
170
    using data_t = typename TestType::data_t;

171
172
    INFO("Testing type: " << TypeName_v<const data_t>);

Jens Petit's avatar
Jens Petit committed
173
174
    GIVEN("a DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
175
176
177
        IndexVector_t numCoeff(2);
        numCoeff << 47, 11;
        DataDescriptor desc(numCoeff);
178
        DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
179

Jens Petit's avatar
Jens Petit committed
180
181
        WHEN("accessing the elements")
        {
Tobias Lasser's avatar
Tobias Lasser committed
182
183
184
185
            IndexVector_t coord(2);
            coord << 17, 4;
            index_t index = desc.getIndexFromCoordinate(coord);

Jens Petit's avatar
Jens Petit committed
186
187
            THEN("it works as expected when using indices/coordinates")
            {
188
189
190
191
192
193
194
195
196
                dc[index] = data_t(2.2f);
                REQUIRE(dc[index] == data_t(2.2f));
                REQUIRE(dc(coord) == data_t(2.2f));
                REQUIRE(dc(17, 4) == data_t(2.2f));

                dc(coord) = data_t(3.3f);
                REQUIRE(dc[index] == data_t(3.3f));
                REQUIRE(dc(coord) == data_t(3.3f));
                REQUIRE(dc(17, 4) == data_t(3.3f));
Tobias Lasser's avatar
Tobias Lasser committed
197
198
199
200
201
            }
        }
    }
}

202
203
204
205
206
207
208
209
210
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the reduction operations of DataContainer", "",
                           (TestHelperCPU, TestHelperGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the reduction operations of DataContainer", "",
                           (TestHelperCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
211
{
212
213
    using data_t = typename TestType::data_t;

214
215
    INFO("Testing type: " << TypeName_v<const data_t>);

Jens Petit's avatar
Jens Petit committed
216
217
    GIVEN("a DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
218
219
220
221
        IndexVector_t numCoeff(3);
        numCoeff << 11, 73, 45;
        DataDescriptor desc(numCoeff);

Jens Petit's avatar
Jens Petit committed
222
223
        WHEN("putting in some random data")
        {
224
            auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
225

Jens Petit's avatar
Jens Petit committed
226
227
            THEN("the reductions work as expected")
            {
228
229
230
231
232
                REQUIRE(checkSameNumbers(dc.sum(), randVec.sum()));
                REQUIRE(checkSameNumbers(dc.l1Norm(), randVec.array().abs().sum()));
                REQUIRE(checkSameNumbers(dc.lInfNorm(), randVec.array().abs().maxCoeff()));
                REQUIRE(checkSameNumbers(dc.squaredL2Norm(), randVec.squaredNorm()));

233
                auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
234

235
                REQUIRE(checkSameNumbers(dc.dot(dc2), randVec.dot(randVec2)));
Tobias Lasser's avatar
Tobias Lasser committed
236
237
238
239
240
            }
        }
    }
}

241
242
243
244
245
246
247
248
249
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the element-wise operations of DataContainer", "",
                           (TestHelperCPU, TestHelperGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the element-wise operations of DataContainer", "",
                           (TestHelperCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
250
{
251
252
    using data_t = typename TestType::data_t;

253
254
    INFO("Testing type: " << TypeName_v<const data_t>);

Jens Petit's avatar
Jens Petit committed
255
256
    GIVEN("a DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
257
258
259
260
        IndexVector_t numCoeff(2);
        numCoeff << 47, 11;
        DataDescriptor desc(numCoeff);

Jens Petit's avatar
Jens Petit committed
261
262
        WHEN("putting in some random data")
        {
263
            auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
264

Jens Petit's avatar
Jens Petit committed
265
266
            THEN("the element-wise unary operations work as expected")
            {
Jens Petit's avatar
Jens Petit committed
267
                DataContainer dcSquare = square(dc);
Tobias Lasser's avatar
Tobias Lasser committed
268
                for (index_t i = 0; i < dc.getSize(); ++i)
269
                    REQUIRE(checkSameNumbers(dcSquare[i], randVec.array().square()[i]));
270
                DataContainer dcSqrt = sqrt(dcSquare);
Tobias Lasser's avatar
Tobias Lasser committed
271
                for (index_t i = 0; i < dc.getSize(); ++i)
272
273
274
275
276
277
278
279
280
                    REQUIRE(checkSameNumbers(dcSqrt[i], randVec.array().square().sqrt()[i]));

                // do exponent check only for floating point types as for integer will likely lead
                // to overflow due to random init over full value range
                if constexpr (!std::is_integral_v<data_t>) {
                    DataContainer dcExp = exp(dc);
                    for (index_t i = 0; i < dc.getSize(); ++i)
                        REQUIRE(checkSameNumbers(dcExp[i], randVec.array().exp()[i]));
                }
Tobias Lasser's avatar
Tobias Lasser committed
281

282
                DataContainer dcLog = log(dcSquare);
Tobias Lasser's avatar
Tobias Lasser committed
283
                for (index_t i = 0; i < dc.getSize(); ++i)
284
                    REQUIRE(checkSameNumbers(dcLog[i], randVec.array().square().log()[i]));
Tobias Lasser's avatar
Tobias Lasser committed
285
286
            }

287
288
            auto scalar = static_cast<data_t>(923.41f);

Jens Petit's avatar
Jens Petit committed
289
290
            THEN("the binary in-place addition of a scalar work as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
291
292
293
294
295
                dc += scalar;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == randVec(i) + scalar);
            }

Jens Petit's avatar
Jens Petit committed
296
297
            THEN("the binary in-place subtraction of a scalar work as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
298
299
300
301
302
                dc -= scalar;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == randVec(i) - scalar);
            }

Jens Petit's avatar
Jens Petit committed
303
304
            THEN("the binary in-place multiplication with a scalar work as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
305
306
307
308
309
                dc *= scalar;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == randVec(i) * scalar);
            }

Jens Petit's avatar
Jens Petit committed
310
311
            THEN("the binary in-place division by a scalar work as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
312
313
                dc /= scalar;
                for (index_t i = 0; i < dc.getSize(); ++i)
314
                    REQUIRE(checkSameNumbers(dc[i], randVec(i) / scalar));
Tobias Lasser's avatar
Tobias Lasser committed
315
316
            }

Jens Petit's avatar
Jens Petit committed
317
318
            THEN("the element-wise assignment of a scalar works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
319
320
321
322
323
324
                dc = scalar;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == scalar);
            }
        }

Jens Petit's avatar
Jens Petit committed
325
326
        WHEN("having two containers with random data")
        {
327
328
            auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
            auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
329

Jens Petit's avatar
Jens Petit committed
330
331
            THEN("the element-wise in-place addition works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
332
333
334
335
336
                dc += dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == randVec(i) + randVec2(i));
            }

Jens Petit's avatar
Jens Petit committed
337
338
            THEN("the element-wise in-place subtraction works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
339
340
341
342
343
                dc -= dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
                    REQUIRE(dc[i] == randVec(i) - randVec2(i));
            }

Jens Petit's avatar
Jens Petit committed
344
345
            THEN("the element-wise in-place multiplication works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
346
347
                dc *= dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
348
                    REQUIRE(checkSameNumbers(dc[i], randVec(i) * randVec2(i)));
Tobias Lasser's avatar
Tobias Lasser committed
349
350
            }

Jens Petit's avatar
Jens Petit committed
351
352
            THEN("the element-wise in-place division works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
353
354
                dc /= dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
355
                    if (dc2[i] != data_t(0))
356
                        REQUIRE(checkSameNumbers(dc[i], randVec(i) / randVec2(i)));
Tobias Lasser's avatar
Tobias Lasser committed
357
358
359
360
361
            }
        }
    }
}

362
363
364
365
366
367
368
369
370
371
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE(
    "Scenario: Testing the arithmetic operations with DataContainer arguments", "",
    (TestHelperCPU, TestHelperGPU),
    (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE(
    "Scenario: Testing the arithmetic operations with DataContainer arguments", "", (TestHelperCPU),
    (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
372
{
373
374
    using data_t = typename TestType::data_t;

375
376
    INFO("Testing type: " << TypeName_v<const data_t>);

Jens Petit's avatar
Jens Petit committed
377
378
    GIVEN("some DataContainers")
    {
Tobias Lasser's avatar
Tobias Lasser committed
379
380
381
382
        IndexVector_t numCoeff(3);
        numCoeff << 52, 7, 29;
        DataDescriptor desc(numCoeff);

383
384
        auto [dc, randVec] = generateRandomContainer<data_t>(desc, TestType::handler_t);
        auto [dc2, randVec2] = generateRandomContainer<data_t>(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
385

Jens Petit's avatar
Jens Petit committed
386
387
        THEN("the binary element-wise operations work as expected")
        {
388
            DataContainer resultPlus = dc + dc2;
Tobias Lasser's avatar
Tobias Lasser committed
389
            for (index_t i = 0; i < dc.getSize(); ++i)
390
                REQUIRE(resultPlus[i] == dc[i] + dc2[i]);
Tobias Lasser's avatar
Tobias Lasser committed
391

392
            DataContainer resultMinus = dc - dc2;
Tobias Lasser's avatar
Tobias Lasser committed
393
            for (index_t i = 0; i < dc.getSize(); ++i)
394
                REQUIRE(resultMinus[i] == dc[i] - dc2[i]);
Tobias Lasser's avatar
Tobias Lasser committed
395

396
            DataContainer resultMult = dc * dc2;
Tobias Lasser's avatar
Tobias Lasser committed
397
            for (index_t i = 0; i < dc.getSize(); ++i)
398
                REQUIRE(checkSameNumbers(resultMult[i], dc[i] * dc2[i]));
Tobias Lasser's avatar
Tobias Lasser committed
399

400
            DataContainer resultDiv = dc / dc2;
Tobias Lasser's avatar
Tobias Lasser committed
401
            for (index_t i = 0; i < dc.getSize(); ++i)
402
                if (dc2[i] != data_t(0))
403
                    REQUIRE(checkSameNumbers(resultDiv[i], dc[i] / dc2[i]));
Tobias Lasser's avatar
Tobias Lasser committed
404
405
        }

Jens Petit's avatar
Jens Petit committed
406
407
        THEN("the operations with a scalar work as expected")
        {
408
            data_t scalar = static_cast<data_t>(4.92f);
Tobias Lasser's avatar
Tobias Lasser committed
409

410
            DataContainer resultScalarPlus = scalar + dc;
Tobias Lasser's avatar
Tobias Lasser committed
411
            for (index_t i = 0; i < dc.getSize(); ++i)
412
                REQUIRE(resultScalarPlus[i] == scalar + dc[i]);
Tobias Lasser's avatar
Tobias Lasser committed
413

414
            DataContainer resultPlusScalar = dc + scalar;
Tobias Lasser's avatar
Tobias Lasser committed
415
            for (index_t i = 0; i < dc.getSize(); ++i)
416
                REQUIRE(resultPlusScalar[i] == dc[i] + scalar);
Tobias Lasser's avatar
Tobias Lasser committed
417

418
            DataContainer resultScalarMinus = scalar - dc;
Tobias Lasser's avatar
Tobias Lasser committed
419
            for (index_t i = 0; i < dc.getSize(); ++i)
420
                REQUIRE(resultScalarMinus[i] == scalar - dc[i]);
Tobias Lasser's avatar
Tobias Lasser committed
421

422
            DataContainer resultMinusScalar = dc - scalar;
Tobias Lasser's avatar
Tobias Lasser committed
423
            for (index_t i = 0; i < dc.getSize(); ++i)
424
                REQUIRE(resultMinusScalar[i] == dc[i] - scalar);
Tobias Lasser's avatar
Tobias Lasser committed
425

426
            DataContainer resultScalarMult = scalar * dc;
Tobias Lasser's avatar
Tobias Lasser committed
427
            for (index_t i = 0; i < dc.getSize(); ++i)
428
                REQUIRE(resultScalarMult[i] == scalar * dc[i]);
Tobias Lasser's avatar
Tobias Lasser committed
429

430
            DataContainer resultMultScalar = dc * scalar;
Tobias Lasser's avatar
Tobias Lasser committed
431
            for (index_t i = 0; i < dc.getSize(); ++i)
432
                REQUIRE(resultMultScalar[i] == dc[i] * scalar);
Tobias Lasser's avatar
Tobias Lasser committed
433

434
            DataContainer resultScalarDiv = scalar / dc;
Tobias Lasser's avatar
Tobias Lasser committed
435
            for (index_t i = 0; i < dc.getSize(); ++i)
436
437
                if (dc[i] != data_t(0))
                    REQUIRE(checkSameNumbers(resultScalarDiv[i], scalar / dc[i]));
Tobias Lasser's avatar
Tobias Lasser committed
438

439
            DataContainer resultDivScalar = dc / scalar;
Tobias Lasser's avatar
Tobias Lasser committed
440
            for (index_t i = 0; i < dc.getSize(); ++i)
441
                REQUIRE(checkSameNumbers(resultDivScalar[i], dc[i] / scalar));
Jens Petit's avatar
Jens Petit committed
442
443
444
445
        }
    }
}

446
447
448
449
450
451
452
453
454
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing creation of Maps through DataContainer", "",
                           (TestHelperCPU, TestHelperGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing creation of Maps through DataContainer", "",
                           (TestHelperCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
Jens Petit's avatar
Jens Petit committed
455
{
456
457
    using data_t = typename TestType::data_t;

458
459
    INFO("Testing type: " << TypeName_v<const data_t>);

460
    GIVEN("a non-blocked container")
Jens Petit's avatar
Jens Petit committed
461
    {
Jens Petit's avatar
Jens Petit committed
462
463
464
465
        IndexVector_t numCoeff(3);
        numCoeff << 52, 7, 29;
        DataDescriptor desc(numCoeff);

466
467
        DataContainer<data_t> dc(desc, TestType::handler_t);
        const DataContainer<data_t> constDc(desc, TestType::handler_t);
Jens Petit's avatar
Jens Petit committed
468

469
        WHEN("trying to reference a block")
Jens Petit's avatar
Jens Petit committed
470
        {
471
            THEN("an exception occurs")
Jens Petit's avatar
Jens Petit committed
472
            {
473
474
                REQUIRE_THROWS(dc.getBlock(0));
                REQUIRE_THROWS(constDc.getBlock(0));
Jens Petit's avatar
Jens Petit committed
475
476
477
            }
        }

478
        WHEN("creating a view")
Jens Petit's avatar
Jens Petit committed
479
        {
480
481
482
483
484
            IndexVector_t numCoeff(1);
            numCoeff << desc.getNumberOfCoefficients();
            DataDescriptor linearDesc(numCoeff);
            auto linearDc = dc.viewAs(linearDesc);
            auto linearConstDc = constDc.viewAs(linearDesc);
Jens Petit's avatar
Jens Petit committed
485

486
            THEN("view has the correct descriptor and data")
Jens Petit's avatar
Jens Petit committed
487
            {
488
489
                REQUIRE(linearDesc == linearDc.getDataDescriptor());
                REQUIRE(&linearDc[0] == &dc[0]);
Jens Petit's avatar
Jens Petit committed
490

491
492
                REQUIRE(linearDesc == linearConstDc.getDataDescriptor());
                REQUIRE(&linearConstDc[0] == &constDc[0]);
Jens Petit's avatar
Jens Petit committed
493

494
495
496
497
                AND_THEN("view is not a shallow copy")
                {
                    const auto dcCopy = dc;
                    const auto constDcCopy = constDc;
Jens Petit's avatar
Jens Petit committed
498

499
500
501
                    linearDc[0] = 1;
                    REQUIRE(&linearDc[0] == &dc[0]);
                    REQUIRE(&linearDc[0] != &dcCopy[0]);
Jens Petit's avatar
Jens Petit committed
502

503
504
505
506
                    linearConstDc[0] = 1;
                    REQUIRE(&linearConstDc[0] == &constDc[0]);
                    REQUIRE(&linearConstDc[0] != &constDcCopy[0]);
                }
Jens Petit's avatar
Jens Petit committed
507
            }
508
509
        }
    }
Jens Petit's avatar
Jens Petit committed
510

511
512
513
514
515
516
    GIVEN("a blocked container")
    {
        IndexVector_t numCoeff(2);
        numCoeff << 52, 29;
        DataDescriptor desc(numCoeff);
        index_t numBlocks = 7;
517
        IdenticalBlocksDescriptor blockDesc(numBlocks, desc);
Jens Petit's avatar
Jens Petit committed
518

519
520
        DataContainer<data_t> dc(blockDesc, TestType::handler_t);
        const DataContainer<data_t> constDc(blockDesc, TestType::handler_t);
Jens Petit's avatar
Jens Petit committed
521

522
523
524
        WHEN("referencing a block")
        {
            THEN("block has the correct descriptor and data")
Jens Petit's avatar
Jens Petit committed
525
            {
526
527
528
                for (index_t i = 0; i < numBlocks; i++) {
                    auto dcBlock = dc.getBlock(i);
                    const auto constDcBlock = constDc.getBlock(i);
Jens Petit's avatar
Jens Petit committed
529

530
531
532
533
534
535
                    REQUIRE(dcBlock.getDataDescriptor() == blockDesc.getDescriptorOfBlock(i));
                    REQUIRE(&dcBlock[0] == &dc[0] + blockDesc.getOffsetOfBlock(i));

                    REQUIRE(constDcBlock.getDataDescriptor() == blockDesc.getDescriptorOfBlock(i));
                    REQUIRE(&constDcBlock[0] == &constDc[0] + blockDesc.getOffsetOfBlock(i));
                }
Jens Petit's avatar
Jens Petit committed
536
537
538
            }
        }

Jens Petit's avatar
Jens Petit committed
539
        WHEN("creating a view")
Jens Petit's avatar
Jens Petit committed
540
        {
541
542
543
544
545
546
547
548
549
550
551
552
553
            IndexVector_t numCoeff(1);
            numCoeff << blockDesc.getNumberOfCoefficients();
            DataDescriptor linearDesc(numCoeff);
            auto linearDc = dc.viewAs(linearDesc);
            auto linearConstDc = constDc.viewAs(linearDesc);

            THEN("view has the correct descriptor and data")
            {
                REQUIRE(linearDesc == linearDc.getDataDescriptor());
                REQUIRE(&linearDc[0] == &dc[0]);

                REQUIRE(linearDesc == linearConstDc.getDataDescriptor());
                REQUIRE(&linearConstDc[0] == &constDc[0]);
Jens Petit's avatar
Jens Petit committed
554

555
556
557
558
559
560
561
562
563
564
565
566
567
568
                AND_THEN("view is not a shallow copy")
                {
                    const auto dcCopy = dc;
                    const auto constDcCopy = constDc;

                    linearDc[0] = 1;
                    REQUIRE(&linearDc[0] == &dc[0]);
                    REQUIRE(&linearDc[0] != &dcCopy[0]);

                    linearConstDc[0] = 1;
                    REQUIRE(&linearConstDc[0] == &constDc[0]);
                    REQUIRE(&linearConstDc[0] != &constDcCopy[0]);
                }
            }
Tobias Lasser's avatar
Tobias Lasser committed
569
570
        }
    }
571
572
}

573
574
575
576
577
578
579
580
581
582
583
584
585
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_TEST_CASE("Scenario: Testing loading data to GPU and vice versa.", "", float, double,
                   std::complex<float>, std::complex<double>, index_t)
{
    GIVEN("A CPU DataContainer with random data")
    {
        IndexVector_t numCoeff(3);
        numCoeff << 52, 7, 29;
        DataDescriptor desc(numCoeff);

        DataContainer<TestType> dcCPU(desc, DataHandlerType::CPU);
        DataContainer<TestType> dcGPU(desc, DataHandlerType::GPU);

586
        auto randVec = generateRandomMatrix<TestType>(dcCPU.getSize());
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657

        for (index_t i = 0; i < dcCPU.getSize(); ++i) {
            dcCPU[i] = randVec(i);
            dcGPU[i] = randVec(i);
        }

        WHEN("Trying to call loadToCPU on CPU container")
        {
            THEN("Throws") { REQUIRE_THROWS(dcCPU.loadToCPU()); }
        }

        WHEN("Trying to call loadToGPU on GPU container")
        {
            THEN("Throws") { REQUIRE_THROWS(dcGPU.loadToGPU()); }
        }

        WHEN("Loading to GPU from CPU")
        {
            DataContainer dcGPU2 = dcCPU.loadToGPU();

            REQUIRE(dcGPU2.getDataHandlerType() == DataHandlerType::GPU);

            THEN("all elements have to be the same")
            {
                for (index_t i = 0; i < dcCPU.getSize(); ++i) {
                    REQUIRE(dcGPU2[i] == dcGPU[i]);
                }
            }
        }

        WHEN("Loading to CPU from GPU")
        {
            DataContainer dcCPU2 = dcGPU.loadToCPU();

            REQUIRE(dcCPU2.getDataHandlerType() == DataHandlerType::CPU);

            THEN("all elements have to be the same")
            {
                for (index_t i = 0; i < dcCPU.getSize(); ++i) {
                    REQUIRE(dcCPU2[i] == dcGPU[i]);
                }
            }
        }

        WHEN("copy-assigning a GPU to a CPU container")
        {
            dcCPU = dcGPU;

            THEN("it should be a GPU container")
            {
                REQUIRE(dcCPU.getDataHandlerType() == DataHandlerType::GPU);
            }

            AND_THEN("they should be equal") { REQUIRE(dcCPU == dcGPU); }
        }

        WHEN("copy-assigning a CPU to a GPU container")
        {
            dcGPU = dcCPU;

            THEN("it should be a GPU container")
            {
                REQUIRE(dcGPU.getDataHandlerType() == DataHandlerType::CPU);
            }

            AND_THEN("they should be equal") { REQUIRE(dcCPU == dcGPU); }
        }
    }
}
#endif

Jens Petit's avatar
Jens Petit committed
658
659
660
661
SCENARIO("Testing iterators for DataContainer")
{
    GIVEN("A 1D container")
    {
662
663
664
665
666
667
668
669
        constexpr index_t size = 20;
        IndexVector_t numCoeff(1);
        numCoeff << size;
        DataDescriptor desc(numCoeff);

        DataContainer dc1(desc);
        DataContainer dc2(desc);

Jens Petit's avatar
Jens Petit committed
670
        Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size);
671
672
673
674
675
676
677
        Eigen::VectorXf randVec2 = Eigen::VectorXf::Random(size);

        for (index_t i = 0; i < size; ++i) {
            dc1[i] = randVec1(i);
            dc2[i] = randVec2(i);
        }

Jens Petit's avatar
Jens Petit committed
678
679
        THEN("We can iterate forward")
        {
680
681
682
683
684
685
686
            int i = 0;
            for (auto v = dc1.cbegin(); v != dc1.cend(); v++) {
                REQUIRE(*v == randVec1[i++]);
            }
            REQUIRE(i == size);
        }

Jens Petit's avatar
Jens Petit committed
687
688
        THEN("We can iterate backward")
        {
689
690
691
692
693
694
695
            int i = size;
            for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
                REQUIRE(*v == randVec1[--i]);
            }
            REQUIRE(i == 0);
        }

Jens Petit's avatar
Jens Petit committed
696
697
        THEN("We can iterate and mutate")
        {
698
699
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
700
                v = v * 2;
701
702
703
704
705
706
707
708
709
710
711
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size);

            i = 0;
            for (auto v : dc1) {
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size);
        }

Jens Petit's avatar
Jens Petit committed
712
713
        THEN("We can use STL algorithms")
        {
714
715
716
717
            REQUIRE(*std::min_element(dc1.cbegin(), dc1.cend()) == randVec1.minCoeff());
            REQUIRE(*std::max_element(dc1.cbegin(), dc1.cend()) == randVec1.maxCoeff());
        }
    }
Jens Petit's avatar
Jens Petit committed
718
719
    GIVEN("A 2D container")
    {
720
721
722
723
724
725
726
727
728
729
730
731
732
        constexpr index_t size = 20;
        IndexVector_t numCoeff(2);
        numCoeff << size, size;
        DataDescriptor desc(numCoeff);

        DataContainer dc1(desc);

        Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size);

        for (index_t i = 0; i < dc1.getSize(); ++i) {
            dc1[i] = randVec1[i];
        }

Jens Petit's avatar
Jens Petit committed
733
734
        THEN("We can iterate forward")
        {
735
            int i = 0;
Jens Petit's avatar
Jens Petit committed
736
            for (auto v : dc1) {
737
738
739
740
741
                REQUIRE(v == randVec1[i++]);
            }
            REQUIRE(i == size * size);
        }

Jens Petit's avatar
Jens Petit committed
742
743
        THEN("We can iterate backward")
        {
744
745
746
747
748
749
750
            int i = size * size;
            for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
                REQUIRE(*v == randVec1[--i]);
            }
            REQUIRE(i == 0);
        }

Jens Petit's avatar
Jens Petit committed
751
752
        THEN("We can iterate and mutate")
        {
753
754
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
755
                v = v * 2;
756
757
758
759
760
761
762
763
764
765
766
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size * size);

            i = 0;
            for (auto v : dc1) {
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size * size);
        }

Jens Petit's avatar
Jens Petit committed
767
768
        THEN("We can use STL algorithms")
        {
769
770
771
772
            REQUIRE(*std::min_element(dc1.cbegin(), dc1.cend()) == randVec1.minCoeff());
            REQUIRE(*std::max_element(dc1.cbegin(), dc1.cend()) == randVec1.maxCoeff());
        }
    }
Jens Petit's avatar
Jens Petit committed
773
774
    GIVEN("A 3D container")
    {
775
776
777
778
779
780
781
        constexpr index_t size = 20;
        IndexVector_t numCoeff(3);
        numCoeff << size, size, size;
        DataDescriptor desc(numCoeff);

        DataContainer dc1(desc);

Jens Petit's avatar
Jens Petit committed
782
        Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size * size);
783
784
785
786
787

        for (index_t i = 0; i < dc1.getSize(); ++i) {
            dc1[i] = randVec1[i];
        }

Jens Petit's avatar
Jens Petit committed
788
789
        THEN("We can iterate forward")
        {
790
791
792
793
794
795
796
            int i = 0;
            for (auto v : dc1) {
                REQUIRE(v == randVec1[i++]);
            }
            REQUIRE(i == size * size * size);
        }

Jens Petit's avatar
Jens Petit committed
797
798
        THEN("We can iterate backward")
        {
799
800
801
802
803
804
805
            int i = size * size * size;
            for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
                REQUIRE(*v == randVec1[--i]);
            }
            REQUIRE(i == 0);
        }

Jens Petit's avatar
Jens Petit committed
806
807
        THEN("We can iterate and mutate")
        {
808
809
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
810
                v = v * 2;
811
812
813
814
815
816
817
818
819
820
821
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size * size * size);

            i = 0;
            for (auto v : dc1) {
                REQUIRE(v == 2 * randVec1[i++]);
            }
            REQUIRE(i == size * size * size);
        }

Jens Petit's avatar
Jens Petit committed
822
823
        THEN("We can use STL algorithms")
        {
824
825
826
827
            REQUIRE(*std::min_element(dc1.cbegin(), dc1.cend()) == randVec1.minCoeff());
            REQUIRE(*std::max_element(dc1.cbegin(), dc1.cend()) == randVec1.maxCoeff());
        }
    }
828
}