LCOV - code coverage report
Current view: top level - functionals/tests - test_LinearResidual.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 124 127 97.6 %
Date: 2022-02-28 03:37:41 Functions: 50 54 92.6 %

          Line data    Source code
       1             : /**
       2             :  * @file test_LinearResidual.cpp
       3             :  *
       4             :  * @brief Tests for LinearResidual class
       5             :  *
       6             :  * @author Matthias Wieczorek - main code
       7             :  * @author Tobias Lasser - rewrite
       8             :  */
       9             : 
      10             : #include <doctest/doctest.h>
      11             : 
      12             : #include "testHelpers.h"
      13             : #include "LinearResidual.h"
      14             : #include "Identity.h"
      15             : #include "VolumeDescriptor.h"
      16             : 
      17             : using namespace elsa;
      18             : using namespace doctest;
      19             : 
      20             : // mock operator, which outputs 1 for apply and 3 for applyAdjoint
      21             : template <typename data_t = real_t>
      22             : class MockOperator : public LinearOperator<data_t>
      23             : {
      24             : public:
      25          72 :     MockOperator(const DataDescriptor& domain, const DataDescriptor& range)
      26          72 :         : LinearOperator<data_t>(domain, range)
      27             :     {
      28          72 :     }
      29             : 
      30             : protected:
      31          16 :     void applyImpl([[maybe_unused]] const DataContainer<data_t>& x,
      32             :                    DataContainer<data_t>& Ax) const override
      33             :     {
      34          16 :         Ax = 1;
      35          16 :     }
      36             : 
      37           0 :     void applyAdjointImpl([[maybe_unused]] const DataContainer<data_t>& y,
      38             :                           DataContainer<data_t>& Aty) const override
      39             :     {
      40           0 :         Aty = 3;
      41           0 :     }
      42             : 
      43             : protected:
      44          48 :     MockOperator<data_t>* cloneImpl() const override
      45             :     {
      46          48 :         return new MockOperator<data_t>(this->getDomainDescriptor(), this->getRangeDescriptor());
      47             :     }
      48             : };
      49             : 
      50          64 : TYPE_TO_STRING(complex<float>);
      51          64 : TYPE_TO_STRING(complex<double>);
      52             : 
      53             : TEST_SUITE_BEGIN("functionals");
      54             : 
      55          92 : TEST_CASE_TEMPLATE("LinearResidual: Testing trivial linear residual", TestType, float, double,
      56             :                    complex<float>, complex<double>)
      57             : {
      58          24 :     GIVEN("a descriptor")
      59             :     {
      60          24 :         IndexVector_t numCoeff(3);
      61          12 :         numCoeff << 11, 33, 55;
      62          24 :         VolumeDescriptor dd(numCoeff);
      63             : 
      64          24 :         WHEN("instantiating")
      65             :         {
      66          24 :             LinearResidual<TestType> linRes(dd);
      67             : 
      68          16 :             THEN("the residual is as expected")
      69             :             {
      70           4 :                 REQUIRE_EQ(linRes.getDomainDescriptor(), dd);
      71           4 :                 REQUIRE_EQ(linRes.getRangeDescriptor(), dd);
      72             : 
      73           4 :                 REQUIRE_UNARY_FALSE(linRes.hasOperator());
      74           4 :                 REQUIRE_UNARY_FALSE(linRes.hasDataVector());
      75             : 
      76           8 :                 REQUIRE_THROWS_AS(linRes.getOperator(), Error);
      77           8 :                 REQUIRE_THROWS_AS(linRes.getDataVector(), Error);
      78             :             }
      79             : 
      80          16 :             THEN("a clone behaves as expected")
      81             :             {
      82           8 :                 auto linResClone = linRes.clone();
      83             : 
      84           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
      85           4 :                 REQUIRE_EQ(*linResClone, linRes);
      86             :             }
      87             : 
      88          16 :             THEN("the Jacobian and evaluate work as expected")
      89             :             {
      90           8 :                 Identity<TestType> idOp(dd);
      91           4 :                 DataContainer<TestType> dcX(dd);
      92           4 :                 dcX = 1;
      93             : 
      94           4 :                 REQUIRE_EQ(linRes.getJacobian(dcX), leaf(idOp));
      95           4 :                 REQUIRE_UNARY(isApprox(linRes.evaluate(dcX), dcX));
      96             :             }
      97             :         }
      98             :     }
      99          12 : }
     100             : 
     101          92 : TEST_CASE_TEMPLATE("LinearResidual: Testing with just an data vector", TestType, float, double,
     102             :                    complex<float>, complex<double>)
     103             : {
     104             :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     105             : 
     106          24 :     GIVEN("a descriptor and data")
     107             :     {
     108          24 :         IndexVector_t numCoeff(2);
     109          12 :         numCoeff << 18, 36;
     110          24 :         VolumeDescriptor dd(numCoeff);
     111             : 
     112          24 :         Vector randomData(dd.getNumberOfCoefficients());
     113          12 :         randomData.setRandom();
     114          24 :         DataContainer<TestType> dc(dd, randomData);
     115             : 
     116          24 :         WHEN("instantiating")
     117             :         {
     118          24 :             LinearResidual<TestType> linRes(dc);
     119             : 
     120          16 :             THEN("the residual is as expected")
     121             :             {
     122           4 :                 REQUIRE_EQ(linRes.getDomainDescriptor(), dd);
     123           4 :                 REQUIRE_EQ(linRes.getRangeDescriptor(), dd);
     124             : 
     125           4 :                 REQUIRE_UNARY_FALSE(linRes.hasOperator());
     126           4 :                 REQUIRE_UNARY(linRes.hasDataVector());
     127             : 
     128           4 :                 REQUIRE_UNARY(isApprox(linRes.getDataVector(), dc));
     129           8 :                 REQUIRE_THROWS_AS(linRes.getOperator(), Error);
     130             :             }
     131             : 
     132          16 :             THEN("a clone behaves as expected")
     133             :             {
     134           8 :                 auto linResClone = linRes.clone();
     135             : 
     136           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     137           4 :                 REQUIRE_EQ(*linResClone, linRes);
     138             :             }
     139             : 
     140          16 :             THEN("the Jacobian and evaluate work as expected")
     141             :             {
     142           8 :                 Identity<TestType> idOp(dd);
     143           8 :                 DataContainer<TestType> dcX(dd);
     144           4 :                 dcX = 1;
     145             : 
     146           4 :                 REQUIRE_EQ(linRes.getJacobian(dcX), leaf(idOp));
     147             : 
     148           4 :                 DataContainer<TestType> tmp = dcX - dc;
     149           4 :                 REQUIRE_UNARY(isApprox(linRes.evaluate(dcX), tmp));
     150             :             }
     151             :         }
     152             :     }
     153          12 : }
     154             : 
     155          92 : TEST_CASE_TEMPLATE("LinearResidual: Testing with just an operator", TestType, float, double,
     156             :                    complex<float>, complex<double>)
     157             : {
     158          24 :     GIVEN("descriptors and an operator")
     159             :     {
     160          24 :         IndexVector_t numCoeff(3);
     161          12 :         numCoeff << 11, 33, 55;
     162          24 :         VolumeDescriptor ddDomain(numCoeff);
     163             : 
     164          24 :         IndexVector_t numCoeff2(2);
     165          12 :         numCoeff2 << 18, 36;
     166          24 :         VolumeDescriptor ddRange(numCoeff2);
     167             : 
     168          24 :         MockOperator<TestType> mockOp(ddDomain, ddRange);
     169             : 
     170          24 :         WHEN("instantiating")
     171             :         {
     172          24 :             LinearResidual<TestType> linRes(mockOp);
     173             : 
     174          16 :             THEN("the residual is as expected")
     175             :             {
     176           4 :                 REQUIRE_EQ(linRes.getDomainDescriptor(), ddDomain);
     177           4 :                 REQUIRE_EQ(linRes.getRangeDescriptor(), ddRange);
     178             : 
     179           4 :                 REQUIRE_UNARY(linRes.hasOperator());
     180           4 :                 REQUIRE_UNARY_FALSE(linRes.hasDataVector());
     181             : 
     182           4 :                 REQUIRE_EQ(linRes.getOperator(), mockOp);
     183           8 :                 REQUIRE_THROWS_AS(linRes.getDataVector(), Error);
     184             :             }
     185             : 
     186          16 :             THEN("a clone behaves as expected")
     187             :             {
     188           8 :                 auto linResClone = linRes.clone();
     189             : 
     190           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     191           4 :                 REQUIRE_EQ(*linResClone, linRes);
     192             :             }
     193             : 
     194          16 :             THEN("the Jacobian and evaluate work as expected")
     195             :             {
     196           4 :                 DataContainer<TestType> dcX(ddDomain);
     197           4 :                 dcX = 1;
     198             : 
     199           4 :                 REQUIRE_EQ(linRes.getJacobian(dcX), leaf(mockOp));
     200           4 :                 REQUIRE_UNARY(isApprox(linRes.evaluate(dcX), mockOp.apply(dcX)));
     201             :             }
     202             :         }
     203             :     }
     204          12 : }
     205             : 
     206          92 : TEST_CASE_TEMPLATE("LinearResidual: Testing with operator and data", TestType, float, double,
     207             :                    complex<float>, complex<double>)
     208             : {
     209             :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     210             : 
     211          24 :     GIVEN("an operator and data")
     212             :     {
     213          24 :         IndexVector_t numCoeff(3);
     214          12 :         numCoeff << 11, 33, 55;
     215          24 :         VolumeDescriptor ddDomain(numCoeff);
     216          24 :         IndexVector_t numCoeff2(2);
     217          12 :         numCoeff2 << 18, 36;
     218          24 :         VolumeDescriptor ddRange(numCoeff2);
     219             : 
     220          24 :         MockOperator<TestType> mockOp(ddDomain, ddRange);
     221             : 
     222          24 :         Vector randomData(ddRange.getNumberOfCoefficients());
     223          12 :         randomData.setRandom();
     224          24 :         DataContainer<TestType> dc(ddRange, randomData);
     225             : 
     226          24 :         WHEN("instantiating")
     227             :         {
     228          24 :             LinearResidual<TestType> linRes(mockOp, dc);
     229             : 
     230          16 :             THEN("the residual is as expected")
     231             :             {
     232           4 :                 REQUIRE_EQ(linRes.getDomainDescriptor(), ddDomain);
     233           4 :                 REQUIRE_EQ(linRes.getRangeDescriptor(), ddRange);
     234             : 
     235           4 :                 REQUIRE_UNARY(linRes.hasOperator());
     236           4 :                 REQUIRE_UNARY(linRes.hasDataVector());
     237             : 
     238           4 :                 REQUIRE_EQ(linRes.getOperator(), mockOp);
     239           4 :                 REQUIRE_UNARY(isApprox(linRes.getDataVector(), dc));
     240             :             }
     241             : 
     242          16 :             THEN("a clone behaves as expected")
     243             :             {
     244           8 :                 auto linResClone = linRes.clone();
     245             : 
     246           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     247           4 :                 REQUIRE_EQ(*linResClone, linRes);
     248             :             }
     249             : 
     250          16 :             THEN("the Jacobian and evaluate work as expected")
     251             :             {
     252           8 :                 DataContainer<TestType> dcX(ddDomain);
     253           4 :                 dcX = 1;
     254             : 
     255           4 :                 REQUIRE_EQ(linRes.getJacobian(dcX), leaf(mockOp));
     256             : 
     257           4 :                 DataContainer<TestType> tmp = mockOp.apply(dcX) - dc;
     258           4 :                 REQUIRE_UNARY(isApprox(linRes.evaluate(dcX), tmp));
     259             :             }
     260             :         }
     261             :     }
     262          12 : }
     263             : 
     264             : TEST_SUITE_END();

Generated by: LCOV version 1.15