Line data Source code
1 : /** 2 : * @file test_L2NormPow2.cpp 3 : * 4 : * @brief Tests for the L2NormPow2 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 "L2NormPow2.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 4 : TYPE_TO_STRING(complex<float>); 24 4 : TYPE_TO_STRING(complex<double>); 25 : 26 : TEST_SUITE_BEGIN("functionals"); 27 : 28 44 : 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 : 33 36 : GIVEN("just data (no residual)") 34 : { 35 24 : IndexVector_t numCoeff(2); 36 12 : numCoeff << 11, 13; 37 24 : VolumeDescriptor dd(numCoeff); 38 : 39 24 : WHEN("instantiating") 40 : { 41 24 : L2NormPow2<TestType> func(dd); 42 : 43 16 : THEN("the functional is as expected") 44 : { 45 4 : REQUIRE_EQ(func.getDomainDescriptor(), dd); 46 : 47 4 : auto* linRes = downcast_safe<LinearResidual<TestType>>(&func.getResidual()); 48 4 : REQUIRE_UNARY(linRes); 49 4 : REQUIRE_UNARY_FALSE(linRes->hasOperator()); 50 4 : REQUIRE_UNARY_FALSE(linRes->hasDataVector()); 51 : } 52 : 53 16 : THEN("a clone behaves as expected") 54 : { 55 8 : auto l2Clone = func.clone(); 56 : ; 57 : 58 4 : REQUIRE_NE(l2Clone.get(), &func); 59 4 : REQUIRE_EQ(*l2Clone, func); 60 : } 61 : 62 16 : THEN("the evaluate, gradient and Hessian work as expected") 63 : { 64 8 : Vector dataVec(dd.getNumberOfCoefficients()); 65 4 : dataVec.setRandom(); 66 8 : DataContainer<TestType> x(dd, dataVec); 67 : 68 4 : REQUIRE_UNARY(checkApproxEq(func.evaluate(x), 0.5f * dataVec.squaredNorm())); 69 4 : REQUIRE_EQ(func.getGradient(x), x); 70 : 71 4 : Identity<TestType> idOp(dd); 72 4 : REQUIRE_EQ(func.getHessian(x), leaf(idOp)); 73 : } 74 : } 75 : } 76 : 77 36 : GIVEN("a residual with data") 78 : { 79 24 : IndexVector_t numCoeff(2); 80 12 : numCoeff << 47, 11; 81 24 : VolumeDescriptor dd(numCoeff); 82 : 83 24 : Vector randomData(dd.getNumberOfCoefficients()); 84 12 : randomData.setRandom(); 85 24 : DataContainer<TestType> b(dd, randomData); 86 : 87 24 : Identity<TestType> A(dd); 88 : 89 24 : LinearResidual<TestType> linRes(A, b); 90 : 91 24 : WHEN("instantiating") 92 : { 93 24 : L2NormPow2<TestType> func(linRes); 94 : 95 16 : THEN("the functional is as expected") 96 : { 97 4 : REQUIRE_EQ(func.getDomainDescriptor(), dd); 98 : 99 4 : auto* lRes = downcast_safe<LinearResidual<TestType>>(&func.getResidual()); 100 4 : REQUIRE_UNARY(lRes); 101 4 : REQUIRE_EQ(*lRes, linRes); 102 : } 103 : 104 16 : THEN("a clone behaves as expected") 105 : { 106 8 : auto l2Clone = func.clone(); 107 : 108 4 : REQUIRE_NE(l2Clone.get(), &func); 109 4 : REQUIRE_EQ(*l2Clone, func); 110 : } 111 : 112 16 : THEN("the evaluate, gradient and Hessian work was expected") 113 : { 114 8 : Vector dataVec(dd.getNumberOfCoefficients()); 115 4 : dataVec.setRandom(); 116 8 : DataContainer<TestType> x(dd, dataVec); 117 : 118 4 : REQUIRE_UNARY( 119 : checkApproxEq(func.evaluate(x), 0.5f * (dataVec - randomData).squaredNorm())); 120 : 121 8 : DataContainer<TestType> grad(dd, (dataVec - randomData).eval()); 122 4 : REQUIRE_EQ(func.getGradient(x), grad); 123 : 124 4 : auto hessian = func.getHessian(x); 125 4 : REQUIRE_EQ(hessian.apply(x), x); 126 : } 127 : } 128 : } 129 24 : } 130 : 131 : TEST_SUITE_END();