LCOV - code coverage report
Current view: top level - operators/tests - test_BlockLinearOperator.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 340 340 100.0 %
Date: 2022-02-28 03:37:41 Functions: 25 25 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          58 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing construction", TestType, float, double)
      19             : {
      20             :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
      21             :     using OperatoList = std::vector<std::unique_ptr<LinearOperator<TestType>>>;
      22             : 
      23          28 :     index_t rows = 6, cols = 8;
      24          56 :     IndexVector_t size2D(2);
      25          28 :     size2D << rows, cols;
      26          56 :     VolumeDescriptor dd{size2D};
      27             : 
      28          56 :     auto sizeBlock = size2D;
      29          28 :     sizeBlock[1] *= 2;
      30          56 :     VolumeDescriptor bdBase{sizeBlock};
      31          56 :     PartitionDescriptor bd{bdBase, 2};
      32             : 
      33          30 :     GIVEN("an empty operator list")
      34             :     {
      35             : 
      36           4 :         OperatoList ops;
      37             : 
      38           4 :         WHEN("creating a BlockLinearOperator from it")
      39             :         {
      40           4 :             THEN("an exception is thrown")
      41             :             {
      42           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
      43             :                                   InvalidArgumentError);
      44             : 
      45           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
      46             :                                   InvalidArgumentError);
      47             : 
      48           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bd, ops, BlockType::ROW),
      49             :                                   InvalidArgumentError);
      50             : 
      51           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, dd, ops, BlockType::COL),
      52             :                                   InvalidArgumentError);
      53             :             }
      54             :         }
      55             :     }
      56             : 
      57          38 :     GIVEN("a list of identical operators")
      58             :     {
      59          20 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
      60          20 :         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          14 :         WHEN("creating a BlockLinearOperator from it")
      64             :         {
      65           8 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
      66           8 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
      67             : 
      68           6 :             THEN("the BlockLinearOperator contains the correct operators")
      69             :             {
      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             :             }
      77             : 
      78           6 :             THEN("the automatically generated operator descriptors are correct")
      79             :             {
      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             :             }
      85             :         }
      86             : 
      87          14 :         WHEN("creating a BlockLinearOperator with user specified descriptors from it")
      88             :         {
      89           8 :             IdenticalBlocksDescriptor bd2{2, dd};
      90           8 :             VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
      91           8 :             BlockLinearOperator<TestType> blockOp1{bd2, ddLinearized, ops, BlockType::COL};
      92           8 :             BlockLinearOperator<TestType> blockOp2{ddLinearized, bd2, ops, BlockType::ROW};
      93             : 
      94           6 :             THEN("the BlockLinearOperator contains the correct operators")
      95             :             {
      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             :             }
     103             : 
     104           6 :             THEN("the automatically generated operator descriptors are correct")
     105             :             {
     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             :             }
     111             :         }
     112             : 
     113          12 :         WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
     114             :         {
     115           4 :             THEN("an exception is thrown")
     116             :             {
     117           4 :                 IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
     118             : 
     119             :                 // wrong number of coefficients
     120           4 :                 REQUIRE_THROWS_AS(
     121             :                     BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
     122             :                     InvalidArgumentError);
     123           4 :                 REQUIRE_THROWS_AS(
     124             :                     BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
     125             :                     InvalidArgumentError);
     126           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
     127             :                                   InvalidArgumentError);
     128           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
     129             :                                   InvalidArgumentError);
     130             : 
     131             :                 // descriptor not of block type
     132           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
     133             :                                   InvalidArgumentError);
     134           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
     135             :                                   InvalidArgumentError);
     136             :             }
     137             :         }
     138             :     }
     139             : 
     140          38 :     GIVEN("a list of operators with different number of dimensions")
     141             :     {
     142          20 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     143          20 :         VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
     144          20 :         auto iop2 = std::make_unique<Identity<TestType>>(ddLinearized);
     145          20 :         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          20 :         std::vector<std::unique_ptr<DataDescriptor>> descVec;
     150          10 :         descVec.push_back(dd.clone());
     151          10 :         descVec.push_back(ddLinearized.clone());
     152          20 :         RandomBlocksDescriptor expectedBlocks(std::move(descVec));
     153             : 
     154          14 :         WHEN("creating a BlockLinearOperator from it")
     155             :         {
     156           8 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
     157           8 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
     158             : 
     159           6 :             THEN("the BlockLinearOperator contains the correct operators")
     160             :             {
     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             :             }
     168             : 
     169           6 :             THEN("the automatically generated operator descriptors are correct")
     170             :             {
     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             :             }
     176             :         }
     177             : 
     178          14 :         WHEN("creating a BlockLinearOperator with user specified descriptors from it")
     179             :         {
     180           8 :             IdenticalBlocksDescriptor bd2{2, dd};
     181           8 :             VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
     182           8 :             BlockLinearOperator<TestType> blockOp1{bd2, dd, ops, BlockType::COL};
     183           8 :             BlockLinearOperator<TestType> blockOp2{dd, bd2, ops, BlockType::ROW};
     184             : 
     185           6 :             THEN("the BlockLinearOperator contains the correct operators")
     186             :             {
     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             :             }
     194             : 
     195           6 :             THEN("the automatically generated operator descriptors are correct")
     196             :             {
     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             :             }
     202             :         }
     203             : 
     204          12 :         WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
     205             :         {
     206           4 :             THEN("an exception is thrown")
     207             :             {
     208           4 :                 IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
     209             : 
     210             :                 // wrong number of coefficients
     211           4 :                 REQUIRE_THROWS_AS(
     212             :                     BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
     213             :                     InvalidArgumentError);
     214           4 :                 REQUIRE_THROWS_AS(
     215             :                     BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
     216             :                     InvalidArgumentError);
     217           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
     218             :                                   InvalidArgumentError);
     219           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
     220             :                                   InvalidArgumentError);
     221             : 
     222             :                 // descriptor not of block type
     223           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
     224             :                                   InvalidArgumentError);
     225           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
     226             :                                   InvalidArgumentError);
     227             :             }
     228             :         }
     229             :     }
     230             : 
     231          30 :     GIVEN("a list of operators that cannot be stacked in the given fashion")
     232             :     {
     233           4 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     234           4 :         auto iop2 = std::make_unique<Identity<TestType>>(bdBase);
     235           4 :         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           4 :         WHEN("creating a BlockLinearOperator from it")
     240             :         {
     241           4 :             THEN("an exception is thrown")
     242             :             {
     243           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
     244             :                                   InvalidArgumentError);
     245           4 :                 REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
     246             :                                   InvalidArgumentError);
     247             :             }
     248             :         }
     249             :     }
     250             : 
     251          32 :     GIVEN("a list of operators whose descriptors have equal number of coefficients per dimension "
     252             :           "but different spacing")
     253             :     {
     254           8 :         auto iop1 = std::make_unique<Identity<TestType>>(dd);
     255          12 :         VolumeDescriptor dds2{size2D, dd.getSpacingPerDimension() * 2};
     256           8 :         auto iop2 = std::make_unique<Identity<TestType>>(dds2);
     257           8 :         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           8 :         WHEN("creating a BlockLinearOperator from it")
     262             :         {
     263           8 :             BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
     264           8 :             BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
     265             : 
     266           6 :             THEN("the BlockLinearOperator contains the correct operators")
     267             :             {
     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             :             }
     275             : 
     276           6 :             THEN("the automatically generated operator descriptors are correct and have a uniform "
     277             :                  "spacing of one")
     278             :             {
     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             :             }
     284             :         }
     285             :     }
     286          28 : }
     287             : 
     288          38 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing apply", TestType, float, double)
     289             : {
     290             :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     291           8 :     index_t rows = 4, cols = 8, numBlks = 3;
     292          14 :     GIVEN("a 2D volume")
     293             :     {
     294          12 :         IndexVector_t domainIndex(2);
     295           6 :         domainIndex << rows, cols;
     296          12 :         VolumeDescriptor domainDesc(domainIndex);
     297             : 
     298          12 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
     299          12 :         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          12 :             2, 2, 2, 2;
     301             : 
     302          12 :         DataContainer<TestType> domain(domainDesc, vec);
     303             : 
     304          12 :         WHEN("3 Scaling operators are applied to it, in a ROW-Block fashion")
     305             :         {
     306          12 :             IndexVector_t rangeIndex(2);
     307           6 :             rangeIndex << rows, cols * numBlks;
     308          12 :             VolumeDescriptor rangeDesc(rangeIndex);
     309          12 :             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          12 :             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          12 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     321             : 
     322           6 :             blockOp.apply(domain, range);
     323             : 
     324           8 :             THEN("the for the first block, x was multiplied by 2.")
     325             :             {
     326          66 :                 for (int i = 0; i < rows * cols; i++)
     327          64 :                     REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1));
     328             :             }
     329           8 :             THEN("the for the second block, x was multiplied by 3.")
     330             :             {
     331          66 :                 for (int i = 0; i < rows * cols; i++)
     332          64 :                     REQUIRE_UNARY(checkApproxEq(range[i + rows * cols], vec[i] * scale2));
     333             :             }
     334           8 :             THEN("the for the third block, x was multiplied by 4.")
     335             :             {
     336          66 :                 for (int i = 0; i < rows * cols; i++)
     337          64 :                     REQUIRE_UNARY(checkApproxEq(range[i + rows * cols * 2], vec[i] * scale3));
     338             :             }
     339             :         }
     340             :     }
     341             : 
     342          10 :     GIVEN("a 2D volume with 3 blocks")
     343             :     {
     344           4 :         IndexVector_t blockIndex(2);
     345           2 :         blockIndex << rows, cols;
     346           4 :         VolumeDescriptor blockDesc(blockIndex);
     347           4 :         IdenticalBlocksDescriptor domainDesc(numBlks, blockDesc);
     348             : 
     349           4 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
     350           4 :         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           4 :             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           4 :         DataContainer<TestType> domain(domainDesc, vec);
     359             : 
     360           4 :         WHEN("3 Scaling operators are applied to it in a COL-Block fashion")
     361             :         {
     362           4 :             IndexVector_t rangeIndex(2);
     363           2 :             rangeIndex << rows, cols;
     364           4 :             VolumeDescriptor rangeDesc(rangeIndex);
     365           4 :             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           4 :             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           4 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     377             : 
     378           2 :             blockOp.apply(domain, range);
     379             : 
     380           4 :             THEN("then the range data, is a component wise addition of the 3 blocks each "
     381             :                  "scaled with the corresponding factor")
     382             :             {
     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             :                                                               + vec[i + size * 2] * scale3));
     387             :                 }
     388             :             }
     389             :         }
     390             :     }
     391           8 : }
     392             : 
     393          38 : TEST_CASE_TEMPLATE("BlockLinearOperator: applyAdjoint", TestType, float, double)
     394             : {
     395             :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     396           8 :     index_t rows = 4, cols = 8, numBlks = 3;
     397          10 :     GIVEN("a 2D volume with 3 blocks")
     398             :     {
     399           4 :         IndexVector_t rangeIndex(2);
     400           2 :         rangeIndex << rows, cols * numBlks;
     401           4 :         VolumeDescriptor rangeDesc(rangeIndex);
     402             : 
     403           2 :         const index_t n = rangeDesc.getNumberOfCoefficients();
     404           4 :         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           4 :         DataContainer<TestType> range(rangeDesc, rangeVec);
     410             : 
     411           4 :         WHEN("applying the adjoint of 3 Scaling operators ordered in a ROW-Block fashion")
     412             :         {
     413           4 :             IndexVector_t domainIndex(2);
     414           2 :             domainIndex << rows, cols;
     415           4 :             VolumeDescriptor domainDesc(domainIndex);
     416             : 
     417           2 :             TestType scale1 = 2.f;
     418           2 :             TestType scale2 = 3.f;
     419           2 :             TestType scale3 = 4.f;
     420             : 
     421           4 :             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           4 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     427             : 
     428           4 :             auto result = blockOp.applyAdjoint(range);
     429             : 
     430           4 :             THEN("then the result is a component wise addition of the 3 blocks each "
     431             :                  "scaled with the corresponding factor")
     432             :             {
     433          66 :                 for (int i = 0; i < rows * cols; i++)
     434          64 :                     REQUIRE_UNARY(checkApproxEq(result[i], 35));
     435             :             }
     436             :         }
     437             :     }
     438             : 
     439          14 :     GIVEN("a 2D volume")
     440             :     {
     441          12 :         IndexVector_t rangeIndex(2);
     442           6 :         rangeIndex << rows, cols;
     443          12 :         VolumeDescriptor rangeDesc(rangeIndex);
     444             : 
     445          12 :         Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(rangeDesc.getNumberOfCoefficients());
     446          12 :         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          12 :             2, 2, 2, 2;
     448             : 
     449          12 :         DataContainer<TestType> range(rangeDesc, vec);
     450             : 
     451          12 :         WHEN("applying the adjoint of 3 Scaling operators ordered in a COL-Block fashion")
     452             :         {
     453           6 :             TestType scale1 = 2.f;
     454           6 :             TestType scale2 = 3.f;
     455           6 :             TestType scale3 = 4.f;
     456             : 
     457          12 :             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          12 :             BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     463             : 
     464          12 :             auto result = blockOp.applyAdjoint(range);
     465             : 
     466           8 :             THEN("the for the first block, x was multiplied by 2.")
     467             :             {
     468          66 :                 for (int i = 0; i < rows * cols; i++)
     469          64 :                     REQUIRE_EQ(result[i], vec[i] * scale1);
     470             :             }
     471           8 :             THEN("the for the second block, x was multiplied by 3.")
     472             :             {
     473          66 :                 for (int i = 0; i < rows * cols; i++)
     474          64 :                     REQUIRE_EQ(result[i + rows * cols], vec[i] * scale2);
     475             :             }
     476           8 :             THEN("the for the third block, x was multiplied by 4.")
     477             :             {
     478          66 :                 for (int i = 0; i < rows * cols; i++)
     479          64 :                     REQUIRE_EQ(result[i + rows * cols * 2], vec[i] * scale3);
     480             :             }
     481             :         }
     482             :     }
     483           8 : }
     484             : 
     485          34 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing cloning", TestType, float, double)
     486             : {
     487             :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     488           4 :     index_t rows = 4, cols = 8;
     489           6 :     GIVEN("a ROW BlockLinearOperator")
     490             :     {
     491           4 :         IndexVector_t domainIndex(2);
     492           2 :         domainIndex << rows, cols;
     493           4 :         VolumeDescriptor domainDesc(domainIndex);
     494             : 
     495           2 :         TestType scale1 = 2.f;
     496           2 :         TestType scale2 = 3.f;
     497           2 :         TestType scale3 = 4.f;
     498             : 
     499           4 :         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           4 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     505             : 
     506           4 :         WHEN("cloning the operator")
     507             :         {
     508           4 :             auto bloClone = blockOp.clone();
     509             : 
     510           4 :             THEN("it's a real clone")
     511             :             {
     512           2 :                 REQUIRE_NE(bloClone.get(), &blockOp);
     513           2 :                 REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
     514           2 :                 REQUIRE_EQ(blockOp, *bloClone);
     515             :             }
     516             :         }
     517             :     }
     518             : 
     519           6 :     GIVEN("a COL BlockLinearOperator")
     520             :     {
     521           4 :         IndexVector_t rangeIndex(2);
     522           2 :         rangeIndex << rows, cols;
     523           4 :         VolumeDescriptor rangeDesc(rangeIndex);
     524             : 
     525           2 :         TestType scale1 = 2.f;
     526           2 :         TestType scale2 = 3.f;
     527           2 :         TestType scale3 = 4.f;
     528             : 
     529           4 :         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           4 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
     535             : 
     536           4 :         WHEN("cloning the operator")
     537             :         {
     538           4 :             auto bloClone = blockOp.clone();
     539             : 
     540           4 :             THEN("it's a real clone")
     541             :             {
     542           2 :                 REQUIRE_NE(bloClone.get(), &blockOp);
     543           2 :                 REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
     544           2 :                 REQUIRE_EQ(blockOp, *bloClone);
     545             :             }
     546             :         }
     547             :     }
     548           4 : }
     549             : 
     550          36 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing comparison", TestType, float, double)
     551             : {
     552             :     using BlockType = typename BlockLinearOperator<TestType>::BlockType;
     553           6 :     index_t rows = 4, cols = 8;
     554          12 :     GIVEN("a BlockLinearOperator")
     555             :     {
     556          12 :         IndexVector_t domainIndex(2);
     557           6 :         domainIndex << rows, cols;
     558          12 :         VolumeDescriptor domainDesc(domainIndex);
     559             : 
     560           6 :         TestType scale1 = 2.f;
     561           6 :         TestType scale2 = 3.f;
     562           6 :         TestType scale3 = 4.f;
     563             : 
     564          12 :         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          12 :         BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
     570             : 
     571           8 :         WHEN("comparing the operator to a leaf of itself")
     572             :         {
     573           4 :             auto blockOpLeaf = leaf(blockOp);
     574             : 
     575           4 :             THEN("they are not equal")
     576             :             {
     577           2 :                 REQUIRE_NE(blockOp, blockOpLeaf);
     578           2 :                 REQUIRE_NE(blockOpLeaf, blockOp);
     579             :             }
     580             :         }
     581             : 
     582           8 :         WHEN("comparing the operator to a BlockLinearOperator containing the same operators, but "
     583             :              "stacked differently")
     584             :         {
     585           4 :             BlockLinearOperator<TestType> blockOp2(ops, BlockType::COL);
     586             : 
     587           4 :             THEN("they are not equal")
     588             :             {
     589           2 :                 REQUIRE_NE(blockOp, blockOp2);
     590           2 :                 REQUIRE_NE(blockOp2, blockOp);
     591             :             }
     592             :         }
     593             : 
     594           8 :         WHEN("comparing the operator to a BlockLinearOperator containing different operators")
     595             :         {
     596           4 :             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           4 :             BlockLinearOperator<TestType> blockOp2(ops2, BlockType::ROW);
     601             : 
     602           4 :             THEN("they are not equal")
     603             :             {
     604           2 :                 REQUIRE_NE(blockOp, blockOp2);
     605           2 :                 REQUIRE_NE(blockOp2, blockOp);
     606             :             }
     607             :         }
     608             :     }
     609           6 : }
     610             : TEST_SUITE_END();

Generated by: LCOV version 1.15