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

          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             :     MockOperator(const DataDescriptor& domain, const DataDescriptor& range)
      26             :         : LinearOperator<data_t>(domain, range)
      27         596 :     {
      28         596 :     }
      29             : 
      30             : protected:
      31             :     void applyImpl([[maybe_unused]] const DataContainer<data_t>& x,
      32             :                    DataContainer<data_t>& Ax) const override
      33          56 :     {
      34          56 :         Ax = 1;
      35          56 :     }
      36             : 
      37             :     void applyAdjointImpl([[maybe_unused]] const DataContainer<data_t>& y,
      38             :                           DataContainer<data_t>& Aty) const override
      39          40 :     {
      40          40 :         Aty = 3;
      41          40 :     }
      42             : 
      43             : protected:
      44             :     MockOperator<data_t>* cloneImpl() const override
      45         412 :     {
      46         412 :         return new MockOperator<data_t>(this->getDomainDescriptor(), this->getRangeDescriptor());
      47         412 :     }
      48             : };
      49             : 
      50             : TYPE_TO_STRING(complex<float>);
      51             : TYPE_TO_STRING(complex<double>);
      52             : 
      53             : TEST_SUITE_BEGIN("functionals");
      54             : 
      55             : TEST_CASE_TEMPLATE("LinearResidual: Testing trivial linear residual", TestType, float, double,
      56             :                    complex<float>, complex<double>)
      57          12 : {
      58          12 :     GIVEN("a descriptor")
      59          12 :     {
      60          12 :         IndexVector_t numCoeff(3);
      61          12 :         numCoeff << 11, 33, 55;
      62          12 :         VolumeDescriptor dd(numCoeff);
      63             : 
      64          12 :         WHEN("instantiating")
      65          12 :         {
      66          12 :             LinearResidual<TestType> linRes(dd);
      67             : 
      68          12 :             THEN("the residual is as expected")
      69          12 :             {
      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           4 :                 REQUIRE_THROWS_AS(linRes.getOperator(), Error);
      77           4 :                 REQUIRE_THROWS_AS(linRes.getDataVector(), Error);
      78           4 :             }
      79             : 
      80          12 :             THEN("a clone behaves as expected")
      81          12 :             {
      82           4 :                 auto linResClone = linRes.clone();
      83             : 
      84           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
      85           4 :                 REQUIRE_EQ(*linResClone, linRes);
      86           4 :             }
      87             : 
      88          12 :             THEN("the Jacobian and evaluate work as expected")
      89          12 :             {
      90           4 :                 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           4 :             }
      97          12 :         }
      98          12 :     }
      99          12 : }
     100             : 
     101             : TEST_CASE_TEMPLATE("LinearResidual: Testing with just an data vector", TestType, float, double,
     102             :                    complex<float>, complex<double>)
     103          12 : {
     104          12 :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     105             : 
     106          12 :     GIVEN("a descriptor and data")
     107          12 :     {
     108          12 :         IndexVector_t numCoeff(2);
     109          12 :         numCoeff << 18, 36;
     110          12 :         VolumeDescriptor dd(numCoeff);
     111             : 
     112          12 :         Vector randomData(dd.getNumberOfCoefficients());
     113          12 :         randomData.setRandom();
     114          12 :         DataContainer<TestType> dc(dd, randomData);
     115             : 
     116          12 :         WHEN("instantiating")
     117          12 :         {
     118          12 :             LinearResidual<TestType> linRes(dc);
     119             : 
     120          12 :             THEN("the residual is as expected")
     121          12 :             {
     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           4 :                 REQUIRE_THROWS_AS(linRes.getOperator(), Error);
     130           4 :             }
     131             : 
     132          12 :             THEN("a clone behaves as expected")
     133          12 :             {
     134           4 :                 auto linResClone = linRes.clone();
     135             : 
     136           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     137           4 :                 REQUIRE_EQ(*linResClone, linRes);
     138           4 :             }
     139             : 
     140          12 :             THEN("the Jacobian and evaluate work as expected")
     141          12 :             {
     142           4 :                 Identity<TestType> idOp(dd);
     143           4 :                 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           4 :             }
     151          12 :         }
     152          12 :     }
     153          12 : }
     154             : 
     155             : TEST_CASE_TEMPLATE("LinearResidual: Testing with just an operator", TestType, float, double,
     156             :                    complex<float>, complex<double>)
     157          12 : {
     158          12 :     GIVEN("descriptors and an operator")
     159          12 :     {
     160          12 :         IndexVector_t numCoeff(3);
     161          12 :         numCoeff << 11, 33, 55;
     162          12 :         VolumeDescriptor ddDomain(numCoeff);
     163             : 
     164          12 :         IndexVector_t numCoeff2(2);
     165          12 :         numCoeff2 << 18, 36;
     166          12 :         VolumeDescriptor ddRange(numCoeff2);
     167             : 
     168          12 :         MockOperator<TestType> mockOp(ddDomain, ddRange);
     169             : 
     170          12 :         WHEN("instantiating")
     171          12 :         {
     172          12 :             LinearResidual<TestType> linRes(mockOp);
     173             : 
     174          12 :             THEN("the residual is as expected")
     175          12 :             {
     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           4 :                 REQUIRE_THROWS_AS(linRes.getDataVector(), Error);
     184           4 :             }
     185             : 
     186          12 :             THEN("a clone behaves as expected")
     187          12 :             {
     188           4 :                 auto linResClone = linRes.clone();
     189             : 
     190           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     191           4 :                 REQUIRE_EQ(*linResClone, linRes);
     192           4 :             }
     193             : 
     194          12 :             THEN("the Jacobian and evaluate work as expected")
     195          12 :             {
     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           4 :             }
     202          12 :         }
     203          12 :     }
     204          12 : }
     205             : 
     206             : TEST_CASE_TEMPLATE("LinearResidual: Testing with operator and data", TestType, float, double,
     207             :                    complex<float>, complex<double>)
     208          12 : {
     209          12 :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     210             : 
     211          12 :     GIVEN("an operator and data")
     212          12 :     {
     213          12 :         IndexVector_t numCoeff(3);
     214          12 :         numCoeff << 11, 33, 55;
     215          12 :         VolumeDescriptor ddDomain(numCoeff);
     216          12 :         IndexVector_t numCoeff2(2);
     217          12 :         numCoeff2 << 18, 36;
     218          12 :         VolumeDescriptor ddRange(numCoeff2);
     219             : 
     220          12 :         MockOperator<TestType> mockOp(ddDomain, ddRange);
     221             : 
     222          12 :         Vector randomData(ddRange.getNumberOfCoefficients());
     223          12 :         randomData.setRandom();
     224          12 :         DataContainer<TestType> dc(ddRange, randomData);
     225             : 
     226          12 :         WHEN("instantiating")
     227          12 :         {
     228          12 :             LinearResidual<TestType> linRes(mockOp, dc);
     229             : 
     230          12 :             THEN("the residual is as expected")
     231          12 :             {
     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           4 :             }
     241             : 
     242          12 :             THEN("a clone behaves as expected")
     243          12 :             {
     244           4 :                 auto linResClone = linRes.clone();
     245             : 
     246           4 :                 REQUIRE_NE(linResClone.get(), &linRes);
     247           4 :                 REQUIRE_EQ(*linResClone, linRes);
     248           4 :             }
     249             : 
     250          12 :             THEN("the Jacobian and evaluate work as expected")
     251          12 :             {
     252           4 :                 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           4 :             }
     260          12 :         }
     261          12 :     }
     262          12 : }
     263             : 
     264             : TEST_SUITE_END();

Generated by: LCOV version 1.14