Skip to content

Commit 136ac70

Browse files
Add early exit in preconditioned CG when initial residual is below tolerance (#350)
Previously, the (preconditioned) Conjugate Gradient (CG) algorithm applies the preconditioner before checking whether the current residual already met the required tolerance. The changes from this MR allows the CG to return immediately when the initial residual is small enough, avoiding the unnecessary cost of a preconditioner call. This change can improve performance in cases where the initial guess is already close to the solution. Thanks to @ChristosMatzoros for proposing this enhancement!
1 parent 67af453 commit 136ac70

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

NOTICE

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ to Huawei Technologies Co., Ltd. or one of its subsidiaries:
2121

2222
- Aristeidis Mastoras, Huawei Technologies Switzerland AG; 2020-current.
2323

24-
- Alberto Scolari, Huawei Technologies Switzerland AG; 2021-current.
24+
- Alberto Scolari, Huawei Technologies Switzerland AG; 2021-2025.
2525

2626
- Verner Vlacic, Huawei Technologies Switzerland AG; 2021-current.
2727

@@ -34,6 +34,8 @@ to Huawei Technologies Co., Ltd. or one of its subsidiaries:
3434
- Denis Jelovina, Huawei Technologies Switzerland AG; 2022-current.
3535

3636
- Benjamin Lozes, Huawei Technologies Switzerland AG; 2023.
37+
38+
- Christos Konstantinos Matzoros, Huawei Technologies Switzerland AG; 2024-current.
3739

3840
The experimental banshee backend has been developed in collaboration with
3941
Prof. Luca Benini at ETH Zuerich and his group. In particular this backend

include/graphblas/algorithms/conjugate_gradient.hpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,37 @@ namespace grb {
348348
ret = ret ? ret : grb::foldl< descr_dense >( r, temp, minus );
349349
assert( ret == grb::SUCCESS );
350350

351+
// bnorm = b' * b;
352+
bnorm = zero;
353+
ret = ret ? ret : grb::dot< descr_dense >(
354+
bnorm,
355+
b, b,
356+
ring.getAdditiveMonoid(),
357+
grb::operators::conjugate_left_mul< IOType >()
358+
);
359+
assert( ret == grb::SUCCESS );
360+
361+
// get effective tolerance
362+
if( ret == grb::SUCCESS ) {
363+
tol *= std::sqrt( grb::utils::is_complex< IOType >::modulus( bnorm ) );
364+
}
365+
366+
// get residual
367+
alpha = zero;
368+
ret = ret ? ret : grb::dot< descr_dense >(
369+
alpha,
370+
r, r,
371+
ring.getAdditiveMonoid(),
372+
grb::operators::conjugate_left_mul< IOType >()
373+
);
374+
assert( ret == grb::SUCCESS );
375+
residual = grb::utils::is_complex< IOType >::modulus( alpha );
376+
377+
// check residual for early exit
378+
if( ret == grb::SUCCESS ) {
379+
if( sqrt( residual ) < tol ) { return ret; }
380+
}
381+
351382
// z = M^-1r
352383
if( preconditioned ) {
353384
ret = ret ? ret : grb::set( z, 0 ); // also ensures z is dense, henceforth
@@ -374,19 +405,8 @@ namespace grb {
374405

375406
assert( ret == grb::SUCCESS );
376407

377-
// bnorm = b' * b;
378-
bnorm = zero;
379-
ret = ret ? ret : grb::dot< descr_dense >(
380-
bnorm,
381-
b, b,
382-
ring.getAdditiveMonoid(),
383-
grb::operators::conjugate_left_mul< IOType >() );
384-
assert( ret == grb::SUCCESS );
385-
386-
// get effective tolerance and exit on any error during prelude
387-
if( ret == grb::SUCCESS ) {
388-
tol *= std::sqrt( grb::utils::is_complex< IOType >::modulus( bnorm ) );
389-
} else {
408+
// exit on any error during prelude
409+
if( ret != grb::SUCCESS ) {
390410
std::cerr << "Warning: preconditioned CG caught error during prelude ("
391411
<< grb::toString( ret ) << ")\n";
392412
return ret;

0 commit comments

Comments
 (0)