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

          Line data    Source code
       1             : /**
       2             :  * @file test_WeightedL1Norm.cpp
       3             :  *
       4             :  * @brief Tests for the WeightedL1Norm class
       5             :  *
       6             :  * @author Andi Braimllari
       7             :  */
       8             : 
       9             : #include "WeightedL1Norm.h"
      10             : #include "LinearResidual.h"
      11             : #include "Identity.h"
      12             : #include "VolumeDescriptor.h"
      13             : #include "testHelpers.h"
      14             : #include "TypeCasts.hpp"
      15             : 
      16             : #include <doctest/doctest.h>
      17             : 
      18             : using namespace elsa;
      19             : using namespace doctest;
      20             : 
      21             : TEST_SUITE_BEGIN("functionals");
      22             : 
      23             : TEST_CASE_TEMPLATE("WeightedL1Norm: Testing the weighted, l1 norm functional", TestType, float,
      24             :                    double)
      25          18 : {
      26          18 :     using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>;
      27             : 
      28          18 :     GIVEN("a linear residual and weights with a non-positive element")
      29          18 :     {
      30           2 :         IndexVector_t numCoeff(2);
      31           2 :         numCoeff << 25, 27;
      32           2 :         VolumeDescriptor dd(numCoeff);
      33             : 
      34           2 :         Vector randomData(dd.getNumberOfCoefficients());
      35           2 :         randomData.setRandom();
      36           2 :         DataContainer<TestType> b(dd, randomData);
      37             : 
      38           2 :         Identity<TestType> A(dd);
      39             : 
      40           2 :         LinearResidual<TestType> linRes(A, b);
      41             : 
      42             :         // scaling operator
      43           2 :         DataContainer<TestType> scaleFactors(dd);
      44           2 :         scaleFactors = 1;
      45           2 :         scaleFactors[3] = -8;
      46             : 
      47           2 :         WHEN("instantiating an WeightedL1Norm object")
      48           2 :         {
      49           2 :             THEN("an InvalidArgumentError is thrown")
      50           2 :             {
      51           2 :                 REQUIRE_THROWS_AS(WeightedL1Norm<TestType>{scaleFactors}, InvalidArgumentError);
      52           2 :                 REQUIRE_THROWS_AS(WeightedL1Norm<TestType>(linRes, scaleFactors),
      53           2 :                                   InvalidArgumentError);
      54           2 :             }
      55           2 :         }
      56           2 :     }
      57             : 
      58          18 :     GIVEN("weights of value 1 and no residual")
      59          18 :     {
      60           8 :         IndexVector_t numCoeff(2);
      61           8 :         numCoeff << 7, 17;
      62           8 :         VolumeDescriptor dd(numCoeff);
      63             : 
      64           8 :         DataContainer<TestType> scaleFactors(dd);
      65           8 :         scaleFactors = 1;
      66             : 
      67           8 :         WHEN("instantiating an WeightedL1Norm object")
      68           8 :         {
      69           8 :             WeightedL1Norm<TestType> func(scaleFactors);
      70             : 
      71           8 :             THEN("the functional is as expected")
      72           8 :             {
      73           2 :                 REQUIRE(func.getDomainDescriptor() == dd);
      74           2 :                 REQUIRE(func.getWeightingOperator() == scaleFactors);
      75             : 
      76           2 :                 const auto* linRes =
      77           2 :                     dynamic_cast<const LinearResidual<TestType>*>(&func.getResidual());
      78           2 :                 REQUIRE(linRes);
      79           2 :                 REQUIRE(linRes->hasOperator() == false);
      80           2 :                 REQUIRE(linRes->hasDataVector() == false);
      81           2 :             }
      82             : 
      83           8 :             THEN("a clone behaves as expected")
      84           8 :             {
      85           2 :                 auto wl1Clone = func.clone();
      86             : 
      87           2 :                 REQUIRE(wl1Clone.get() != &func);
      88           2 :                 REQUIRE(*wl1Clone == func);
      89           2 :             }
      90             : 
      91           8 :             Vector dataVec(dd.getNumberOfCoefficients());
      92           8 :             dataVec.setRandom();
      93           8 :             DataContainer<TestType> x(dd, dataVec);
      94             : 
      95           8 :             THEN("the evaluate works as expected")
      96           8 :             {
      97           2 :                 REQUIRE(func.evaluate(x) == Approx(scaleFactors.dot(cwiseAbs(x))));
      98           2 :             }
      99             : 
     100           8 :             THEN("the gradient and Hessian throw as expected")
     101           8 :             {
     102           2 :                 REQUIRE_THROWS_AS(func.getGradient(x), LogicError);
     103           2 :                 REQUIRE_THROWS_AS(func.getHessian(x), LogicError);
     104           2 :             }
     105           8 :         }
     106           8 :     }
     107             : 
     108          18 :     GIVEN("different sizes of the linear residual and weighting operator")
     109          18 :     {
     110             :         // linear residual
     111           2 :         IndexVector_t numCoeff(2);
     112           2 :         numCoeff << 47, 11;
     113           2 :         VolumeDescriptor dd(numCoeff);
     114             : 
     115             :         // linear residual
     116           2 :         IndexVector_t otherNumCoeff(3);
     117           2 :         otherNumCoeff << 15, 24, 4;
     118           2 :         VolumeDescriptor otherDD(otherNumCoeff);
     119             : 
     120           2 :         Vector randomData(dd.getNumberOfCoefficients());
     121           2 :         randomData.setRandom();
     122           2 :         DataContainer<TestType> b(dd, randomData);
     123             : 
     124           2 :         Identity<TestType> A(dd);
     125             : 
     126           2 :         LinearResidual<TestType> linRes(A, b);
     127             : 
     128             :         // scaling operator
     129           2 :         DataContainer<TestType> scaleFactors(otherDD);
     130           2 :         scaleFactors = 1;
     131             : 
     132           2 :         WHEN("instantiating an WeightedL1Norm object")
     133           2 :         {
     134           2 :             THEN("an InvalidArgumentError is thrown")
     135           2 :             {
     136           2 :                 REQUIRE_THROWS_AS(WeightedL1Norm<TestType>(linRes, scaleFactors),
     137           2 :                                   InvalidArgumentError);
     138           2 :             }
     139           2 :         }
     140           2 :     }
     141             : 
     142          18 :     GIVEN("weights of value 1 and a linear residual")
     143          18 :     {
     144             :         // linear residual
     145           6 :         IndexVector_t numCoeff(2);
     146           6 :         numCoeff << 47, 11;
     147           6 :         VolumeDescriptor dd(numCoeff);
     148             : 
     149           6 :         Vector randomData(dd.getNumberOfCoefficients());
     150           6 :         randomData.setRandom();
     151           6 :         DataContainer<TestType> b(dd, randomData);
     152             : 
     153           6 :         Identity<TestType> A(dd);
     154             : 
     155           6 :         LinearResidual<TestType> linRes(A, b);
     156             : 
     157             :         // scaling operator
     158           6 :         DataContainer<TestType> scaleFactors(dd);
     159           6 :         scaleFactors = 1;
     160             : 
     161           6 :         WHEN("instantiating an WeightedL1Norm object")
     162           6 :         {
     163           6 :             WeightedL1Norm<TestType> func(linRes, scaleFactors);
     164             : 
     165           6 :             THEN("the functional is as expected")
     166           6 :             {
     167           2 :                 REQUIRE(func.getDomainDescriptor() == dd);
     168           2 :                 REQUIRE(func.getWeightingOperator() == scaleFactors);
     169             : 
     170           2 :                 const auto* lRes =
     171           2 :                     dynamic_cast<const LinearResidual<TestType>*>(&func.getResidual());
     172           2 :                 REQUIRE(lRes);
     173           2 :                 REQUIRE(*lRes == linRes);
     174           2 :             }
     175             : 
     176           6 :             THEN("a clone behaves as expected")
     177           6 :             {
     178           2 :                 auto wl1Clone = func.clone();
     179             : 
     180           2 :                 REQUIRE(wl1Clone.get() != &func);
     181           2 :                 REQUIRE(*wl1Clone == func);
     182           2 :             }
     183             : 
     184           6 :             THEN("the evaluate, gradient and Hessian work was expected")
     185           6 :             {
     186           2 :                 Vector dataVec(dd.getNumberOfCoefficients());
     187           2 :                 dataVec.setRandom();
     188           2 :                 DataContainer<TestType> x(dd, dataVec);
     189             : 
     190           2 :                 REQUIRE(func.evaluate(x) == Approx(scaleFactors.dot(cwiseAbs(x - b))));
     191           2 :                 REQUIRE_THROWS_AS(func.getGradient(x), LogicError);
     192           2 :                 REQUIRE_THROWS_AS(func.getHessian(x), LogicError);
     193           2 :             }
     194           6 :         }
     195           6 :     }
     196          18 : }
     197             : 
     198             : TEST_SUITE_END();

Generated by: LCOV version 1.14