27 #ifndef _H_GRB_ALGORITHMS_GMRES 28 #define _H_GRB_ALGORITHMS_GMRES 36 #include <graphblas/utils/iscomplex.hpp> 40 namespace algorithms {
136 typename NonzeroType,
137 typename DimensionType,
138 typename ResidualType,
139 class Ring = Semiring<
143 class Minus = operators::subtract< NonzeroType >,
144 class Divide = operators::divide< NonzeroType >
147 std::vector< NonzeroType > &H,
148 const DimensionType n,
149 const DimensionType &kspspacesize,
150 const ResidualType tol,
151 std::vector< NonzeroType > &vecx,
152 const Ring &ring = Ring(),
153 const Minus &minus = Minus(),
154 const Divide ÷ = Divide(),
155 const std::function< ResidualType( ResidualType ) > &sqrtX =
156 std_sqrt< ResidualType, ResidualType >
163 if( H.size() < ( n * n ) ) {
164 std::cerr <<
"Error: algorithms::hessolve requires input parameter H to " 165 <<
"have a number of entries greater-than n^2. " 166 <<
"However, " << H.size() <<
" is smaller-than " 167 << ( n * n ) <<
".\n";
170 if( kspspacesize < 1 ) {
173 if( kspspacesize >= n ) {
179 if( vecx.size() <= n ) {
180 std::cerr <<
"Error: algorithms::hessolve requires a given workspace vecx " 181 <<
"that has a number of entries greater-than or equal-to the given " 182 <<
"parameter n. However, " << vecx.size() <<
" is strictly smaller-than " 183 <<
"or equal-to " << n <<
".\n";
188 for(
size_t i = 0; i < n; ++i ) {
192 size_t n_ksp = std::min( kspspacesize, n - 1 );
195 for(
size_t i = 0; i < n_ksp; ++i ) {
207 NonzeroType a = H[ ( i + 1 ) * n + i ];
208 NonzeroType b = H[ ( i + 1 ) * n + i + 1 ];
210 ResidualType a_mod = grb::utils::is_complex< NonzeroType >::modulus( a );
211 ResidualType b_mod = grb::utils::is_complex< NonzeroType >::modulus( b );
212 NonzeroType b_conj = grb::utils::is_complex< NonzeroType >::conjugate( b );
213 ResidualType a_mod2 = a_mod;
214 ResidualType b_mod2 = b_mod;
216 ring_rtype.getMultiplicativeOperator() );
218 ring_rtype.getMultiplicativeOperator() );
221 ResidualType tmp1 = a_mod2;
223 ring_rtype.getAdditiveOperator() );
224 tmp1 = sqrtX( tmp1 );
232 rc = rc ? rc :
grb::foldl( s, a_mod, divide );
233 rc = rc ? rc :
grb::foldl( s, b_conj, ring.getMultiplicativeOperator() );
243 for(
size_t k = i; k < n_ksp; ++k ) {
245 NonzeroType tmp2 = H[ ( k + 1 ) * n + i + 1 ];
246 rc = rc ? rc :
grb::foldl( tmp2, s, ring.getMultiplicativeOperator() );
249 NonzeroType tmp4 = H[ ( k + 1 ) * n + i ];
250 rc = rc ? rc :
grb::foldl( H[ ( k + 1 ) * n + i + 1 ], c,
251 ring.getMultiplicativeOperator() );
254 grb::utils::is_complex< NonzeroType >::conjugate( s ),
255 ring.getMultiplicativeOperator()
257 rc = rc ? rc :
grb::foldl( H[ ( k + 1 ) * n + i + 1 ], tmp4, minus );
260 rc = rc ? rc :
grb::foldl( H[ ( k + 1 ) * n + i ], c,
261 ring.getMultiplicativeOperator() );
262 rc = rc ? rc :
grb::foldl( H[ ( k + 1 ) * n + i ], tmp2,
263 ring.getAdditiveOperator() );
267 NonzeroType tmp3 = vecx[ i ];
268 NonzeroType tmp5 = vecx[ i + 1 ];
271 rc = rc ? rc :
grb::foldl( vecx[ i ], c, ring.getMultiplicativeOperator() );
272 rc = rc ? rc :
grb::foldl( tmp5, s, ring.getMultiplicativeOperator() );
273 rc = rc ? rc :
grb::foldl( vecx[ i ], tmp5, ring.getAdditiveOperator() );
277 rc = rc ? rc :
grb::foldl( vecx[ i + 1 ], c, ring.getMultiplicativeOperator() );
280 grb::utils::is_complex< NonzeroType >::conjugate( s ),
281 ring.getMultiplicativeOperator()
283 rc = rc ? rc :
grb::foldl( vecx[ i + 1 ], tmp3, minus );
287 std::cout <<
"hessolve vecx vector before back-substitution, vector = ";
288 for(
size_t k = 0; k < n_ksp; ++k ) {
289 std::cout << vecx[ k ] <<
" ";
295 for(
size_t m = 0; m < n_ksp; ++m ) {
296 size_t i = n_ksp - 1 - m;
298 for(
size_t j = i + 1; j < n_ksp; ++j ) {
300 NonzeroType tmp6 = vecx[ j ];
301 rc = rc ? rc :
grb::foldl( tmp6, H[ ( j + 1 ) * n + i ],
302 ring.getMultiplicativeOperator() );
303 rc = rc ? rc :
grb::foldl( vecx[ i ], tmp6, minus );
306 if( grb::utils::is_complex< NonzeroType >::modulus( H[ ( i + 1 ) * n + i ] )
309 std::cerr <<
"Warning: small number in algorithms::hessolve\n";
311 rc = rc ? rc :
grb::foldl( vecx[ i ], H[ ( i + 1 ) * n + i ], divide );
315 for(
size_t i = 0; i < n; ++i ) {
413 typename NonzeroType,
414 typename ResidualType,
426 std::vector< NonzeroType > &Hmatrix,
428 const size_t n_restart,
429 const ResidualType tol,
433 const Ring &ring = Ring(),
434 const Minus &minus = Minus(),
435 const Divide ÷ = Divide(),
436 const std::function< ResidualType( ResidualType ) > &sqrtX =
437 std_sqrt< ResidualType, ResidualType >
440 static_assert( std::is_floating_point< ResidualType >::value,
441 "Can only use the Arnoldi algorithm with floating-point residual types." );
443 bool useprecond =
false;
444 if( (
nrows( M ) != 0) && (
ncols( M ) != 0) ) {
449 const ResidualType zero = ring.template getZero< ResidualType >();
457 assert(
size( x ) == n );
458 assert(
size( b ) == m );
459 assert(
size( Q[ 0 ] ) == n );
460 assert(
size( temp ) == n );
464 assert( tol > zero );
468 ResidualType rho, tau;
471 std::fill( Hmatrix.begin(), Hmatrix.end(), zero );
475 grb::RC ret = grb::set< descr_dense >( temp, zero );
479 ret = ret ? ret : grb::mxv< descr_dense >( temp, A, x, ring );
483 ret = ret ? ret : grb::set< descr_dense >( Q[ 0 ], zero );
484 ret = ret ? ret : grb::foldl< descr_dense >( Q[ 0 ], b,
485 ring.getAdditiveMonoid() );
486 assert(
nnz( Q[ 0 ] ) == n );
487 assert(
nnz( temp ) == n );
488 ret = ret ? ret : grb::foldl< descr_dense >( Q[ 0 ], temp, minus );
494 ret = grb::set< descr_dense >( temp, Q[ 0 ] );
497 ret = grb::set< descr_dense >( Q[ 0 ], zero );
500 ret = ret ? ret : grb::mxv< descr_dense >( Q[ 0 ], M, temp, ring );
506 ret = ret ? ret : grb::algorithms::norm2< descr_dense >( rho, Q[ 0 ], ring,
515 while( ( rho > tau ) && ( k < n_restart ) ) {
518 if( grb::utils::is_complex< NonzeroType >::modulus(
519 Hmatrix[ k * ( n_restart + 1 ) + k ]
526 ret = ret ? ret : grb::foldl< descr_dense >( Q[ k ],
527 Hmatrix[ k * ( n_restart + 1 ) + k ], divide );
531 ret = ret ? ret : grb::set< descr_dense >( Q[ k + 1 ], zero );
535 ret = ret ? ret : grb::mxv< descr_dense >( Q[ k + 1 ], A, Q[ k ], ring );
541 ret = grb::set< descr_dense >( temp, Q[ k+1 ] );
544 ret = grb::set< descr_dense >( Q[ k+1 ], zero );
547 ret = ret ? ret : grb::mxv< descr_dense >( Q[ k+1 ], M, temp, ring );
553 for(
size_t j = 0; j < std::min( k, n_restart ); j++ ) {
555 Hmatrix[ k * ( n_restart + 1 ) + j ] = zero;
556 ret = ret ? ret : grb::dot< descr_dense >(
557 Hmatrix[ k * ( n_restart + 1 ) + j ],
559 ring.getAdditiveMonoid(),
565 grb::RC ret = grb::set< descr_dense >( temp, zero );
568 NonzeroType alpha1 = Hmatrix[ k * ( n_restart + 1 ) + j ];
569 ret = ret ? ret : grb::eWiseMul< descr_dense >( temp, alpha1, Q[ j ],
573 ret = ret ? ret : grb::foldl< descr_dense >( Q[ k ], temp, minus );
578 ResidualType alpha = zero;
579 ret = ret ? ret : grb::algorithms::norm2< descr_dense >( alpha, Q[ k ],
584 Hmatrix[ k * ( n_restart + 1 ) + k ] = alpha;
603 bool no_preconditioning =
true,
604 typename NonzeroType,
605 typename ResidualType,
606 class Ring = Semiring<
610 class Minus = operators::subtract< NonzeroType >,
611 class Divide = operators::divide< NonzeroType >
617 const size_t n_restart,
618 const size_t max_iterations,
619 const ResidualType tol,
621 size_t &iterations_gmres,
622 size_t &iterations_arnoldi,
623 ResidualType &residual,
625 std::vector< NonzeroType > &Hmatrix,
627 std::vector< NonzeroType > &temp3,
629 const Ring &ring = Ring(),
630 const Minus &minus = Minus(),
631 const Divide ÷ = Divide(),
632 const std::function< ResidualType( ResidualType ) > &sqrtX =
633 std_sqrt< ResidualType, ResidualType >
637 const ResidualType zero = ring.template getZero< ResidualType >();
650 if( !no_preconditioning ) {
661 std::cerr <<
"Warning: grb::algorithms::conjugate_gradient requires " 662 <<
"square input matrices, but a non-square input matrix was " 663 <<
"given instead.\n";
666 if( n_restart == 0 && max_iterations > 0 ) {
670 std::cerr <<
"Error: tolerance input to GMRES must be strictly" 676 if( Q.size() <= n_restart ) {
677 std::cerr <<
"Error: expected n_restart + 1 (" << (n_restart+1) <<
") " 678 <<
"columns in the given Q, but only " << Q.size() <<
" were given.\n";
682 for(
size_t i = 0; i <= n_restart; ++i ) {
684 std::cerr <<
"Error: provided workspace vectors in Q are not of the " 685 <<
"correct length and/or capacity.\n";
689 if( Hmatrix.size() < ( ( n_restart + 1 ) * ( n_restart + 1 ) ) ) {
690 std::cerr <<
"Error: expected (n_restart + 1)^2 entries in H (" 691 << ( ( n_restart + 1 ) * ( n_restart + 1 ) ) <<
"), but only " 692 << Hmatrix.size() <<
" were given.\n";
698 std::cerr <<
"Error: provided temp workspace vector is not of the correct " 699 <<
"length and/or capacity.\n";
702 if( temp3.size() < n ) {
703 std::cerr <<
"Error: provided temp3 workspace vector (STL) is not of the " 704 <<
"correct length.\n";
710 iterations = iterations_gmres = iterations_arnoldi = 0;
714 ResidualType bnorm = zero;
715 rc = rc ? rc : grb::algorithms::norm2< descr_dense >( bnorm, b, ring,
720 std::cout <<
"RHS norm = " << bnorm <<
" \n";
721 PinnedVector< NonzeroType > pinnedVector( b,
SEQUENTIAL );
722 std::cout <<
"RHS vector = ";
723 for(
size_t k = 0; k < 10; ++k ) {
724 const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
725 std::cout << nonzeroValue <<
" ";
727 std::cout <<
" ... ";
728 for(
size_t k = n - 10; k < n; ++k ) {
729 const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
730 std::cout << nonzeroValue <<
" ";
736 if( max_iterations == 0 ) {
737 rc = rc ? rc : grb::algorithms::norm2< descr_dense >( residual, b, ring,
741 if( residual <= tol * bnorm ) {
749 for(
size_t gmres_iter = 0; gmres_iter < max_iterations; ++gmres_iter ) {
751 (void) ++iterations_gmres;
752 size_t kspspacesize = 0;
753 if( no_preconditioning ) {
755 std::cout <<
"Call gmres without preconditioner.\n";
757 rc = rc ? rc : gmres_step< descr_dense >(
763 ring, minus, divide, sqrtX
767 std::cout <<
"Call gmres with preconditioner.\n";
769 rc = rc ? rc : gmres_step< descr_dense >(
775 ring, minus, divide, sqrtX
780 std::cout <<
"gmres iteration finished successfully, kspspacesize = " 781 << kspspacesize <<
"\n";
786 iterations_arnoldi += kspspacesize;
789 Hmatrix, n_restart + 1, kspspacesize, tol, temp3,
790 ring, minus, divide, sqrtX
796 for(
size_t i = 0; rc ==
grb::SUCCESS && i < kspspacesize; ++i ) {
797 rc = rc ? rc : grb::eWiseMul< descr_dense >( x, Hmatrix[ i ], Q[ i ],
805 std::cout <<
"vector x updated successfully\n";
806 PinnedVector< NonzeroType > pinnedVector( x,
SEQUENTIAL );
807 std::cout <<
"x vector = ";
808 for(
size_t k = 0; k < 10; ++k ) {
809 const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
810 std::cout << nonzeroValue <<
" ";
812 std::cout <<
" ... ";
813 for(
size_t k = n-10; k < n; ++k ) {
814 const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
815 std::cout << nonzeroValue <<
" ";
822 rc = grb::set< descr_dense >( temp, zero );
823 rc = rc ? rc : grb::mxv< descr_dense >( temp, A, x, ring );
824 rc = rc ? rc : grb::foldl< descr_dense >( temp, b, minus );
825 rc = rc ? rc : grb::algorithms::norm2< descr_dense >( residual, temp, ring,
830 std::cout <<
"Residual norm = " << residual <<
" \n";
833 if( residual <= tol * bnorm ) {
835 std::cout <<
"Convergence reached\n";
841 if( rc ==
SUCCESS && residual > tol * bnorm ) {
958 typename NonzeroType,
959 typename ResidualType,
960 class Ring = Semiring<
964 class Minus = operators::subtract< NonzeroType >,
965 class Divide = operators::divide< NonzeroType >
971 const size_t n_restart,
972 const size_t max_iterations,
973 const ResidualType tol,
975 size_t &iterations_gmres,
976 size_t &iterations_arnoldi,
977 ResidualType &residual,
979 std::vector< NonzeroType > &Hmatrix,
981 std::vector< NonzeroType > &temp3,
982 const Ring &ring = Ring(),
983 const Minus &minus = Minus(),
984 const Divide ÷ = Divide(),
985 const std::function< ResidualType( ResidualType ) > &sqrtX =
986 std_sqrt< ResidualType, ResidualType >
989 return internal::gmres_dispatch< descr, true >(
991 n_restart, max_iterations,
993 iterations, iterations_gmres, iterations_arnoldi,
995 Q, Hmatrix, temp, temp3,
997 ring, minus, divide, sqrtX
1111 typename NonzeroType,
1112 typename ResidualType,
1125 const size_t n_restart,
1126 const size_t max_iterations,
1127 const ResidualType tol,
1129 size_t &iterations_gmres,
1130 size_t &iterations_arnoldi,
1131 ResidualType &residual,
1133 std::vector< NonzeroType > &Hmatrix,
1135 std::vector< NonzeroType > &temp3,
1136 const Ring &ring = Ring(),
1137 const Minus &minus = Minus(),
1138 const Divide ÷ = Divide(),
1139 const std::function< ResidualType( ResidualType ) > &sqrtX =
1140 std_sqrt< ResidualType, ResidualType >
1142 return internal::gmres_dispatch< descr, false >(
1144 n_restart, max_iterations,
1146 iterations, iterations_gmres, iterations_arnoldi,
1148 Q, Hmatrix, temp, temp3,
1150 ring, minus, divide, sqrtX
1159 #endif // end _H_GRB_ALGORITHMS_GMRES grb::RC gmres(grb::Vector< NonzeroType > &x, const grb::Matrix< NonzeroType > &A, const grb::Vector< NonzeroType > &b, const size_t n_restart, const size_t max_iterations, const ResidualType tol, size_t &iterations, size_t &iterations_gmres, size_t &iterations_arnoldi, ResidualType &residual, std::vector< grb::Vector< NonzeroType > > &Q, std::vector< NonzeroType > &Hmatrix, grb::Vector< NonzeroType > &temp, std::vector< NonzeroType > &temp3, const Ring &ring=Ring(), const Minus &minus=Minus(), const Divide ÷=Divide(), const std::function< ResidualType(ResidualType) > &sqrtX=std_sqrt< ResidualType, ResidualType >)
Solves a linear system with unknown using the Generalised Minimal Residual (GMRES) method on genera...
Definition: gmres.hpp:967
Standard identity for numerical addition.
Definition: identities.hpp:57
A call to a primitive has determined that one of its arguments was illegal as per the specification o...
Definition: rc.hpp:143
An ALP/GraphBLAS matrix.
Definition: matrix.hpp:72
RC
Return codes of ALP primitives.
Definition: rc.hpp:47
A GraphBLAS vector.
Definition: vector.hpp:64
Standard identity for numerical multiplication.
Definition: identities.hpp:79
Numerical substraction of two numbers.
Definition: ops.hpp:301
grb::RC preconditioned_gmres(grb::Vector< NonzeroType > &x, const grb::Matrix< NonzeroType > &M, const grb::Matrix< NonzeroType > &A, const grb::Vector< NonzeroType > &b, const size_t n_restart, const size_t max_iterations, const ResidualType tol, size_t &iterations, size_t &iterations_gmres, size_t &iterations_arnoldi, ResidualType &residual, std::vector< grb::Vector< NonzeroType > > &Q, std::vector< NonzeroType > &Hmatrix, grb::Vector< NonzeroType > &temp, std::vector< NonzeroType > &temp3, const Ring &ring=Ring(), const Minus &minus=Minus(), const Divide ÷=Divide(), const std::function< ResidualType(ResidualType) > &sqrtX=std_sqrt< ResidualType, ResidualType >)
Solves a linear system with unknown using the Generalised Minimal Residual (GMRES) method on genera...
Definition: gmres.hpp:1120
grb::RC hessolve(std::vector< NonzeroType > &H, const DimensionType n, const DimensionType &kspspacesize, const ResidualType tol, std::vector< NonzeroType > &vecx, const Ring &ring=Ring(), const Minus &minus=Minus(), const Divide ÷=Divide(), const std::function< ResidualType(ResidualType) > &sqrtX=std_sqrt< ResidualType, ResidualType >)
Solves the least linear square problem of size n - 1, defined by the equation where the is an upper...
Definition: gmres.hpp:146
Sequential mode IO.
Definition: iomode.hpp:75
size_t nnz(const Vector< DataType, backend, Coords > &x) noexcept
Request the number of nonzeroes in a given vector.
Definition: io.hpp:479
static constexpr Descriptor no_operation
Indicates no additional pre- or post-processing on any of the GraphBLAS function arguments.
Definition: descriptors.hpp:63
This operator multiplies the two input parameters and writes the result to the output variable.
Definition: ops.hpp:208
unsigned int Descriptor
Descriptors indicate pre- or post-processing for some or all of the arguments to an ALP/GraphBLAS cal...
Definition: descriptors.hpp:54
size_t nrows(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the row size of a given matrix.
Definition: io.hpp:286
static constexpr Descriptor dense
Indicates that all input and output vectors to an ALP/GraphBLAS primitive are structurally dense.
Definition: descriptors.hpp:151
size_t ncols(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the column size of a given matrix.
Definition: io.hpp:339
Conjugate-multiply operator that conjugates the right-hand operand before multiplication.
Definition: ops.hpp:918
RC foldl(IOType &x, const Vector< InputType, backend, Coords > &y, const Vector< MaskType, backend, Coords > &mask, const Monoid &monoid=Monoid(), const typename std::enable_if< !grb::is_object< IOType >::value &&!grb::is_object< InputType >::value &&!grb::is_object< MaskType >::value &&grb::is_monoid< Monoid >::value, void >::type *const =nullptr)
Reduces, or folds, a vector into a scalar.
Definition: blas1.hpp:3840
Indicates when one of the grb::algorithms has failed to achieve its intended result,...
Definition: rc.hpp:154
This operator takes the sum of the two input parameters and writes it to the output variable.
Definition: ops.hpp:175
The ALP/GraphBLAS namespace.
Definition: graphblas.hpp:477
The main header to include in order to use the ALP/GraphBLAS API.
size_t size(const Vector< DataType, backend, Coords > &x) noexcept
Request the size of a given vector.
Definition: io.hpp:235
Numerical division of two numbers.
Definition: ops.hpp:328
Indicates the primitive has executed successfully.
Definition: rc.hpp:54
size_t capacity(const Vector< InputType, backend, Coords > &x) noexcept
Queries the capacity of the given ALP/GraphBLAS container.
Definition: io.hpp:388
A generalised semiring.
Definition: semiring.hpp:190
One or more of the ALP/GraphBLAS objects passed to the primitive that returned this error have mismat...
Definition: rc.hpp:90