LCOV - code coverage report
Current view: top level - solvers/tests - test_GradientDescent.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 64 64 100.0 %
Date: 2022-02-28 03:37:41 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_GradientDescent.cpp
       3             :  *
       4             :  * @brief Tests for the GradientDescent class
       5             :  *
       6             :  * @author Tobias Lasser - initial code
       7             :  */
       8             : 
       9             : #include "doctest/doctest.h"
      10             : 
      11             : #include "GradientDescent.h"
      12             : #include "WLSProblem.h"
      13             : #include "Problem.h"
      14             : #include "Identity.h"
      15             : #include "LinearResidual.h"
      16             : #include "L2NormPow2.h"
      17             : #include "Logger.h"
      18             : #include "VolumeDescriptor.h"
      19             : #include "testHelpers.h"
      20             : #include <iostream>
      21             : 
      22             : using namespace elsa;
      23             : using namespace doctest;
      24             : 
      25             : TEST_SUITE_BEGIN("solvers");
      26             : 
      27           8 : TYPE_TO_STRING(GradientDescent<float>);
      28           8 : TYPE_TO_STRING(GradientDescent<double>);
      29             : 
      30             : template <template <typename> typename T, typename data_t>
      31             : constexpr data_t return_data_t(const T<data_t>&);
      32             : 
      33          16 : TEST_CASE_TEMPLATE("GradientDescent: Solving a simple linear problem", TestType,
      34             :                    GradientDescent<float>, GradientDescent<double>)
      35             : {
      36             :     // Set seed for Eigen Matrices!
      37           4 :     srand((unsigned int) 666);
      38             : 
      39             :     using data_t = decltype(return_data_t(std::declval<TestType>()));
      40             :     // eliminate the timing info from console for the tests
      41           4 :     Logger::setLevel(Logger::LogLevel::OFF);
      42             : 
      43           8 :     GIVEN("a linear problem")
      44             :     {
      45           8 :         IndexVector_t numCoeff(2);
      46           4 :         numCoeff << 13, 24;
      47           8 :         VolumeDescriptor dd(numCoeff);
      48             : 
      49           8 :         Eigen::Matrix<data_t, -1, 1> bVec(dd.getNumberOfCoefficients());
      50           4 :         bVec.setRandom();
      51           8 :         DataContainer dcB(dd, bVec);
      52             : 
      53           8 :         Identity<data_t> idOp(dd);
      54             : 
      55           8 :         WLSProblem prob(idOp, dcB);
      56           4 :         data_t epsilon = std::numeric_limits<data_t>::epsilon();
      57             : 
      58           6 :         WHEN("setting up a Gradient Descent solver with fixed step size")
      59             :         {
      60           4 :             TestType solver{prob, 0.5};
      61             : 
      62           4 :             THEN("the clone works correctly")
      63             :             {
      64           4 :                 auto gdClone = solver.clone();
      65             : 
      66           2 :                 REQUIRE_NE(gdClone.get(), &solver);
      67           2 :                 REQUIRE_EQ(*gdClone, solver);
      68             : 
      69           4 :                 AND_THEN("it works as expected")
      70             :                 {
      71           4 :                     auto solution = solver.solve(100);
      72             : 
      73           2 :                     DataContainer<data_t> resultsDifference = solution - dcB;
      74             : 
      75             :                     // should have converged for the given number of iterations
      76           2 :                     REQUIRE_LE(resultsDifference.squaredL2Norm(),
      77             :                                epsilon * epsilon * dcB.squaredL2Norm());
      78             :                 }
      79             :             }
      80             :         }
      81             : 
      82           6 :         WHEN("setting up a Gradient Descent solver with lipschitz step size")
      83             :         {
      84           4 :             TestType solver{prob};
      85             : 
      86           4 :             THEN("the clone works correctly")
      87             :             {
      88           4 :                 auto gdClone = solver.clone();
      89             : 
      90           2 :                 REQUIRE_NE(gdClone.get(), &solver);
      91           2 :                 REQUIRE_EQ(*gdClone, solver);
      92             : 
      93           4 :                 AND_THEN("it works as expected")
      94             :                 {
      95           4 :                     auto solution = solver.solve(10);
      96             : 
      97           2 :                     DataContainer<data_t> resultsDifference = solution - dcB;
      98             : 
      99             :                     // should have converged for the given number of iterations
     100           2 :                     REQUIRE_UNARY(checkApproxEq(resultsDifference.squaredL2Norm(),
     101             :                                                 epsilon * epsilon * dcB.squaredL2Norm()));
     102             :                 }
     103             :             }
     104             :         }
     105             :     }
     106           4 : }
     107             : 
     108          16 : TEST_CASE_TEMPLATE("GradientDescent: Solving a Tikhonov problem", TestType, GradientDescent<float>,
     109             :                    GradientDescent<double>)
     110             : {
     111             :     // Set seed for Eigen Matrices!
     112           4 :     srand((unsigned int) 666);
     113             : 
     114             :     using data_t = decltype(return_data_t(std::declval<TestType>()));
     115             :     // eliminate the timing info from console for the tests
     116           4 :     Logger::setLevel(Logger::LogLevel::OFF);
     117             : 
     118           8 :     GIVEN("a Tikhonov problem")
     119             :     {
     120           8 :         IndexVector_t numCoeff(2);
     121           4 :         numCoeff << 13, 24;
     122           8 :         VolumeDescriptor dd(numCoeff);
     123             : 
     124           8 :         Eigen::Matrix<data_t, -1, 1> bVec(dd.getNumberOfCoefficients());
     125           4 :         bVec.setRandom();
     126           8 :         DataContainer dcB(dd, bVec);
     127             : 
     128           8 :         Identity<data_t> idOp(dd);
     129           8 :         LinearResidual<data_t> linRes(idOp, dcB);
     130           8 :         L2NormPow2<data_t> func(linRes);
     131             : 
     132             :         // the regularization term
     133           8 :         L2NormPow2<data_t> regFunc(dd);
     134           4 :         auto lambda = static_cast<data_t>(0.1f);
     135           8 :         RegularizationTerm<data_t> regTerm(lambda, regFunc);
     136           8 :         Problem prob(func, regTerm);
     137             : 
     138           8 :         WHEN("setting up a Gradient Descent solver with fixed step size")
     139             :         {
     140           8 :             TestType solver{prob, 0.5};
     141             : 
     142           6 :             THEN("the clone works correctly")
     143             :             {
     144           4 :                 auto gdClone = solver.clone();
     145             : 
     146           2 :                 REQUIRE_NE(gdClone.get(), &solver);
     147           2 :                 REQUIRE_EQ(*gdClone, solver);
     148             :             }
     149           6 :             THEN("it works as expected")
     150             :             {
     151           4 :                 auto solution = solver.solve(10);
     152             : 
     153           2 :                 DataContainer<data_t> resultsDifference = solution - dcB;
     154             : 
     155             :                 // should have converged for the given number of iterations
     156             :                 // does not converge to the optimal solution because of the regularization term
     157             :                 // Therefore, just check to fixed value
     158           2 :                 REQUIRE_UNARY(checkApproxEq(resultsDifference.squaredL2Norm(), 0.85f));
     159             :             }
     160             :         }
     161             :     }
     162           4 : }
     163             : 
     164             : TEST_SUITE_END();

Generated by: LCOV version 1.15