LCOV - code coverage report
Current view: top level - elsa/functionals/tests - test_WeightedL2NormPow2.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 112 112 100.0 %
Date: 2022-08-25 03:05:39 Functions: 8 8 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             : TYPE_TO_STRING(complex<float>);
      24             : TYPE_TO_STRING(complex<double>);
      25             : 
      26             : TEST_SUITE_BEGIN("functionals");
      27             : 
      28             : TEST_CASE_TEMPLATE("WeightedL2NormPow2: Testing without residual", TestType, float, double,
      29             :                    complex<float>, complex<double>)
      30          20 : {
      31          20 :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
      32          20 :     using Scalar = GetFloatingPointType_t<TestType>;
      33             : 
      34          20 :     GIVEN("just data (no residual)")
      35          20 :     {
      36          20 :         IndexVector_t numCoeff(2);
      37          20 :         numCoeff << 7, 17;
      38          20 :         VolumeDescriptor dd(numCoeff);
      39             : 
      40          20 :         Vector scalingData(dd.getNumberOfCoefficients());
      41          20 :         scalingData.setRandom();
      42          20 :         DataContainer<TestType> scaleFactors(dd, scalingData);
      43             : 
      44          20 :         Scaling<TestType> scalingOp(dd, scaleFactors);
      45             : 
      46          20 :         WHEN("instantiating")
      47          20 :         {
      48          20 :             WeightedL2NormPow2<TestType> func(scalingOp);
      49             : 
      50          20 :             THEN("the functional is as expected")
      51          20 :             {
      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           4 :             }
      60             : 
      61          20 :             THEN("a clone behaves as expected")
      62          20 :             {
      63           4 :                 auto wl2Clone = func.clone();
      64             : 
      65           4 :                 REQUIRE_NE(wl2Clone.get(), &func);
      66           4 :                 REQUIRE_EQ(*wl2Clone, func);
      67           4 :             }
      68             : 
      69          20 :             Vector dataVec(dd.getNumberOfCoefficients());
      70          20 :             dataVec.setRandom();
      71          20 :             DataContainer<TestType> x(dd, dataVec);
      72             : 
      73          20 :             Vector Wx = scalingData.array() * dataVec.array();
      74             : 
      75          20 :             THEN("the evaluate works as expected")
      76          20 :             {
      77             :                 // TODO: with complex numbers this for some reason doesn't work, the result is
      78             :                 // always the negation of the expected
      79           4 :                 if constexpr (std::is_floating_point_v<TestType>)
      80           4 :                     REQUIRE_UNARY(checkApproxEq(func.evaluate(x),
      81           4 :                                                 static_cast<Scalar>(0.5) * Wx.dot(dataVec)));
      82           4 :             }
      83             : 
      84          20 :             THEN("the gradient works as expected")
      85          20 :             {
      86           4 :                 DataContainer<TestType> dcWx(dd, Wx);
      87           4 :                 REQUIRE_UNARY(isApprox(func.getGradient(x), dcWx));
      88           4 :             }
      89             : 
      90          20 :             THEN("the Hessian works as expected")
      91          20 :             {
      92           4 :                 REQUIRE_EQ(func.getHessian(x), leaf(scalingOp));
      93           4 :             }
      94          20 :         }
      95          20 :     }
      96          20 : }
      97             : 
      98             : TEST_CASE_TEMPLATE("WeightedL2NormPow2: Testing with residual", TestType, float, double,
      99             :                    complex<float>, complex<double>)
     100          20 : {
     101          20 :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
     102          20 :     using Scalar = GetFloatingPointType_t<TestType>;
     103             : 
     104          20 :     GIVEN("a residual with data")
     105          20 :     {
     106             :         // linear residual
     107          20 :         IndexVector_t numCoeff(2);
     108          20 :         numCoeff << 47, 11;
     109          20 :         VolumeDescriptor dd(numCoeff);
     110             : 
     111          20 :         Vector randomData(dd.getNumberOfCoefficients());
     112          20 :         randomData.setRandom();
     113          20 :         DataContainer<TestType> b(dd, randomData);
     114             : 
     115          20 :         Identity<TestType> A(dd);
     116             : 
     117          20 :         LinearResidual linRes(A, b);
     118             : 
     119             :         // scaling operator
     120          20 :         Vector scalingData(dd.getNumberOfCoefficients());
     121          20 :         scalingData.setRandom();
     122          20 :         DataContainer<TestType> scaleFactors(dd, scalingData);
     123             : 
     124          20 :         Scaling scalingOp(dd, scaleFactors);
     125             : 
     126          20 :         WHEN("instantiating")
     127          20 :         {
     128          20 :             WeightedL2NormPow2 func(linRes, scalingOp);
     129             : 
     130          20 :             THEN("the functional is as expected")
     131          20 :             {
     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           4 :             }
     139             : 
     140          20 :             THEN("a clone behaves as expected")
     141          20 :             {
     142           4 :                 auto wl2Clone = func.clone();
     143             : 
     144           4 :                 REQUIRE_NE(wl2Clone.get(), &func);
     145           4 :                 REQUIRE_EQ(*wl2Clone, func);
     146           4 :             }
     147             : 
     148          20 :             Vector dataVec(dd.getNumberOfCoefficients());
     149          20 :             dataVec.setRandom();
     150          20 :             DataContainer<TestType> x(dd, dataVec);
     151             : 
     152          20 :             Vector WRx = scalingData.array() * (dataVec - randomData).array();
     153             : 
     154          20 :             THEN("the evaluate works was expected")
     155          20 :             {
     156             :                 // TODO: with complex numbers this for some reason doesn't work, the result is
     157             :                 // always the negation of the expected
     158           4 :                 if constexpr (std::is_floating_point_v<TestType>)
     159           4 :                     REQUIRE_UNARY(
     160           4 :                         checkApproxEq(func.evaluate(x),
     161           4 :                                       static_cast<Scalar>(0.5) * WRx.dot(dataVec - randomData)));
     162           4 :             }
     163             : 
     164          20 :             THEN("the gradient works was expected")
     165          20 :             {
     166           4 :                 DataContainer<TestType> dcWRx(dd, WRx);
     167           4 :                 REQUIRE_UNARY(isApprox(func.getGradient(x), dcWRx));
     168           4 :             }
     169             : 
     170          20 :             THEN("the Hessian works was expected")
     171          20 :             {
     172           4 :                 auto hessian = func.getHessian(x);
     173           4 :                 Vector Wx = scalingData.array() * dataVec.array();
     174           4 :                 DataContainer<TestType> dcWx(dd, Wx);
     175           4 :                 REQUIRE_UNARY(isApprox(hessian.apply(x), dcWx));
     176           4 :             }
     177          20 :         }
     178          20 :     }
     179          20 : }
     180             : 
     181             : TEST_SUITE_END();

Generated by: LCOV version 1.14