LCOV - code coverage report
Current view: top level - src/include/panoc-alm/inner/detail - anderson-helpers.hpp (source / functions) Hit Total Coverage
Test: ecee3ec3a495b05c61f077aa7a236b7e00601437 Lines: 19 19 100.0 %
Date: 2021-11-04 22:49:09 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <panoc-alm/inner/detail/limited-memory-qr.hpp>
       4             : 
       5             : namespace pa {
       6             : 
       7             : /**
       8             :  * @brief   Solve one step of Anderson acceleration to find a fixed point of a 
       9             :  *          function g(x):
      10             :  * 
      11             :  * @f$ g(x^\star) - x^\star = 0 @f$
      12             :  * 
      13             :  * Updates the QR factorization of @f$ \mathcal{R}_k = QR @f$, solves the least 
      14             :  * squares problem to find @f$ \gamma_\text{LS} @f$, computes the next 
      15             :  * iterate @f$ x_{k+1} @f$, and stores the current function value @f$ g_k @f$
      16             :  * in the matrix @f$ G @f$, which is used as a circular buffer.
      17             :  * @f[ \begin{aligned}
      18             :  * \mathcal{R}_k &= \begin{pmatrix} \Delta r_{k-m_k} & \dots & \Delta r_{k-1} \end{pmatrix} \in \mathbb{R}^{n\times m_k} \\
      19             :  * \Delta r_i &= r_{i+1} - r_i \\
      20             :  * r_i &= g_i - x_i \\
      21             :  * g_i &= g(x_i) \\
      22             :  * \DeclareMathOperator*{\argmin}{argmin}
      23             :  * \gamma_\text{LS} &= \argmin_\gamma \left\| \mathcal{R}_k \gamma - r_k \right\|_2 \\
      24             :  * \alpha_i &= \begin{cases} \gamma_\text{LS}[0] & i = 0 \\
      25             :  *                           \gamma_\text{LS}[i] - \gamma_\text{LS}[i-1] & 0 < i < m_k \\
      26             :  *                           1 - \gamma_\text{LS}[m_k - 1] & i = m_k \end{cases} \\
      27             :  * x_{k+1} &= \sum_{i=0}^{m_k} \alpha_i\,g_i
      28             :  * \end{aligned} @f]
      29             :  */
      30           4 : inline void minimize_update_anderson(LimitedMemoryQR &qr, rmat G, crvec rₖ,
      31             :                                      crvec rₖ₋₁, crvec gₖ, rvec γ_LS,
      32             :                                      rvec xₖ_aa) {
      33             :     // Update QR factorization for Anderson acceleration
      34           4 :     if (qr.num_columns() == qr.m()) // if the history buffer is full
      35           3 :         qr.remove_column();
      36           4 :     qr.add_column(rₖ - rₖ₋₁);
      37             : 
      38             :     // Solve least squares problem Anderson acceleration
      39             :     // γ = argmin ‖ ΔR γ - rₖ ‖²
      40           4 :     qr.solve_col(rₖ, γ_LS);
      41             : 
      42             :     // Iterate over columns of G, whose indices match the indices of the matrix
      43             :     // R in the QR factorization, stored as a circular buffer.
      44           4 :     auto g_it  = qr.ring_iter().begin();
      45           4 :     auto g_end = qr.ring_iter().end();
      46           4 :     assert(g_it != g_end);
      47             : 
      48             :     // Compute Anderson acceleration next iterate yₑₓₜ = ∑ₙ₌₀ αₙ gₙ
      49             :     // α₀ = γ₀             if n = 0
      50             :     // αₙ = γₙ - γₙ₋₁      if 0 < n < mₖ
      51             :     // αₘ = 1 - γₘ₋₁       if n = mₖ
      52           4 :     real_t α = γ_LS(0);
      53           4 :     xₖ_aa    = α * G.col((*g_it).circular);
      54          12 :     while (++g_it != g_end) {
      55          32 :         auto [i, g_idx] = *g_it; // [zero based index, circular index]
      56           8 :         α               = γ_LS(i) - γ_LS(i - 1);
      57           8 :         xₖ_aa += α * G.col(g_idx);
      58           8 :     }
      59           4 :     α = 1 - γ_LS(qr.num_columns() - 1);
      60           4 :     xₖ_aa += α * gₖ;
      61             : 
      62             :     // Add the new column to G
      63           4 :     G.col(qr.ring_tail()) = gₖ; // TODO: avoid copy, make G an array of vectors
      64           4 : }
      65             : 
      66             : } // namespace pa

Generated by: LCOV version 1.15