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 : 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 24 : { 31 24 : using Vector = Eigen::Matrix<TestType, Eigen::Dynamic, 1>; 32 : 33 24 : GIVEN("just data (no residual)") 34 24 : { 35 12 : IndexVector_t numCoeff(2); 36 12 : numCoeff << 11, 13; 37 12 : VolumeDescriptor dd(numCoeff); 38 : 39 12 : WHEN("instantiating") 40 12 : { 41 12 : L2NormPow2<TestType> func(dd); 42 : 43 12 : THEN("the functional is as expected") 44 12 : { 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 4 : } 52 : 53 12 : THEN("a clone behaves as expected") 54 12 : { 55 4 : auto l2Clone = func.clone(); 56 4 : ; 57 : 58 4 : REQUIRE_NE(l2Clone.get(), &func); 59 4 : REQUIRE_EQ(*l2Clone, func); 60 4 : } 61 : 62 12 : THEN("the evaluate, gradient and Hessian work as expected") 63 12 : { 64 4 : Vector dataVec(dd.getNumberOfCoefficients()); 65 4 : dataVec.setRandom(); 66 4 : 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 4 : } 74 12 : } 75 12 : } 76 : 77 24 : GIVEN("a residual with data") 78 24 : { 79 12 : IndexVector_t numCoeff(2); 80 12 : numCoeff << 47, 11; 81 12 : VolumeDescriptor dd(numCoeff); 82 : 83 12 : Vector randomData(dd.getNumberOfCoefficients()); 84 12 : randomData.setRandom(); 85 12 : DataContainer<TestType> b(dd, randomData); 86 : 87 12 : Identity<TestType> A(dd); 88 : 89 12 : LinearResidual<TestType> linRes(A, b); 90 : 91 12 : WHEN("instantiating") 92 12 : { 93 12 : L2NormPow2<TestType> func(linRes); 94 : 95 12 : THEN("the functional is as expected") 96 12 : { 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 4 : } 103 : 104 12 : THEN("a clone behaves as expected") 105 12 : { 106 4 : auto l2Clone = func.clone(); 107 : 108 4 : REQUIRE_NE(l2Clone.get(), &func); 109 4 : REQUIRE_EQ(*l2Clone, func); 110 4 : } 111 : 112 12 : THEN("the evaluate, gradient and Hessian work was expected") 113 12 : { 114 4 : Vector dataVec(dd.getNumberOfCoefficients()); 115 4 : dataVec.setRandom(); 116 4 : DataContainer<TestType> x(dd, dataVec); 117 : 118 4 : REQUIRE_UNARY( 119 4 : checkApproxEq(func.evaluate(x), 0.5f * (dataVec - randomData).squaredNorm())); 120 : 121 4 : 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 4 : } 127 12 : } 128 12 : } 129 24 : } 130 : 131 : TEST_SUITE_END();