test_DataHandlerMap.cpp 30.1 KB
Newer Older
1
/**
2
 * \file test_DataHandlerMap.cpp
3
 *
4
 * \brief Tests for DataHandlerMaps - DataHandlerMapCPU and DataHandlerMapGPU
5
6
7
 *
 * \author David Frank - initial code
 * \author Tobias Lasser - rewrite and code coverage
8
 * \author Jens Petit - refactoring into TEMPLATE_PRODUCT_TEST_CASE
9
10
11
12
13
 */

#include <catch2/catch.hpp>
#include "DataHandlerMapCPU.h"
#include "DataHandlerCPU.h"
14
#include "testHelpers.h"
15

16
17
18
19
20
21
22
23
#ifdef ELSA_CUDA_VECTOR
#include "DataHandlerGPU.h"
#include "DataHandlerMapGPU.h"
#endif

using namespace elsa;

// for testing the copy-on-write mechanism
24
template <typename data_t>
25
long elsa::useCount(const DataHandlerCPU<data_t>& dh)
26
27
28
29
{
    return dh._data.use_count();
}

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifdef ELSA_CUDA_VECTOR
// for testing the copy-on-write mechanism
template <typename data_t>
long elsa::useCount(const DataHandlerGPU<data_t>& dh)
{
    return dh._data.use_count();
}
#endif

// Helper to provide the correct map based on the handler type
template <typename Handler>
struct MapToHandler {
    using map =
        std::conditional_t<std::is_same_v<DataHandlerCPU<typename Handler::value_type>, Handler>,
                           DataHandlerMapCPU<typename Handler::value_type>,
#ifdef ELSA_CUDA_VECTOR
                           DataHandlerMapGPU<typename Handler::value_type>>;
#else
                           DataHandlerMapCPU<typename Handler::value_type>>;
#endif
};

#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Constructing DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Constructing DataHandlerMap", "", (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
60
{
61
62
    using data_t = typename TestType::value_type;

63
64
65
66
67
68
    GIVEN("a certain size")
    {
        index_t size = 314;

        WHEN("constructing with a given vector")
        {
69
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size * 2};
70
            randVec.setRandom();
71
            const TestType dh{randVec};
72
73
            const auto dhMap = dh.getBlock(size / 3, size / 3);

74
            THEN("the DataHandlerMap references the actual vector")
75
76
77
78
79
80
81
82
83
84
            {
                REQUIRE(dhMap->getSize() == size / 3);

                for (index_t i = 0; i < size / 3; ++i)
                    REQUIRE(&(*dhMap)[i] == &dh[i + size / 3]);
            }
        }

        WHEN("copy constructing")
        {
85
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size * 2};
86
            randVec.setRandom();
87
            const TestType dh{randVec};
88
            const auto dhMap = dh.getBlock(size / 3, size / 3);
89
90
91

            const auto& dhMapRef = static_cast<const typename MapToHandler<TestType>::map&>(*dhMap);

92
93
94
95
96
97
98
99
100
101
102
103
104
            const auto dhMapCopy = dhMapRef;

            THEN("the copy references the actual vector")
            {
                REQUIRE(dhMap->getSize() == size / 3);

                for (index_t i = 0; i < size / 3; ++i)
                    REQUIRE(&dhMapCopy[i] == &dh[i + size / 3]);
            }
        }
    }
}

105
106
107
108
109
110
111
112
113
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing equality operator on DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing equality operator on DataHandlerMap", "",
                           (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
114
{
115
116
117
    using data_t = typename TestType::value_type;

    GIVEN("some DataHandlerMap")
118
119
    {
        index_t size = 314;
120
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
121
        randVec.setRandom();
122
        const TestType realDh{randVec};
123
124
125
126
127
        const auto dhPtr = realDh.getBlock(0, size);
        const auto& dh = *dhPtr;

        WHEN("comparing to a handler with a different size")
        {
128
            const TestType dh2{size + 1};
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
            THEN("the result is false")
            {
                REQUIRE_FALSE(dh == dh2);
                REQUIRE_FALSE(dh == *dh2.getBlock(0, size + 1));
            }
        }

        WHEN("comparing to a shallow copy or view of the handler")
        {
            const auto dh2 = realDh;
            THEN("the result is true")
            {
                REQUIRE(dh == dh2);
                REQUIRE(dh == *realDh.getBlock(0, size));
            }
        }

        WHEN("comparing to a deep copy or a view of the deep copy")
        {
148
            const TestType dh2{randVec};
149
150
151
152
153
154
155
156
157
158
            THEN("the result is true")
            {
                REQUIRE(dh == dh2);
                REQUIRE(dh == *dh2.getBlock(0, size));
            }
        }

        WHEN("comparing to a handler or map with different data")
        {
            randVec[0] += 1;
159
            const TestType dh2{randVec};
160
161
162
163
164
165
166
167
168
            THEN("the result is false")
            {
                REQUIRE_FALSE(dh == dh2);
                REQUIRE_FALSE(dh == *dh2.getBlock(0, size));
            }
        }
    }
}

169
170
171
172
173
174
175
176
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Assigning to DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Assigning to DataHandlerMap", "", (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
177
{
178
179
180
    using data_t = typename TestType::value_type;

    GIVEN("a partial DataHandlerMap")
181
182
    {
        index_t size = 314;
183
        TestType dh{2 * size};
184
        dh = 0;
185
186
187
188
        const auto dhMap = dh.getBlock(0, size);

        WHEN("copy assigning")
        {
189
            auto& dhMapRef = static_cast<typename MapToHandler<TestType>::map&>(*dhMap);
190
191
192

            THEN("sizes must match")
            {
193
                const TestType dh2{3 * size};
194
                const auto dh2Map = dh2.getBlock(0, 3 * size);
195
196
                const auto& dh2MapRef =
                    static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
197
198
199
200
201
                REQUIRE_THROWS(dhMapRef = dh2MapRef);
            }

            THEN("a deep copy is performed")
            {
Jens Petit's avatar
Jens Petit committed
202
203
204
                Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
                randVec.setRandom();
                const TestType dh2{randVec};
205
                const auto dh2Map = dh2.getBlock(0, size);
206
207
                const auto& dh2MapRef =
                    static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
208
209
210
211
212
213
214
215
216
217

                dhMapRef = dh2MapRef;
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dh2) == 1);
                REQUIRE(&dh[0] == &dhMapRef[0]);
                REQUIRE(dhMapRef == dh2);
                REQUIRE(&dh[0] != &dh2MapRef[0]);
            }
        }

218
        WHEN("copy assigning a DataHandlerMap through base pointers")
219
        {
220
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
221
            randVec.setRandom();
222
223
            const std::unique_ptr<const DataHandler<data_t>> dh2Ptr =
                std::make_unique<const TestType>(randVec);
224
225
226

            THEN("sizes must match")
            {
227
228
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
                REQUIRE_THROWS(*dhMap = *bigDh);
            }

            const auto dhCopy = dh;
            *dhMap = *dh2Ptr;
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == (*dh2Ptr)[i]);

                REQUIRE(*dhMap == *dh2Ptr);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

247
        WHEN("copy assigning a partial DataHandlerMap through base pointers")
248
249
        {
            const auto dhCopy = dh;
250
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{2 * size};
251
            randVec.setRandom();
252
            const TestType dh2{randVec};
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
                const auto bigDh = dh2.getBlock(0, 2 * size);
                REQUIRE_THROWS(*dhMap = *bigDh);
            }

            *dhMap = *dh2Map;
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

275
        WHEN("copy assigning a full DataHandlerMap (aka a view) through base pointers")
276
277
        {
            const auto dhCopy = dh;
278
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
279
            randVec.setRandom();
280
            const TestType dh2{randVec};
281
282
283
284
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
285
286
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
                REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size));
            }

            *dhMap = *dh2Map;
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

303
        WHEN("\"move\" assigning a DataHandlerMap through base pointers")
304
        {
305
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
306
            randVec.setRandom();
307
            const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
308
309
310

            THEN("sizes must match")
            {
311
312
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
                REQUIRE_THROWS(*dhMap = std::move(*bigDh));
            }

            const auto dhCopy = dh;
            *dhMap = std::move(*dh2Ptr);
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == (*dh2Ptr)[i]);

                REQUIRE(*dhMap == *dh2Ptr);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

331
        WHEN("\"move\" assigning a partial DataHandlerMap through base pointers")
332
333
        {
            const auto dhCopy = dh;
334
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{2 * size};
335
            randVec.setRandom();
336
            TestType dh2{randVec};
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
                const auto bigDh = dh2.getBlock(0, 2 * size);
                REQUIRE_THROWS(*dhMap = std::move(*bigDh));
            }

            *dhMap = std::move(*dh2Map);
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

359
        WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through base pointers")
360
361
        {
            const auto dhCopy = dh;
362
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
363
            randVec.setRandom();
364
            TestType dh2{randVec};
365
366
367
368
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
369
370
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
                REQUIRE_THROWS(*dhMap = std::move(*bigDh->getBlock(0, 2 * size)));
            }

            *dhMap = std::move(*dh2Map);
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }
    }

388
    GIVEN("a full DataHandlerMap (aka a view)")
389
390
    {
        index_t size = 314;
391
        TestType dh{size};
392
393
394
395
        const auto dhMap = dh.getBlock(0, size);

        WHEN("copy assigning and both maps are views")
        {
396
            auto& dhMapRef = static_cast<typename MapToHandler<TestType>::map&>(*dhMap);
397
398
399

            THEN("sizes must match")
            {
400
                const TestType dh2{3 * size};
401
                const auto dh2Map = dh2.getBlock(0, 3 * size);
402
403
                const auto& dh2MapRef =
                    static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
404
405
406
407
408
                REQUIRE_THROWS(dhMapRef = dh2MapRef);
            }

            THEN("a shallow copy is performed")
            {
409
                const TestType dh2{size};
410
                const auto dh2Map = dh2.getBlock(0, size);
411
412
                const auto& dh2MapRef =
                    static_cast<const typename MapToHandler<TestType>::map&>(*dh2Map);
413
414
415
416
417
418
419
420
421
422
423
                dhMapRef = dh2MapRef;
                REQUIRE(useCount(dh) == 2);
                REQUIRE(dh == dh2);
                REQUIRE(dh == dhMapRef);
                REQUIRE(dh == dh2MapRef);
                dhMapRef[0] = 1;
                REQUIRE(&dhMapRef[0] == &dh[0]);
                REQUIRE(&dhMapRef[0] != &dh2MapRef[0]);
            }
        }

424
        WHEN("copy assigning a DataHandlerMap through base pointers")
425
        {
426
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
427
            randVec.setRandom();
428
            const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
429
430
431

            THEN("sizes must match")
            {
432
433
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
                REQUIRE_THROWS(*dhMap = *bigDh);
            }

            *dhMap = *dh2Ptr;
            THEN("a shallow copy is performed")
            {
                REQUIRE(useCount(dh) == 2);
                REQUIRE(dh == *dh2Ptr);
                REQUIRE(*dhMap == *dh2Ptr);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                dh[0] = 1;
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                REQUIRE(&dh[0] != &(*dh2Ptr)[0]);
            }
        }

450
        WHEN("copy assigning a partial DataHandlerMap through base pointers")
451
452
        {
            const auto dhCopy = dh;
453
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{2 * size};
454
            randVec.setRandom();
455
            const TestType dh2{randVec};
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
                const auto bigDh = dh2.getBlock(0, 2 * size);
                REQUIRE_THROWS(*dhMap = *bigDh);
            }

            *dhMap = *dh2Map;
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

478
        WHEN("copy assigning a full DataHandlerMap (aka a view) through base pointers")
479
        {
480
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
481
            randVec.setRandom();
482
            const TestType dh2{randVec};
483
484
485
486
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
487
488
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
                REQUIRE_THROWS(*dhMap = *bigDh->getBlock(0, 2 * size));
            }

            *dhMap = *dh2Map;
            THEN("a shallow copy is performed")
            {
                REQUIRE(useCount(dh) == 2);
                REQUIRE(dh == dh2);
                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                dh[0] = 1;
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                REQUIRE(&dh[0] != &dh2[0]);
            }
        }

505
        WHEN("\"move\" assigning a DataHandler through base pointers")
506
        {
507
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
508
            randVec.setRandom();
509
            const std::unique_ptr<DataHandler<data_t>> dh2Ptr = std::make_unique<TestType>(randVec);
510
511
512

            THEN("sizes must match")
            {
513
514
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
                REQUIRE_THROWS(*dhMap = std::move(*bigDh));
            }

            *dhMap = std::move(*dh2Ptr);
            THEN("a shallow copy is performed")
            {
                REQUIRE(useCount(dh) == 2);
                REQUIRE(dh == *dh2Ptr);
                REQUIRE(*dhMap == *dh2Ptr);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                dh[0] = 1;
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                REQUIRE(&dh[0] != &(*dh2Ptr)[0]);
            }
        }

531
        WHEN("\"move\" assigning a partial DataHandlerMap through base pointers")
532
533
        {
            const auto dhCopy = dh;
534
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{2 * size};
535
            randVec.setRandom();
536
            TestType dh2{randVec};
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
                const auto bigDh = dh2.getBlock(0, 2 * size);
                REQUIRE_THROWS(*dhMap = std::move(*bigDh));
            }

            *dhMap = std::move(*dh2Map);
            THEN("a deep copy is performed")
            {
                REQUIRE(useCount(dh) == 1);
                REQUIRE(useCount(dhCopy) == 1);

                for (index_t i = 0; i < size; i++)
                    REQUIRE(dh[i] == dh2[i]);

                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
            }
        }

559
        WHEN("\"move\" assigning a full DataHandlerMap (aka a view) through base pointers")
560
        {
561
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{size};
562
            randVec.setRandom();
563
            TestType dh2{randVec};
564
565
566
567
            const auto dh2Map = dh2.getBlock(0, size);

            THEN("sizes must match")
            {
568
569
                const std::unique_ptr<DataHandler<data_t>> bigDh =
                    std::make_unique<TestType>(2 * size);
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
                REQUIRE_THROWS(*dhMap = std::move(*bigDh->getBlock(0, 2 * size)));
            }

            *dhMap = std::move(*dh2Map);
            THEN("a shallow copy is performed")
            {
                REQUIRE(useCount(dh) == 2);
                REQUIRE(dh == dh2);
                REQUIRE(*dhMap == *dh2Map);
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                dh[0] = 1;
                REQUIRE(&(*dhMap)[0] == &dh[0]);
                REQUIRE(&dh[0] != &dh2[0]);
            }
        }
    }
}

588
589
590
591
592
593
594
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Cloning DataHandlerMap", "", (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Cloning DataHandlerMap", "", (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
595
{
596
597
598
    using data_t = typename TestType::value_type;

    GIVEN("a full DataHandlerMap (aka a view)")
599
600
    {
        index_t size = 728;
601
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> dataVec(size);
602
        dataVec.setRandom();
603
        TestType realDh(dataVec);
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
        auto dhPtr = realDh.getBlock(0, size);
        auto& dh = *dhPtr;

        WHEN("cloning")
        {
            auto dhClone = dh.clone();

            THEN("a shallow copy is produced")
            {
                REQUIRE(dhClone.get() != &dh);

                REQUIRE(dhClone->getSize() == dh.getSize());

                REQUIRE(useCount(realDh) == 2);

                REQUIRE(*dhClone == dh);

                dh[0] = 1;
                REQUIRE(*dhClone != dh);
            }
        }
    }

627
    GIVEN("a partial DataHandlerMap")
628
629
    {
        index_t size = 728;
630
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> dataVec(size);
631
        dataVec.setRandom();
632
        TestType realDh(dataVec);
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
        auto dhPtr = realDh.getBlock(0, size / 2);
        auto& dh = *dhPtr;

        WHEN("a deep copy is produced")
        {
            auto dhClone = dh.clone();

            THEN("everything matches")
            {
                REQUIRE(dhClone.get() != &dh);

                REQUIRE(dhClone->getSize() == dh.getSize());

                REQUIRE(useCount(realDh) == 1);

                REQUIRE(dh == *dhClone);
            }
        }
    }
}

654
655
656
657
658
659
660
661
662
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the reduction operations of DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the reduction operations of DataHandlerMap", "",
                           (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
663
{
664
665
666
    using data_t = typename TestType::value_type;

    GIVEN("some DataHandlerMap")
667
668
669
670
671
    {
        index_t size = 284;

        WHEN("putting in some random data")
        {
Jens Petit's avatar
Jens Petit committed
672
            auto randVec = generateRandomMatrix<data_t>(size * 2);
673
            TestType realDh(randVec);
674
675
676
677
678
            auto dhPtr = realDh.getBlock(size / 3, size);
            auto& dh = *dhPtr;

            THEN("the reductions work as expected")
            {
679
680
681
682
683
684
685
                REQUIRE(checkSameNumbers(dh.sum(), randVec.middleRows(size / 3, size).sum()));
                REQUIRE(checkSameNumbers(dh.l1Norm(),
                                         randVec.middleRows(size / 3, size).array().abs().sum()));
                REQUIRE(checkSameNumbers(
                    dh.lInfNorm(), randVec.middleRows(size / 3, size).array().abs().maxCoeff()));
                REQUIRE(checkSameNumbers(dh.squaredL2Norm(),
                                         randVec.middleRows(size / 3, size).squaredNorm()));
686

Jens Petit's avatar
Jens Petit committed
687
                auto randVec2 = generateRandomMatrix<data_t>(size);
688
                TestType realDh2(randVec2);
689
690
                auto dh2Ptr = realDh2.getBlock(0, size);
                auto& dh2 = *dh2Ptr;
691
692
                REQUIRE(checkSameNumbers(dh.dot(dh2),
                                         randVec.middleRows(size / 3, size).dot(randVec2)));
693

694
695
696
                TestType dhCPU(randVec2);
                REQUIRE(checkSameNumbers(dh.dot(dhCPU),
                                         randVec.middleRows(size / 3, size).dot(randVec2)));
697
698
699
700
701
            }

            THEN("the dot product expects correctly sized arguments")
            {
                index_t wrongSize = size - 1;
702
                Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec2(wrongSize);
703
                randVec2.setRandom();
704
                TestType dh2(randVec2);
705
706
707
708
709
710
711

                REQUIRE_THROWS_AS(dh.dot(dh2), std::invalid_argument);
            }
        }
    }
}

712
713
714
715
716
717
718
719
720
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the element-wise operations of DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Testing the element-wise operations of DataHandlerMap", "",
                           (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
721
{
722
723
724
    using data_t = typename TestType::value_type;

    GIVEN("some DataHandlerMap")
725
726
727
728
729
    {
        index_t size = 567;

        WHEN("putting in some random data")
        {
Jens Petit's avatar
Jens Petit committed
730
            auto randVec = generateRandomMatrix<data_t>(size);
731
            TestType realDh(randVec);
Jens Petit's avatar
Jens Petit committed
732

733
            auto dhPtr = realDh.getBlock(0, size);
734
            auto& dh = static_cast<typename MapToHandler<TestType>::map&>(*dhPtr);
735
736
737

            THEN("the element-wise binary vector operations work as expected")
            {
738
                TestType bigDh{2 * size};
739
740
741
742
743
744

                REQUIRE_THROWS(dh += bigDh);
                REQUIRE_THROWS(dh -= bigDh);
                REQUIRE_THROWS(dh *= bigDh);
                REQUIRE_THROWS(dh /= bigDh);

745
                TestType realOldDh(randVec);
746
                auto oldDhPtr = realOldDh.getBlock(0, size);
747
                auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
748

Jens Petit's avatar
Jens Petit committed
749
750
                auto randVec2 = generateRandomMatrix<data_t>(size);

751
                TestType dhCPU(randVec2);
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
                auto dh2Ptr = dhCPU.getBlock(0, size);
                auto& dh2 = *dh2Ptr;

                dh += dh2;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] + dh2[i]);

                dh = oldDh;
                dh += dhCPU;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] + dhCPU[i]);

                dh = oldDh;
                dh -= dh2;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] - dh2[i]);

                dh = oldDh;
                dh -= dhCPU;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] - dhCPU[i]);

                dh = oldDh;
                dh *= dh2;
                for (index_t i = 0; i < size; ++i)
777
                    REQUIRE(checkSameNumbers(dh[i], oldDh[i] * dh2[i]));
778
779
780
781

                dh = oldDh;
                dh *= dhCPU;
                for (index_t i = 0; i < size; ++i)
782
                    REQUIRE(checkSameNumbers(dh[i], oldDh[i] * dhCPU[i]));
783
784
785
786

                dh = oldDh;
                dh /= dh2;
                for (index_t i = 0; i < size; ++i)
787
788
789
                    if (dh2[i] != data_t(0))
                        // due to floating point arithmetic less precision
                        REQUIRE(checkSameNumbers(dh[i], oldDh[i] / dh2[i], 100));
790
791
792
793

                dh = oldDh;
                dh /= dhCPU;
                for (index_t i = 0; i < size; ++i)
794
795
796
                    if (dhCPU[i] != data_t(0))
                        // due to floating point arithmetic less precision
                        REQUIRE(checkSameNumbers(dh[i], oldDh[i] / dhCPU[i], 100));
797
798
799
800
            }

            THEN("the element-wise binary scalar operations work as expected")
            {
801
                TestType realOldDh(randVec);
802
                auto oldDhPtr = realOldDh.getBlock(0, size);
803
804
                auto& oldDh = static_cast<typename MapToHandler<TestType>::map&>(*oldDhPtr);
                data_t scalar = std::is_integral_v<data_t> ? 3 : data_t(3.5f);
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822

                dh += scalar;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] + scalar);

                dh = oldDh;
                dh -= scalar;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] - scalar);

                dh = oldDh;
                dh *= scalar;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == oldDh[i] * scalar);

                dh = oldDh;
                dh /= scalar;
                for (index_t i = 0; i < size; ++i)
823
                    REQUIRE(checkSameNumbers(dh[i], oldDh[i] / scalar));
824
825
826
827
            }

            THEN("the element-wise assignment of a scalar works as expected")
            {
828
                auto scalar = std::is_integral_v<data_t> ? data_t(47) : data_t(47.11f);
829
830
831
832
833
834
835
836
837

                dh = scalar;
                for (index_t i = 0; i < size; ++i)
                    REQUIRE(dh[i] == scalar);
            }
        }
    }
}

838
839
840
841
842
843
844
845
#ifdef ELSA_CUDA_VECTOR
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Referencing blocks of DataHandlerMap", "",
                           (DataHandlerCPU, DataHandlerGPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#else
TEMPLATE_PRODUCT_TEST_CASE("Scenario: Referencing blocks of DataHandlerMap", "", (DataHandlerCPU),
                           (float, double, std::complex<float>, std::complex<double>, index_t))
#endif
846
{
847
848
849
    using data_t = typename TestType::value_type;

    GIVEN("some DataHandlerMap")
850
851
    {
        index_t size = 728;
852
853
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> dataVec(size);
        TestType realDh(dataVec);
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
        auto dhPtr = realDh.getBlock(0, size);
        auto& dh = *dhPtr;

        WHEN("getting the reference to a block")
        {
            REQUIRE_THROWS(dh.getBlock(size, 1));
            REQUIRE_THROWS(dh.getBlock(0, size + 1));

            auto dhBlock = dh.getBlock(size / 3, size / 2);

            THEN("returned data handler references the correct elements")
            {
                REQUIRE(dhBlock->getSize() == size / 2);

                for (index_t i = 0; i < size / 2; i++)
                    REQUIRE(&(*dhBlock)[i] == &dh[i + size / 3]);
            }
        }
    }

874
    GIVEN("a const DataHandlerMap")
875
876
    {
        index_t size = 728;
877
878
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> dataVec(size);
        const TestType realDh(dataVec);
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
        auto dhPtr = realDh.getBlock(0, size);
        auto& dh = *dhPtr;

        WHEN("getting the reference to a block")
        {
            REQUIRE_THROWS(dh.getBlock(size, 1));
            REQUIRE_THROWS(dh.getBlock(0, size + 1));

            auto dhBlock = dh.getBlock(size / 3, size / 2);

            THEN("returned data handler references the correct elements")
            {
                REQUIRE(dhBlock->getSize() == size / 2);

                for (index_t i = 0; i < size / 2; i++)
                    REQUIRE(&(*dhBlock)[i] == &dh[i + size / 3]);
            }
        }
    }
898
}