gko::solver::PipeCg#

Pipelined conjugate gradient. Restructures the standard CG loop so that the global reductions (inner products) can overlap with the next matrix-vector product and preconditioner apply. Reduces synchronisation latency on large distributed runs at the cost of more local work per iteration.

template<typename ValueType = default_precision>
class PipeCg #

Inherits from

  • public gko::LinOp

  • public gko::solver::EnablePreconditionedIterativeSolver<default_precision, PipeCg<default_precision>>

  • public gko::Transposable

PIPE_CG or the pipelined conjugate gradient method is an iterative type Krylov subspace method which is suitable for symmetric positive definite methods. It improves upon the CG method by allowing computation of inner products and norms to be overlapped with operator and preconditioner application. The pipelined method scales up to the 10^6 nodes of the assumed exascale machine, while its standard counterpart level off about one order of magnitude earlier, as suggested in the referenced paper (see below).

Mathematically the iterates \( x_k \) are the same as those produced by CG: the algorithm minimizes the energy-norm error over the Krylov subspace \( x_0 + \mathcal{K}_k(A, r_0) \) and uses the same Fletcher-Reeves \( \beta_k \). CG, however, needs two global reductions per iteration that cannot be merged: \( \rho_k = \langle r_k, z_k \rangle \) is needed to build \( p_k \), and only afterwards can \( q_k = A p_k \) and the second reduction \( \langle p_k, q_k \rangle \) be computed.

The pipelined variant removes that second synchronization point by carrying an extra vector \( w_k = A z_k \) — the operator applied to the preconditioned residual \( z_k = M r_k \), which plain CG never forms. It gives access to \( \delta_k = \langle w_k, z_k \rangle = \langle A z_k, z_k \rangle \), from which the denominator of \( \alpha_k \) follows by a recurrence instead of a second reduction:

\[ \langle p_k, A p_k \rangle = \delta_k - \left| \frac{\rho_k}{\rho_{k-1}} \right|^2 \langle p_{k-1}, A p_{k-1} \rangle . \]
Because \( \rho_k \) and \( \delta_k \) are available at the same point of the iteration, they are computed in a single global reduction that can be overlapped with the operator and preconditioner applies updating the auxiliary vectors \( w_k \), \( q_k = A p_k \), \( m_k = M w_k \) and \( n_k = A m_k \), all of which are advanced by short recurrences. In exact arithmetic the trajectory is identical to CG; in finite arithmetic the decoupling of dependencies amplifies round-off and the residuals can deviate from the classical iterates.

Possible issues:

  1. Numerical instability: Due to the rearrangement of the operations, the method is known to be less stable than standard PCG.

  2. The method is suitable for cases where a large number of iterations need to be performed and when the solver is distributed over a large number of distributed nodes. The advantage of lesser number of reductions that need to be performed comes at the cost of increased vector operations, and the cost of increased storage of vectors.

  3. As the CG itself, this method performs very well for symmetric positive definite matrices but it is in general not suitable for general matrices.

References

  • Sanan, P., Schnepp, S. M., May, D. A. Pipelined, Flexible Krylov Subspace Methods. SIAM Journal on Scientific Computing, 38 (5), 2016. https://doi.org/10.1137/15M1049130

Template Parameters:

ValueType – precision of matrix elements

Public Functions

virtual std::unique_ptr<LinOp> transpose() const override#

Returns a LinOp representing the transpose of the Transposable object.

Returns:

a pointer to the new transposed object

virtual std::unique_ptr<LinOp> conj_transpose() const override#

Returns a LinOp representing the conjugate transpose of the Transposable object.

Returns:

a pointer to the new conjugate transposed object

inline bool apply_uses_initial_guess() const override#

Return true as iterative solvers use the data in x as an initial guess.

Returns:

true as iterative solvers use the data in x as an initial guess.

Public Static Functions

static parameters_type parse(
const config::pnode &config,
const config::registry &context,
const config::type_descriptor &td_for_child = config::make_type_descriptor<ValueType>(),
)#

Create the parameters from the property_tree. Because this is directly tied to the specific type, the value/index type settings within config are ignored and type_descriptor is only used for children configs.

Parameters:
  • config – the property tree for setting

  • context – the registry

  • td_for_child – the type descriptor for children configs. The default uses the value type of this class.

Returns:

parameters

struct parameters_type #

Inherits from

  • public gko::solver::enable_preconditioned_iterative_solver_factory_parameters<parameters_type, Factory>