Line data Source code
1 : /** 2 : * @file test_LInfNorm.cpp 3 : * 4 : * @brief Tests for the LInfNorm 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 "LInfNorm.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("LInfNorm: Testing without residual", TestType, float, double, complex<float>, 29 : 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 << 8, 15; 37 12 : VolumeDescriptor dd(numCoeff); 38 : 39 12 : WHEN("instantiating") 40 12 : { 41 12 : LInfNorm<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& residual = func.getResidual(); 48 4 : auto* linRes = downcast_safe<LinearResidual<TestType>>(&residual); 49 4 : REQUIRE_UNARY(linRes); 50 4 : REQUIRE_UNARY_FALSE(linRes->hasDataVector()); 51 4 : REQUIRE_UNARY_FALSE(linRes->hasOperator()); 52 4 : } 53 : 54 12 : THEN("a clone behaves as expected") 55 12 : { 56 4 : auto lInfClone = func.clone(); 57 : 58 4 : REQUIRE_NE(lInfClone.get(), &func); 59 4 : REQUIRE_EQ(*lInfClone, 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> dc(dd, dataVec); 67 : 68 4 : REQUIRE_UNARY(checkApproxEq(func.evaluate(dc), dataVec.array().abs().maxCoeff())); 69 4 : REQUIRE_THROWS_AS(func.getGradient(dc), LogicError); 70 4 : REQUIRE_THROWS_AS(func.getHessian(dc), LogicError); 71 4 : } 72 12 : } 73 12 : } 74 : 75 24 : GIVEN("a residual with data") 76 24 : { 77 12 : IndexVector_t numCoeff(3); 78 12 : numCoeff << 3, 7, 13; 79 12 : VolumeDescriptor dd(numCoeff); 80 : 81 12 : Vector randomData(dd.getNumberOfCoefficients()); 82 12 : randomData.setRandom(); 83 12 : DataContainer<TestType> dc(dd, randomData); 84 : 85 12 : Identity<TestType> idOp(dd); 86 : 87 12 : LinearResidual<TestType> linRes(idOp, dc); 88 : 89 12 : WHEN("instantiating") 90 12 : { 91 12 : LInfNorm<TestType> func(linRes); 92 : 93 12 : THEN("the functional is as expected") 94 12 : { 95 4 : REQUIRE_EQ(func.getDomainDescriptor(), dd); 96 : 97 4 : auto& residual = func.getResidual(); 98 4 : auto* lRes = downcast_safe<LinearResidual<TestType>>(&residual); 99 4 : REQUIRE_UNARY(lRes); 100 4 : REQUIRE_EQ(*lRes, linRes); 101 4 : } 102 : 103 12 : THEN("a clone behaves as expected") 104 12 : { 105 4 : auto lInfClone = func.clone(); 106 : 107 4 : REQUIRE_NE(lInfClone.get(), &func); 108 4 : REQUIRE_EQ(*lInfClone, func); 109 4 : } 110 : 111 12 : THEN("the evaluate, gradient and Hessian work as expected") 112 12 : { 113 4 : Vector dataVec(dd.getNumberOfCoefficients()); 114 4 : dataVec.setRandom(); 115 4 : DataContainer<TestType> x(dd, dataVec); 116 : 117 4 : REQUIRE_UNARY(checkApproxEq( 118 4 : func.evaluate(x), (dataVec - randomData).template lpNorm<Eigen::Infinity>())); 119 4 : REQUIRE_THROWS_AS(func.getGradient(x), LogicError); 120 4 : REQUIRE_THROWS_AS(func.getHessian(x), LogicError); 121 4 : } 122 12 : } 123 : 124 : // TODO: add the rest with operator A=scaling, vector b=1 etc. 125 12 : } 126 24 : } 127 : 128 : TEST_SUITE_END();