LCOV - code coverage report
Current view: top level - functionals/tests - test_WeightedL2NormPow2.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 77 77 100.0 %
Date: 2022-02-28 03:37:41 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_WeightedL2NormPow2.cpp
       3             :  *
       4             :  * @brief Tests for the WeightedL2NormPow2 class
       5             :  *
       6             :  * @author Matthias Wieczorek - initial code
       7             :  * @author David Frank - rewrite
       8             :  * @author Tobias Lasser - modernization
       9             :  */
      10             : 
      11             : #include <doctest/doctest.h>
      12             : 
      13             : #include "testHelpers.h"
      14             : #include "WeightedL2NormPow2.h"
      15             : #include "LinearResidual.h"
      16             : #include "Identity.h"
      17             : #include "VolumeDescriptor.h"
      18             : #include "TypeCasts.hpp"
      19             : 
      20             : using namespace elsa;
      21             : using namespace doctest;
      22             : 
      23          16 : TYPE_TO_STRING(complex<float>);
      24          16 : TYPE_TO_STRING(complex<double>);
      25             : 
      26             : TEST_SUITE_BEGIN("functionals");
      27             : 
      28          60 : TEST_CASE_TEMPLATE("WeightedL2NormPow2: Testing without residual", TestType, float, double,
      29             :                    complex<float>, complex<double>)
      30             : {
      31             :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
      32             :     using Scalar = GetFloatingPointType_t<TestType>;
      33             : 
      34          40 :     GIVEN("just data (no residual)")
      35             :     {
      36          40 :         IndexVector_t numCoeff(2);
      37          20 :         numCoeff << 7, 17;
      38          40 :         VolumeDescriptor dd(numCoeff);
      39             : 
      40          40 :         Vector scalingData(dd.getNumberOfCoefficients());
      41          20 :         scalingData.setRandom();
      42          40 :         DataContainer<TestType> scaleFactors(dd, scalingData);
      43             : 
      44          40 :         Scaling<TestType> scalingOp(dd, scaleFactors);
      45             : 
      46          40 :         WHEN("instantiating")
      47             :         {
      48          40 :             WeightedL2NormPow2<TestType> func(scalingOp);
      49             : 
      50          24 :             THEN("the functional is as expected")
      51             :             {
      52           4 :                 REQUIRE_EQ(func.getDomainDescriptor(), dd);
      53           4 :                 REQUIRE_EQ(func.getWeightingOperator(), scalingOp);
      54             : 
      55           4 :                 auto* linRes = downcast_safe<LinearResidual<TestType>>(&func.getResidual());
      56           4 :                 REQUIRE_UNARY(linRes);
      57           4 :                 REQUIRE_UNARY_FALSE(linRes->hasOperator());
      58           4 :                 REQUIRE_UNARY_FALSE(linRes->hasDataVector());
      59             :             }
      60             : 
      61          24 :             THEN("a clone behaves as expected")
      62             :             {
      63           8 :                 auto wl2Clone = func.clone();
      64             : 
      65           4 :                 REQUIRE_NE(wl2Clone.get(), &func);
      66           4 :                 REQUIRE_EQ(*wl2Clone, func);
      67             :             }
      68             : 
      69          40 :             Vector dataVec(dd.getNumberOfCoefficients());
      70          20 :             dataVec.setRandom();
      71          40 :             DataContainer<TestType> x(dd, dataVec);
      72             : 
      73          40 :             Vector Wx = scalingData.array() * dataVec.array();
      74             : 
      75          22 :             THEN("the evaluate works as expected")
      76             :             {
      77             :                 // TODO: with complex numbers this for some reason doesn't work, the result is
      78             :                 // always the negation of the expected
      79             :                 if constexpr (std::is_floating_point_v<TestType>)
      80           2 :                     REQUIRE_UNARY(checkApproxEq(func.evaluate(x),
      81             :                                                 static_cast<Scalar>(0.5) * Wx.dot(dataVec)));
      82             :             }
      83             : 
      84          24 :             THEN("the gradient works as expected")
      85             :             {
      86           4 :                 DataContainer<TestType> dcWx(dd, Wx);
      87           4 :                 REQUIRE_UNARY(isApprox(func.getGradient(x), dcWx));
      88             :             }
      89             : 
      90          24 :             THEN("the Hessian works as expected")
      91             :             {
      92           4 :                 REQUIRE_EQ(func.getHessian(x), leaf(scalingOp));
      93             :             }
      94             :         }
      95             :     }
      96          20 : }
      97             : 
      98          60 : TEST_CASE_TEMPLATE("WeightedL2NormPow2: Testing with residual", TestType, float, double,
      99             :                    complex<float>, complex<double>)
     100             : {
     101             :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     102             :     using Scalar = GetFloatingPointType_t<TestType>;
     103             : 
     104          40 :     GIVEN("a residual with data")
     105             :     {
     106             :         // linear residual
     107          40 :         IndexVector_t numCoeff(2);
     108          20 :         numCoeff << 47, 11;
     109          40 :         VolumeDescriptor dd(numCoeff);
     110             : 
     111          40 :         Vector randomData(dd.getNumberOfCoefficients());
     112          20 :         randomData.setRandom();
     113          40 :         DataContainer<TestType> b(dd, randomData);
     114             : 
     115          40 :         Identity<TestType> A(dd);
     116             : 
     117          40 :         LinearResidual linRes(A, b);
     118             : 
     119             :         // scaling operator
     120          40 :         Vector scalingData(dd.getNumberOfCoefficients());
     121          20 :         scalingData.setRandom();
     122          40 :         DataContainer<TestType> scaleFactors(dd, scalingData);
     123             : 
     124          40 :         Scaling scalingOp(dd, scaleFactors);
     125             : 
     126          40 :         WHEN("instantiating")
     127             :         {
     128          40 :             WeightedL2NormPow2 func(linRes, scalingOp);
     129             : 
     130          24 :             THEN("the functional is as expected")
     131             :             {
     132           4 :                 REQUIRE_EQ(func.getDomainDescriptor(), dd);
     133           4 :                 REQUIRE_EQ(func.getWeightingOperator(), scalingOp);
     134             : 
     135           4 :                 auto* lRes = downcast_safe<LinearResidual<TestType>>(&func.getResidual());
     136           4 :                 REQUIRE_UNARY(lRes);
     137           4 :                 REQUIRE_EQ(*lRes, linRes);
     138             :             }
     139             : 
     140          24 :             THEN("a clone behaves as expected")
     141             :             {
     142           8 :                 auto wl2Clone = func.clone();
     143             : 
     144           4 :                 REQUIRE_NE(wl2Clone.get(), &func);
     145           4 :                 REQUIRE_EQ(*wl2Clone, func);
     146             :             }
     147             : 
     148          40 :             Vector dataVec(dd.getNumberOfCoefficients());
     149          20 :             dataVec.setRandom();
     150          40 :             DataContainer<TestType> x(dd, dataVec);
     151             : 
     152          40 :             Vector WRx = scalingData.array() * (dataVec - randomData).array();
     153             : 
     154          22 :             THEN("the evaluate works was expected")
     155             :             {
     156             :                 // TODO: with complex numbers this for some reason doesn't work, the result is
     157             :                 // always the negation of the expected
     158             :                 if constexpr (std::is_floating_point_v<TestType>)
     159           2 :                     REQUIRE_UNARY(
     160             :                         checkApproxEq(func.evaluate(x),
     161             :                                       static_cast<Scalar>(0.5) * WRx.dot(dataVec - randomData)));
     162             :             }
     163             : 
     164          24 :             THEN("the gradient works was expected")
     165             :             {
     166           4 :                 DataContainer<TestType> dcWRx(dd, WRx);
     167           4 :                 REQUIRE_UNARY(isApprox(func.getGradient(x), dcWRx));
     168             :             }
     169             : 
     170          24 :             THEN("the Hessian works was expected")
     171             :             {
     172           8 :                 auto hessian = func.getHessian(x);
     173           8 :                 Vector Wx = scalingData.array() * dataVec.array();
     174           4 :                 DataContainer<TestType> dcWx(dd, Wx);
     175           4 :                 REQUIRE_UNARY(isApprox(hessian.apply(x), dcWx));
     176             :             }
     177             :         }
     178             :     }
     179          20 : }
     180             : 
     181             : TEST_SUITE_END();

Generated by: LCOV version 1.15