LCOV - code coverage report
Current view: top level - elsa/operators/tests - test_BlockLinearOperator.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 489 489 100.0 %
Date: 2022-08-25 03:05:39 Functions: 10 10 100.0 %

          Line data    Source code
       1             : #include "doctest/doctest.h"
       2             : 
       3             : #include "IdenticalBlocksDescriptor.h"
       4             : #include "PartitionDescriptor.h"
       5             : #include "RandomBlocksDescriptor.h"
       6             : #include "BlockLinearOperator.h"
       7             : #include "VolumeDescriptor.h"
       8             : #include "Identity.h"
       9             : #include "Scaling.h"
      10             : #include "TypeCasts.hpp"
      11             : #include "testHelpers.h"
      12             : 
      13             : using namespace elsa;
      14             : using namespace doctest;
      15             : 
      16             : TEST_SUITE_BEGIN("core");
      17             : 
      18             : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing construction", TestType, float, double)
      19          28 : {
      20          28 :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
      21          28 :     using OperatoList = std::vector<std::unique_ptr<LinearOperator<TestType>>>;
      22             : 
      23          28 :     index_t rows = 6, cols = 8;
      24          28 :     IndexVector_t size2D(2);
      25          28 :     size2D << rows, cols;
      26          28 :     VolumeDescriptor dd{size2D};
      27             : 
      28          28 :     auto sizeBlock = size2D;
      29          28 :     sizeBlock[1] *= 2;
      30          28 :     VolumeDescriptor bdBase{sizeBlock};
      31          28 :     PartitionDescriptor bd{bdBase, 2};
      32             : 
      33          28 :     GIVEN("an empty operator list")
      34          28 :     {
      35             : 
      36           2 :         OperatoList ops;
      37             : 
      38           2 :         WHEN("creating a BlockLinearOperator from it")
      39           2 :         {
      40           2 :             THEN("an exception is thrown")
      41           2 :             {
      42           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
      43           2 :                                   InvalidArgumentError);
      44             : 
      45           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
      46           2 :                                   InvalidArgumentError);
      47             : 
      48           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bd, ops, BlockType::ROW),
      49           2 :                                   InvalidArgumentError);
      50             : 
      51           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, dd, ops, BlockType::COL),
      52           2 :                                   InvalidArgumentError);
      53           2 :             }
      54           2 :         }
      55           2 :     }
      56             : 
      57          28 :     GIVEN("a list of identical operators")
      58          28 :     {
      59          10 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
      60          10 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
      61          10 :         ops.push_back(std::move(iop1->clone()));
      62          10 :         ops.push_back(std::move(iop1->clone()));
      63          10 :         WHEN("creating a BlockLinearOperator from it")
      64          10 :         {
      65           4 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
      66           4 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
      67             : 
      68           4 :             THEN("the BlockLinearOperator contains the correct operators")
      69           4 :             {
      70           2 :                 REQUIRE_EQ(blockOp1.numberOfOps(), 2);
      71           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
      72           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(1), *iop1);
      73           2 :                 REQUIRE_EQ(blockOp2.numberOfOps(), 2);
      74           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
      75           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(1), *iop1);
      76           2 :             }
      77             : 
      78           4 :             THEN("the automatically generated operator descriptors are correct")
      79           4 :             {
      80           2 :                 REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd);
      81           2 :                 REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
      82           2 :                 REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
      83           2 :                 REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd);
      84           2 :             }
      85           4 :         }
      86             : 
      87          10 :         WHEN("creating a BlockLinearOperator with user specified descriptors from it")
      88          10 :         {
      89           4 :             IdenticalBlocksDescriptor bd2{2, dd};
      90           4 :             VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
      91           4 :             BlockLinearOperator<TestType> blockOp1{bd2, ddLinearized, ops, BlockType::COL};
      92           4 :             BlockLinearOperator<TestType> blockOp2{ddLinearized, bd2, ops, BlockType::ROW};
      93             : 
      94           4 :             THEN("the BlockLinearOperator contains the correct operators")
      95           4 :             {
      96           2 :                 REQUIRE_EQ(blockOp1.numberOfOps(), 2);
      97           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
      98           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(1), *iop1);
      99           2 :                 REQUIRE_EQ(blockOp2.numberOfOps(), 2);
     100           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
     101           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(1), *iop1);
     102           2 :             }
     103             : 
     104           4 :             THEN("the automatically generated operator descriptors are correct")
     105           4 :             {
     106           2 :                 REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd2);
     107           2 :                 REQUIRE_EQ(blockOp1.getRangeDescriptor(), ddLinearized);
     108           2 :                 REQUIRE_EQ(blockOp2.getDomainDescriptor(), ddLinearized);
     109           2 :                 REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd2);
     110           2 :             }
     111           4 :         }
     112             : 
     113          10 :         WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
     114          10 :         {
     115           2 :             THEN("an exception is thrown")
     116           2 :             {
     117           2 :                 IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
     118             : 
     119             :                 // wrong number of coefficients
     120           2 :                 REQUIRE_THROWS_AS(
     121           2 :                     BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
     122           2 :                     InvalidArgumentError);
     123           2 :                 REQUIRE_THROWS_AS(
     124           2 :                     BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
     125           2 :                     InvalidArgumentError);
     126           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
     127           2 :                                   InvalidArgumentError);
     128           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
     129           2 :                                   InvalidArgumentError);
     130             : 
     131             :                 // descriptor not of block type
     132           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
     133           2 :                                   InvalidArgumentError);
     134           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
     135           2 :                                   InvalidArgumentError);
     136           2 :             }
     137           2 :         }
     138          10 :     }
     139             : 
     140          28 :     GIVEN("a list of operators with different number of dimensions")
     141          28 :     {
     142          10 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     143          10 :         VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
     144          10 :         auto iop2 = std::make_unique<Identity<TestType>>(ddLinearized);
     145          10 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     146          10 :         ops.push_back(std::move(iop1->clone()));
     147          10 :         ops.push_back(std::move(iop2->clone()));
     148             : 
     149          10 :         std::vector<std::unique_ptr<DataDescriptor>> descVec;
     150          10 :         descVec.push_back(dd.clone());
     151          10 :         descVec.push_back(ddLinearized.clone());
     152          10 :         RandomBlocksDescriptor expectedBlocks(std::move(descVec));
     153             : 
     154          10 :         WHEN("creating a BlockLinearOperator from it")
     155          10 :         {
     156           4 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
     157           4 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
     158             : 
     159           4 :             THEN("the BlockLinearOperator contains the correct operators")
     160           4 :             {
     161           2 :                 REQUIRE_EQ(blockOp1.numberOfOps(), 2);
     162           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
     163           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
     164           2 :                 REQUIRE_EQ(blockOp2.numberOfOps(), 2);
     165           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
     166           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
     167           2 :             }
     168             : 
     169           4 :             THEN("the automatically generated operator descriptors are correct")
     170           4 :             {
     171           2 :                 REQUIRE_EQ(blockOp1.getDomainDescriptor(), expectedBlocks);
     172           2 :                 REQUIRE_EQ(blockOp1.getRangeDescriptor(), ddLinearized);
     173           2 :                 REQUIRE_EQ(blockOp2.getDomainDescriptor(), ddLinearized);
     174           2 :                 REQUIRE_EQ(blockOp2.getRangeDescriptor(), expectedBlocks);
     175           2 :             }
     176           4 :         }
     177             : 
     178          10 :         WHEN("creating a BlockLinearOperator with user specified descriptors from it")
     179          10 :         {
     180           4 :             IdenticalBlocksDescriptor bd2{2, dd};
     181           4 :             VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
     182           4 :             BlockLinearOperator<TestType> blockOp1{bd2, dd, ops, BlockType::COL};
     183           4 :             BlockLinearOperator<TestType> blockOp2{dd, bd2, ops, BlockType::ROW};
     184             : 
     185           4 :             THEN("the BlockLinearOperator contains the correct operators")
     186           4 :             {
     187           2 :                 REQUIRE_EQ(blockOp1.numberOfOps(), 2);
     188           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
     189           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
     190           2 :                 REQUIRE_EQ(blockOp2.numberOfOps(), 2);
     191           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
     192           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
     193           2 :             }
     194             : 
     195           4 :             THEN("the automatically generated operator descriptors are correct")
     196           4 :             {
     197           2 :                 REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd2);
     198           2 :                 REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
     199           2 :                 REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
     200           2 :                 REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd2);
     201           2 :             }
     202           4 :         }
     203             : 
     204          10 :         WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
     205          10 :         {
     206           2 :             THEN("an exception is thrown")
     207           2 :             {
     208           2 :                 IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
     209             : 
     210             :                 // wrong number of coefficients
     211           2 :                 REQUIRE_THROWS_AS(
     212           2 :                     BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
     213           2 :                     InvalidArgumentError);
     214           2 :                 REQUIRE_THROWS_AS(
     215           2 :                     BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
     216           2 :                     InvalidArgumentError);
     217           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
     218           2 :                                   InvalidArgumentError);
     219           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
     220           2 :                                   InvalidArgumentError);
     221             : 
     222             :                 // descriptor not of block type
     223           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
     224           2 :                                   InvalidArgumentError);
     225           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
     226           2 :                                   InvalidArgumentError);
     227           2 :             }
     228           2 :         }
     229          10 :     }
     230             : 
     231          28 :     GIVEN("a list of operators that cannot be stacked in the given fashion")
     232          28 :     {
     233           2 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     234           2 :         auto iop2 = std::make_unique<Identity<TestType>>(bdBase);
     235           2 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     236           2 :         ops.push_back(std::move(iop1->clone()));
     237           2 :         ops.push_back(std::move(iop2->clone()));
     238             : 
     239           2 :         WHEN("creating a BlockLinearOperator from it")
     240           2 :         {
     241           2 :             THEN("an exception is thrown")
     242           2 :             {
     243           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
     244           2 :                                   InvalidArgumentError);
     245           2 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
     246           2 :                                   InvalidArgumentError);
     247           2 :             }
     248           2 :         }
     249           2 :     }
     250             : 
     251          28 :     GIVEN("a list of operators whose descriptors have equal number of coefficients per dimension "
     252          28 :           "but different spacing")
     253          28 :     {
     254           4 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     255           4 :         VolumeDescriptor dds2{size2D, dd.getSpacingPerDimension() * 2};
     256           4 :         auto iop2 = std::make_unique<Identity<TestType>>(dds2);
     257           4 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     258           4 :         ops.push_back(std::move(iop1->clone()));
     259           4 :         ops.push_back(std::move(iop2->clone()));
     260             : 
     261           4 :         WHEN("creating a BlockLinearOperator from it")
     262           4 :         {
     263           4 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
     264           4 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
     265             : 
     266           4 :             THEN("the BlockLinearOperator contains the correct operators")
     267           4 :             {
     268           2 :                 REQUIRE_EQ(blockOp1.numberOfOps(), 2);
     269           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
     270           2 :                 REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
     271           2 :                 REQUIRE_EQ(blockOp2.numberOfOps(), 2);
     272           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
     273           2 :                 REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
     274           2 :             }
     275             : 
     276           4 :             THEN("the automatically generated operator descriptors are correct and have a uniform "
     277           4 :                  "spacing of one")
     278           4 :             {
     279           2 :                 REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd);
     280           2 :                 REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
     281           2 :                 REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
     282           2 :                 REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd);
     283           2 :             }
     284           4 :         }
     285           4 :     }
     286          28 : }
     287             : 
     288             : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing apply", TestType, float, double)
     289           8 : {
     290           8 :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     291           8 :     index_t rows = 4, cols = 8, numBlks = 3;
     292           8 :     GIVEN("a 2D volume")
     293           8 :     {
     294           6 :         IndexVector_t domainIndex(2);
     295           6 :         domainIndex << rows, cols;
     296           6 :         VolumeDescriptor domainDesc(domainIndex);
     297             : 
     298           6 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
     299           6 :         vec << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     300           6 :             2, 2, 2, 2;
     301             : 
     302           6 :         DataContainer<TestType> domain(domainDesc, vec);
     303             : 
     304           6 :         WHEN("3 Scaling operators are applied to it, in a ROW-Block fashion")
     305           6 :         {
     306           6 :             IndexVector_t rangeIndex(2);
     307           6 :             rangeIndex << rows, cols * numBlks;
     308           6 :             VolumeDescriptor rangeDesc(rangeIndex);
     309           6 :             DataContainer<TestType> range(rangeDesc);
     310             : 
     311           6 :             TestType scale1 = 2.f;
     312           6 :             TestType scale2 = 3.f;
     313           6 :             TestType scale3 = 4.f;
     314             : 
     315           6 :             std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     316           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
     317           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     318           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
     319             : 
     320           6 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     321             : 
     322           6 :             blockOp.apply(domain, range);
     323             : 
     324           6 :             THEN("the for the first block, x was multiplied by 2.")
     325           6 :             {
     326          66 :                 for (int i = 0; i < rows * cols; i++)
     327           2 :                     REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1));
     328           2 :             }
     329           6 :             THEN("the for the second block, x was multiplied by 3.")
     330           6 :             {
     331          66 :                 for (int i = 0; i < rows * cols; i++)
     332           2 :                     REQUIRE_UNARY(checkApproxEq(range[i + rows * cols], vec[i] * scale2));
     333           2 :             }
     334           6 :             THEN("the for the third block, x was multiplied by 4.")
     335           6 :             {
     336          66 :                 for (int i = 0; i < rows * cols; i++)
     337           2 :                     REQUIRE_UNARY(checkApproxEq(range[i + rows * cols * 2], vec[i] * scale3));
     338           2 :             }
     339           6 :         }
     340           6 :     }
     341             : 
     342           8 :     GIVEN("a 2D volume with 3 blocks")
     343           8 :     {
     344           2 :         IndexVector_t blockIndex(2);
     345           2 :         blockIndex << rows, cols;
     346           2 :         VolumeDescriptor blockDesc(blockIndex);
     347           2 :         IdenticalBlocksDescriptor domainDesc(numBlks, blockDesc);
     348             : 
     349           2 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
     350           2 :         vec << 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
     351             : 
     352           2 :             1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
     353             : 
     354           2 :             2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
     355             : 
     356           2 :             1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2;
     357             : 
     358           2 :         DataContainer<TestType> domain(domainDesc, vec);
     359             : 
     360           2 :         WHEN("3 Scaling operators are applied to it in a COL-Block fashion")
     361           2 :         {
     362           2 :             IndexVector_t rangeIndex(2);
     363           2 :             rangeIndex << rows, cols;
     364           2 :             VolumeDescriptor rangeDesc(rangeIndex);
     365           2 :             DataContainer<TestType> range(rangeDesc);
     366             : 
     367           2 :             float scale1 = 2.f;
     368           2 :             float scale2 = 3.f;
     369           2 :             float scale3 = 4.f;
     370             : 
     371           2 :             std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     372           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale1)));
     373           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale2)));
     374           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale3)));
     375             : 
     376           2 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     377             : 
     378           2 :             blockOp.apply(domain, range);
     379             : 
     380           2 :             THEN("then the range data, is a component wise addition of the 3 blocks each "
     381           2 :                  "scaled with the corresponding factor")
     382           2 :             {
     383           2 :                 auto size = rows * cols;
     384          66 :                 for (int i = 0; i < size; i++) {
     385          64 :                     REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1 + vec[i + size] * scale2
     386          64 :                                                               + vec[i + size * 2] * scale3));
     387          64 :                 }
     388           2 :             }
     389           2 :         }
     390           2 :     }
     391           8 : }
     392             : 
     393             : TEST_CASE_TEMPLATE("BlockLinearOperator: applyAdjoint", TestType, float, double)
     394           8 : {
     395           8 :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     396           8 :     index_t rows = 4, cols = 8, numBlks = 3;
     397           8 :     GIVEN("a 2D volume with 3 blocks")
     398           8 :     {
     399           2 :         IndexVector_t rangeIndex(2);
     400           2 :         rangeIndex << rows, cols * numBlks;
     401           2 :         VolumeDescriptor rangeDesc(rangeIndex);
     402             : 
     403           2 :         const index_t n = rangeDesc.getNumberOfCoefficients();
     404           2 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> rangeVec(n);
     405           2 :         rangeVec.topRows(n / 3).setConstant(5);
     406           2 :         rangeVec.middleRows(n / 3, 2 * n / 3).setConstant(7);
     407           2 :         rangeVec.bottomRows(n / 3).setOnes();
     408             : 
     409           2 :         DataContainer<TestType> range(rangeDesc, rangeVec);
     410             : 
     411           2 :         WHEN("applying the adjoint of 3 Scaling operators ordered in a ROW-Block fashion")
     412           2 :         {
     413           2 :             IndexVector_t domainIndex(2);
     414           2 :             domainIndex << rows, cols;
     415           2 :             VolumeDescriptor domainDesc(domainIndex);
     416             : 
     417           2 :             TestType scale1 = 2.f;
     418           2 :             TestType scale2 = 3.f;
     419           2 :             TestType scale3 = 4.f;
     420             : 
     421           2 :             std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     422           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
     423           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     424           2 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
     425             : 
     426           2 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     427             : 
     428           2 :             auto result = blockOp.applyAdjoint(range);
     429             : 
     430           2 :             THEN("then the result is a component wise addition of the 3 blocks each "
     431           2 :                  "scaled with the corresponding factor")
     432           2 :             {
     433          66 :                 for (int i = 0; i < rows * cols; i++)
     434           2 :                     REQUIRE_UNARY(checkApproxEq(result[i], 35));
     435           2 :             }
     436           2 :         }
     437           2 :     }
     438             : 
     439           8 :     GIVEN("a 2D volume")
     440           8 :     {
     441           6 :         IndexVector_t rangeIndex(2);
     442           6 :         rangeIndex << rows, cols;
     443           6 :         VolumeDescriptor rangeDesc(rangeIndex);
     444             : 
     445           6 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(rangeDesc.getNumberOfCoefficients());
     446           6 :         vec << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     447           6 :             2, 2, 2, 2;
     448             : 
     449           6 :         DataContainer<TestType> range(rangeDesc, vec);
     450             : 
     451           6 :         WHEN("applying the adjoint of 3 Scaling operators ordered in a COL-Block fashion")
     452           6 :         {
     453           6 :             TestType scale1 = 2.f;
     454           6 :             TestType scale2 = 3.f;
     455           6 :             TestType scale3 = 4.f;
     456             : 
     457           6 :             std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     458           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale1)));
     459           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale2)));
     460           6 :             ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale3)));
     461             : 
     462           6 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     463             : 
     464           6 :             auto result = blockOp.applyAdjoint(range);
     465             : 
     466           6 :             THEN("the for the first block, x was multiplied by 2.")
     467           6 :             {
     468          66 :                 for (int i = 0; i < rows * cols; i++)
     469           2 :                     REQUIRE_EQ(result[i], vec[i] * scale1);
     470           2 :             }
     471           6 :             THEN("the for the second block, x was multiplied by 3.")
     472           6 :             {
     473          66 :                 for (int i = 0; i < rows * cols; i++)
     474           2 :                     REQUIRE_EQ(result[i + rows * cols], vec[i] * scale2);
     475           2 :             }
     476           6 :             THEN("the for the third block, x was multiplied by 4.")
     477           6 :             {
     478          66 :                 for (int i = 0; i < rows * cols; i++)
     479           2 :                     REQUIRE_EQ(result[i + rows * cols * 2], vec[i] * scale3);
     480           2 :             }
     481           6 :         }
     482           6 :     }
     483           8 : }
     484             : 
     485             : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing cloning", TestType, float, double)
     486           4 : {
     487           4 :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     488           4 :     index_t rows = 4, cols = 8;
     489           4 :     GIVEN("a ROW BlockLinearOperator")
     490           4 :     {
     491           2 :         IndexVector_t domainIndex(2);
     492           2 :         domainIndex << rows, cols;
     493           2 :         VolumeDescriptor domainDesc(domainIndex);
     494             : 
     495           2 :         TestType scale1 = 2.f;
     496           2 :         TestType scale2 = 3.f;
     497           2 :         TestType scale3 = 4.f;
     498             : 
     499           2 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     500           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
     501           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     502           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
     503             : 
     504           2 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     505             : 
     506           2 :         WHEN("cloning the operator")
     507           2 :         {
     508           2 :             auto bloClone = blockOp.clone();
     509             : 
     510           2 :             THEN("it's a real clone")
     511           2 :             {
     512           2 :                 REQUIRE_NE(bloClone.get(), &blockOp);
     513           2 :                 REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
     514           2 :                 REQUIRE_EQ(blockOp, *bloClone);
     515           2 :             }
     516           2 :         }
     517           2 :     }
     518             : 
     519           4 :     GIVEN("a COL BlockLinearOperator")
     520           4 :     {
     521           2 :         IndexVector_t rangeIndex(2);
     522           2 :         rangeIndex << rows, cols;
     523           2 :         VolumeDescriptor rangeDesc(rangeIndex);
     524             : 
     525           2 :         TestType scale1 = 2.f;
     526           2 :         TestType scale2 = 3.f;
     527           2 :         TestType scale3 = 4.f;
     528             : 
     529           2 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     530           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale1)));
     531           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale2)));
     532           2 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale3)));
     533             : 
     534           2 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     535             : 
     536           2 :         WHEN("cloning the operator")
     537           2 :         {
     538           2 :             auto bloClone = blockOp.clone();
     539             : 
     540           2 :             THEN("it's a real clone")
     541           2 :             {
     542           2 :                 REQUIRE_NE(bloClone.get(), &blockOp);
     543           2 :                 REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
     544           2 :                 REQUIRE_EQ(blockOp, *bloClone);
     545           2 :             }
     546           2 :         }
     547           2 :     }
     548           4 : }
     549             : 
     550             : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing comparison", TestType, float, double)
     551           6 : {
     552           6 :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     553           6 :     index_t rows = 4, cols = 8;
     554           6 :     GIVEN("a BlockLinearOperator")
     555           6 :     {
     556           6 :         IndexVector_t domainIndex(2);
     557           6 :         domainIndex << rows, cols;
     558           6 :         VolumeDescriptor domainDesc(domainIndex);
     559             : 
     560           6 :         TestType scale1 = 2.f;
     561           6 :         TestType scale2 = 3.f;
     562           6 :         TestType scale3 = 4.f;
     563             : 
     564           6 :         std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
     565           6 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
     566           6 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     567           6 :         ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
     568             : 
     569           6 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     570             : 
     571           6 :         WHEN("comparing the operator to a leaf of itself")
     572           6 :         {
     573           2 :             auto blockOpLeaf = leaf(blockOp);
     574             : 
     575           2 :             THEN("they are not equal")
     576           2 :             {
     577           2 :                 REQUIRE_NE(blockOp, blockOpLeaf);
     578           2 :                 REQUIRE_NE(blockOpLeaf, blockOp);
     579           2 :             }
     580           2 :         }
     581             : 
     582           6 :         WHEN("comparing the operator to a BlockLinearOperator containing the same operators, but "
     583           6 :              "stacked differently")
     584           6 :         {
     585           2 :             BlockLinearOperator<TestType> blockOp2(ops, BlockType::COL);
     586             : 
     587           2 :             THEN("they are not equal")
     588           2 :             {
     589           2 :                 REQUIRE_NE(blockOp, blockOp2);
     590           2 :                 REQUIRE_NE(blockOp2, blockOp);
     591           2 :             }
     592           2 :         }
     593             : 
     594           6 :         WHEN("comparing the operator to a BlockLinearOperator containing different operators")
     595           6 :         {
     596           2 :             std::vector<std::unique_ptr<LinearOperator<TestType>>> ops2(0);
     597           2 :             ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
     598           2 :             ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     599           2 :             ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
     600           2 :             BlockLinearOperator<TestType> blockOp2(ops2, BlockType::ROW);
     601             : 
     602           2 :             THEN("they are not equal")
     603           2 :             {
     604           2 :                 REQUIRE_NE(blockOp, blockOp2);
     605           2 :                 REQUIRE_NE(blockOp2, blockOp);
     606           2 :             }
     607           2 :         }
     608           6 :     }
     609           6 : }
     610             : TEST_SUITE_END();

Generated by: LCOV version 1.14