test_DataContainer.cpp 25.4 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

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

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// 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
43
{
44 45
    using data_t = typename TestType::data_t;

Jens Petit's avatar
Jens Petit committed
46 47
    GIVEN("a DataDescriptor")
    {
Tobias Lasser's avatar
Tobias Lasser committed
48 49 50 51
        IndexVector_t numCoeff(3);
        numCoeff << 17, 47, 91;
        DataDescriptor desc(numCoeff);

Jens Petit's avatar
Jens Petit committed
52 53
        WHEN("constructing an empty DataContainer")
        {
54
            DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
55

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

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

Jens Petit's avatar
Jens Petit committed
64 65
        WHEN("constructing an initialized DataContainer")
        {
66
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> data{desc.getNumberOfCoefficients()};
Tobias Lasser's avatar
Tobias Lasser committed
67 68
            data.setRandom();

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

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

Jens Petit's avatar
Jens Petit committed
73 74
            THEN("it has correctly initialized data")
            {
Tobias Lasser's avatar
Tobias Lasser committed
75 76 77 78 79 80 81 82
                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
83 84
    GIVEN("another DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
85 86 87 88
        IndexVector_t numCoeff(2);
        numCoeff << 32, 57;
        DataDescriptor desc(numCoeff);

89 90 91
        DataContainer<data_t> otherDc(desc, TestType::handler_t);
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{otherDc.getSize()};
        randVec.setRandom();
Tobias Lasser's avatar
Tobias Lasser committed
92 93 94
        for (index_t i = 0; i < otherDc.getSize(); ++i)
            otherDc[i] = randVec(i);

Jens Petit's avatar
Jens Petit committed
95 96
        WHEN("copy constructing")
        {
Tobias Lasser's avatar
Tobias Lasser committed
97 98
            DataContainer dc(otherDc);

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

                REQUIRE(dc == otherDc);
            }
        }

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

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

                REQUIRE(dc == otherDc);
            }
        }

Jens Petit's avatar
Jens Petit committed
122 123
        WHEN("move constructing")
        {
Tobias Lasser's avatar
Tobias Lasser committed
124 125 126 127
            DataContainer oldOtherDc(otherDc);

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

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

                REQUIRE(dc == oldOtherDc);
            }

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

Jens Petit's avatar
Jens Petit committed
138 139
        WHEN("move assigning")
        {
Tobias Lasser's avatar
Tobias Lasser committed
140 141
            DataContainer oldOtherDc(otherDc);

142
            DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
143 144
            dc = std::move(otherDc);

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

                REQUIRE(dc == oldOtherDc);
            }

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

157 158 159 160 161 162 163 164
#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
165
{
166 167
    using data_t = typename TestType::data_t;

Jens Petit's avatar
Jens Petit committed
168 169
    GIVEN("a DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
170 171 172
        IndexVector_t numCoeff(2);
        numCoeff << 47, 11;
        DataDescriptor desc(numCoeff);
173
        DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
174

Jens Petit's avatar
Jens Petit committed
175 176
        WHEN("accessing the elements")
        {
Tobias Lasser's avatar
Tobias Lasser committed
177 178 179 180
            IndexVector_t coord(2);
            coord << 17, 4;
            index_t index = desc.getIndexFromCoordinate(coord);

Jens Petit's avatar
Jens Petit committed
181 182
            THEN("it works as expected when using indices/coordinates")
            {
183 184 185 186 187 188 189 190 191
                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
192 193 194 195 196
            }
        }
    }
}

197 198 199 200 201 202 203 204 205
#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
206
{
207 208
    using data_t = typename TestType::data_t;

Jens Petit's avatar
Jens Petit committed
209 210
    GIVEN("a DataContainer")
    {
Tobias Lasser's avatar
Tobias Lasser committed
211 212 213
        IndexVector_t numCoeff(3);
        numCoeff << 11, 73, 45;
        DataDescriptor desc(numCoeff);
214
        DataContainer<data_t> dc(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
215

Jens Petit's avatar
Jens Petit committed
216 217
        WHEN("putting in some random data")
        {
218 219
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{dc.getSize()};
            randVec.setRandom();
Tobias Lasser's avatar
Tobias Lasser committed
220 221 222
            for (index_t i = 0; i < dc.getSize(); ++i)
                dc[i] = randVec(i);

Jens Petit's avatar
Jens Petit committed
223 224
            THEN("the reductions work as expected")
            {
225 226 227 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()));

                Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec2{dc.getSize()};
                randVec2.setRandom();
                DataContainer<data_t> dc2(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
233 234 235
                for (index_t i = 0; i < dc2.getSize(); ++i)
                    dc2[i] = randVec2(i);

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

242 243 244 245 246 247 248 249 250
#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
251
{
252 253
    using data_t = typename TestType::data_t;

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

Jens Petit's avatar
Jens Petit committed
261 262
        WHEN("putting in some random data")
        {
263 264
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{dc.getSize()};
            randVec.setRandom();
Tobias Lasser's avatar
Tobias Lasser committed
265 266 267
            for (index_t i = 0; i < dc.getSize(); ++i)
                dc[i] = randVec(i);

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

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

290 291
            auto scalar = static_cast<data_t>(923.41f);

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

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

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

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

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

Jens Petit's avatar
Jens Petit committed
328 329
        WHEN("having two containers with random data")
        {
330 331
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{dc.getSize()};
            randVec.setRandom();
Tobias Lasser's avatar
Tobias Lasser committed
332 333 334
            for (index_t i = 0; i < dc.getSize(); ++i)
                dc[i] = randVec(i);

335 336 337
            Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec2{dc.getSize()};
            randVec2.setRandom();
            DataContainer<data_t> dc2(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
338 339 340
            for (index_t i = 0; i < dc2.getSize(); ++i)
                dc2[i] = randVec2[i];

Jens Petit's avatar
Jens Petit committed
341 342
            THEN("the element-wise in-place addition works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
343 344 345 346 347
                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
348 349
            THEN("the element-wise in-place subtraction works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
350 351 352 353 354
                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
355 356
            THEN("the element-wise in-place multiplication works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
357 358
                dc *= dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
359
                    REQUIRE(checkSameNumbers(dc[i], randVec(i) * randVec2(i), 100));
Tobias Lasser's avatar
Tobias Lasser committed
360 361
            }

Jens Petit's avatar
Jens Petit committed
362 363
            THEN("the element-wise in-place division works as expected")
            {
Tobias Lasser's avatar
Tobias Lasser committed
364 365
                dc /= dc2;
                for (index_t i = 0; i < dc.getSize(); ++i)
366 367
                    if (dc2[i] != data_t(0))
                        REQUIRE(checkSameNumbers(dc[i], randVec(i) / randVec2(i), 10));
Tobias Lasser's avatar
Tobias Lasser committed
368 369 370 371 372
            }
        }
    }
}

373 374 375 376 377 378 379 380 381 382
#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
383
{
384 385
    using data_t = typename TestType::data_t;

Jens Petit's avatar
Jens Petit committed
386 387
    GIVEN("some DataContainers")
    {
Tobias Lasser's avatar
Tobias Lasser committed
388 389 390 391
        IndexVector_t numCoeff(3);
        numCoeff << 52, 7, 29;
        DataDescriptor desc(numCoeff);

392 393
        DataContainer<data_t> dc(desc, TestType::handler_t);
        DataContainer<data_t> dc2(desc, TestType::handler_t);
Tobias Lasser's avatar
Tobias Lasser committed
394

395 396 397 398
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec{dc.getSize()};
        randVec.setRandom();
        Eigen::Matrix<data_t, Eigen::Dynamic, 1> randVec2{dc.getSize()};
        randVec2.setRandom();
Tobias Lasser's avatar
Tobias Lasser committed
399 400

        for (index_t i = 0; i < dc.getSize(); ++i) {
Jens Petit's avatar
Jens Petit committed
401
            dc[i] = randVec(i);
Tobias Lasser's avatar
Tobias Lasser committed
402 403 404
            dc2[i] = randVec2(i);
        }

Jens Petit's avatar
Jens Petit committed
405 406
        THEN("the binary element-wise operations work as expected")
        {
407
            DataContainer resultPlus = dc + dc2;
Tobias Lasser's avatar
Tobias Lasser committed
408
            for (index_t i = 0; i < dc.getSize(); ++i)
409
                REQUIRE(resultPlus[i] == dc[i] + dc2[i]);
Tobias Lasser's avatar
Tobias Lasser committed
410

411
            DataContainer resultMinus = dc - dc2;
Tobias Lasser's avatar
Tobias Lasser committed
412
            for (index_t i = 0; i < dc.getSize(); ++i)
413
                REQUIRE(resultMinus[i] == dc[i] - dc2[i]);
Tobias Lasser's avatar
Tobias Lasser committed
414

415
            DataContainer resultMult = dc * dc2;
Tobias Lasser's avatar
Tobias Lasser committed
416
            for (index_t i = 0; i < dc.getSize(); ++i)
417
                REQUIRE(checkSameNumbers(resultMult[i], dc[i] * dc2[i], 100));
Tobias Lasser's avatar
Tobias Lasser committed
418

419
            DataContainer resultDiv = dc / dc2;
Tobias Lasser's avatar
Tobias Lasser committed
420
            for (index_t i = 0; i < dc.getSize(); ++i)
421 422
                if (dc2[i] != data_t(0))
                    REQUIRE(checkSameNumbers(resultDiv[i], dc[i] / dc2[i], 1000));
Tobias Lasser's avatar
Tobias Lasser committed
423 424
        }

Jens Petit's avatar
Jens Petit committed
425 426
        THEN("the operations with a scalar work as expected")
        {
427
            data_t scalar = static_cast<data_t>(4.92f);
Tobias Lasser's avatar
Tobias Lasser committed
428

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

433
            DataContainer resultPlusScalar = dc + scalar;
Tobias Lasser's avatar
Tobias Lasser committed
434
            for (index_t i = 0; i < dc.getSize(); ++i)
435
                REQUIRE(resultPlusScalar[i] == dc[i] + scalar);
Tobias Lasser's avatar
Tobias Lasser committed
436

437
            DataContainer resultScalarMinus = scalar - dc;
Tobias Lasser's avatar
Tobias Lasser committed
438
            for (index_t i = 0; i < dc.getSize(); ++i)
439
                REQUIRE(resultScalarMinus[i] == scalar - dc[i]);
Tobias Lasser's avatar
Tobias Lasser committed
440

441
            DataContainer resultMinusScalar = dc - scalar;
Tobias Lasser's avatar
Tobias Lasser committed
442
            for (index_t i = 0; i < dc.getSize(); ++i)
443
                REQUIRE(resultMinusScalar[i] == dc[i] - scalar);
Tobias Lasser's avatar
Tobias Lasser committed
444

445
            DataContainer resultScalarMult = scalar * dc;
Tobias Lasser's avatar
Tobias Lasser committed
446
            for (index_t i = 0; i < dc.getSize(); ++i)
447
                REQUIRE(resultScalarMult[i] == scalar * dc[i]);
Tobias Lasser's avatar
Tobias Lasser committed
448

449
            DataContainer resultMultScalar = dc * scalar;
Tobias Lasser's avatar
Tobias Lasser committed
450
            for (index_t i = 0; i < dc.getSize(); ++i)
451
                REQUIRE(resultMultScalar[i] == dc[i] * scalar);
Tobias Lasser's avatar
Tobias Lasser committed
452

453
            DataContainer resultScalarDiv = scalar / dc;
Tobias Lasser's avatar
Tobias Lasser committed
454
            for (index_t i = 0; i < dc.getSize(); ++i)
455 456
                if (dc[i] != data_t(0))
                    REQUIRE(checkSameNumbers(resultScalarDiv[i], scalar / dc[i]));
Tobias Lasser's avatar
Tobias Lasser committed
457

458
            DataContainer resultDivScalar = dc / scalar;
Tobias Lasser's avatar
Tobias Lasser committed
459
            for (index_t i = 0; i < dc.getSize(); ++i)
460
                REQUIRE(checkSameNumbers(resultDivScalar[i], dc[i] / scalar));
Jens Petit's avatar
Jens Petit committed
461 462 463 464
        }
    }
}

465 466 467 468 469 470 471 472 473
#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
474
{
475 476
    using data_t = typename TestType::data_t;

477
    GIVEN("a non-blocked container")
Jens Petit's avatar
Jens Petit committed
478
    {
Jens Petit's avatar
Jens Petit committed
479 480 481 482
        IndexVector_t numCoeff(3);
        numCoeff << 52, 7, 29;
        DataDescriptor desc(numCoeff);

483 484
        DataContainer<data_t> dc(desc, TestType::handler_t);
        const DataContainer<data_t> constDc(desc, TestType::handler_t);
Jens Petit's avatar
Jens Petit committed
485

486
        WHEN("trying to reference a block")
Jens Petit's avatar
Jens Petit committed
487
        {
488
            THEN("an exception occurs")
Jens Petit's avatar
Jens Petit committed
489
            {
490 491
                REQUIRE_THROWS(dc.getBlock(0));
                REQUIRE_THROWS(constDc.getBlock(0));
Jens Petit's avatar
Jens Petit committed
492 493 494
            }
        }

495
        WHEN("creating a view")
Jens Petit's avatar
Jens Petit committed
496
        {
497 498 499 500 501
            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
502

503
            THEN("view has the correct descriptor and data")
Jens Petit's avatar
Jens Petit committed
504
            {
505 506
                REQUIRE(linearDesc == linearDc.getDataDescriptor());
                REQUIRE(&linearDc[0] == &dc[0]);
Jens Petit's avatar
Jens Petit committed
507

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

511 512 513 514
                AND_THEN("view is not a shallow copy")
                {
                    const auto dcCopy = dc;
                    const auto constDcCopy = constDc;
Jens Petit's avatar
Jens Petit committed
515

516 517 518
                    linearDc[0] = 1;
                    REQUIRE(&linearDc[0] == &dc[0]);
                    REQUIRE(&linearDc[0] != &dcCopy[0]);
Jens Petit's avatar
Jens Petit committed
519

520 521 522 523
                    linearConstDc[0] = 1;
                    REQUIRE(&linearConstDc[0] == &constDc[0]);
                    REQUIRE(&linearConstDc[0] != &constDcCopy[0]);
                }
Jens Petit's avatar
Jens Petit committed
524
            }
525 526
        }
    }
Jens Petit's avatar
Jens Petit committed
527

528 529 530 531 532 533
    GIVEN("a blocked container")
    {
        IndexVector_t numCoeff(2);
        numCoeff << 52, 29;
        DataDescriptor desc(numCoeff);
        index_t numBlocks = 7;
534
        IdenticalBlocksDescriptor blockDesc(numBlocks, desc);
Jens Petit's avatar
Jens Petit committed
535

536 537
        DataContainer<data_t> dc(blockDesc, TestType::handler_t);
        const DataContainer<data_t> constDc(blockDesc, TestType::handler_t);
Jens Petit's avatar
Jens Petit committed
538

539 540 541
        WHEN("referencing a block")
        {
            THEN("block has the correct descriptor and data")
Jens Petit's avatar
Jens Petit committed
542
            {
543 544 545
                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
546

547 548 549 550 551 552
                    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
553 554 555
            }
        }

Jens Petit's avatar
Jens Petit committed
556
        WHEN("creating a view")
Jens Petit's avatar
Jens Petit committed
557
        {
558 559 560 561 562 563 564 565 566 567 568 569 570
            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
571

572 573 574 575 576 577 578 579 580 581 582 583 584 585
                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
586 587
        }
    }
588 589
}

Jens Petit's avatar
Jens Petit committed
590 591 592 593
SCENARIO("Testing iterators for DataContainer")
{
    GIVEN("A 1D container")
    {
594 595 596 597 598 599 600 601
        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
602
        Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size);
603 604 605 606 607 608 609
        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
610 611
        THEN("We can iterate forward")
        {
612 613 614 615 616 617 618
            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
619 620
        THEN("We can iterate backward")
        {
621 622 623 624 625 626 627
            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
628 629
        THEN("We can iterate and mutate")
        {
630 631
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
632
                v = v * 2;
633 634 635 636 637 638 639 640 641 642 643
                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
644 645
        THEN("We can use STL algorithms")
        {
646 647 648 649
            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
650 651
    GIVEN("A 2D container")
    {
652 653 654 655 656 657 658 659 660 661 662 663 664
        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
665 666
        THEN("We can iterate forward")
        {
667
            int i = 0;
Jens Petit's avatar
Jens Petit committed
668
            for (auto v : dc1) {
669 670 671 672 673
                REQUIRE(v == randVec1[i++]);
            }
            REQUIRE(i == size * size);
        }

Jens Petit's avatar
Jens Petit committed
674 675
        THEN("We can iterate backward")
        {
676 677 678 679 680 681 682
            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
683 684
        THEN("We can iterate and mutate")
        {
685 686
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
687
                v = v * 2;
688 689 690 691 692 693 694 695 696 697 698
                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
699 700
        THEN("We can use STL algorithms")
        {
701 702 703 704
            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
705 706
    GIVEN("A 3D container")
    {
707 708 709 710 711 712 713
        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
714
        Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size * size);
715 716 717 718 719

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

Jens Petit's avatar
Jens Petit committed
720 721
        THEN("We can iterate forward")
        {
722 723 724 725 726 727 728
            int i = 0;
            for (auto v : dc1) {
                REQUIRE(v == randVec1[i++]);
            }
            REQUIRE(i == size * size * size);
        }

Jens Petit's avatar
Jens Petit committed
729 730
        THEN("We can iterate backward")
        {
731 732 733 734 735 736 737
            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
738 739
        THEN("We can iterate and mutate")
        {
740 741
            int i = 0;
            for (auto& v : dc1) {
Jens Petit's avatar
Jens Petit committed
742
                v = v * 2;
743 744 745 746 747 748 749 750 751 752 753
                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
754 755
        THEN("We can use STL algorithms")
        {
756 757 758 759
            REQUIRE(*std::min_element(dc1.cbegin(), dc1.cend()) == randVec1.minCoeff());
            REQUIRE(*std::max_element(dc1.cbegin(), dc1.cend()) == randVec1.maxCoeff());
        }
    }
760
}