ALP User Documentation  0.8.preview
Algebraic Programming User Documentation
gmres.hpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2023 Huawei Technologies Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
27 #ifndef _H_GRB_ALGORITHMS_GMRES
28 #define _H_GRB_ALGORITHMS_GMRES
29 
30 #include <cstdio>
31 #include <complex>
32 #include <functional> //function
33 
34 #include <graphblas.hpp>
36 #include <graphblas/utils/iscomplex.hpp>
37 
38 namespace grb {
39 
40  namespace algorithms {
41 
135  template<
136  typename NonzeroType,
137  typename DimensionType,
138  typename ResidualType,
139  class Ring = Semiring<
142  >,
143  class Minus = operators::subtract< NonzeroType >,
144  class Divide = operators::divide< NonzeroType >
145  >
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 = Divide(),
155  const std::function< ResidualType( ResidualType ) > &sqrtX =
156  std_sqrt< ResidualType, ResidualType >
157  ) {
158  RC rc = grb::SUCCESS;
159 
160  if( n < 1 ) {
161  return ILLEGAL;
162  }
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";
168  return ILLEGAL;
169  }
170  if( kspspacesize < 1 ) {
171  return ILLEGAL;
172  }
173  if( kspspacesize >= n ) {
174  return ILLEGAL;
175  }
176  if( tol <= 0 ) {
177  return ILLEGAL;
178  }
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";
184  return MISMATCH;
185  }
186 
187  // vecx = H
188  for( size_t i = 0; i < n; ++i ) {
189  vecx[ i ] = H[ i ];
190  }
191 
192  size_t n_ksp = std::min( kspspacesize, n - 1 );
193 
194  // for i in range(n):
195  for( size_t i = 0; i < n_ksp; ++i ) {
196  // Givens rotation parameters
197  NonzeroType c, s;
198 
199  // this scope is is using real ring
200  {
201  Semiring<
204  > ring_rtype;
205 
206  // a, b = H[ i:i+2, i ]
207  NonzeroType a = H[ ( i + 1 ) * n + i ];
208  NonzeroType b = H[ ( i + 1 ) * n + i + 1 ];
209 
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;
215  rc = rc ? rc : grb::foldl( a_mod2, a_mod,
216  ring_rtype.getMultiplicativeOperator() );
217  rc = rc ? rc : grb::foldl( b_mod2, b_mod,
218  ring_rtype.getMultiplicativeOperator() );
219 
220  // tmp1 = sqrt(norm(a)**2+norm(b)**2)
221  ResidualType tmp1 = a_mod2;
222  rc = rc ? rc : grb::foldl( tmp1, b_mod2,
223  ring_rtype.getAdditiveOperator() );
224  tmp1 = sqrtX( tmp1 );
225 
226  //c = a_mod / tmp1 ;
227  c = a_mod;
228  rc = rc ? rc : grb::foldl( c, tmp1, divide );
229  if( a_mod != 0 ) {
230  // s = a / std::norm(a) * std::conj(b) / tmp1;
231  s = a;
232  rc = rc ? rc : grb::foldl( s, a_mod, divide );
233  rc = rc ? rc : grb::foldl( s, b_conj, ring.getMultiplicativeOperator() );
234  rc = rc ? rc : grb::foldl( s, tmp1, divide );
235  } else {
236  // s = std::conj(b) / tmp1;
237  s = b_conj;
238  rc = rc ? rc : grb::foldl( s, tmp1, divide );
239  }
240  }
241 
242  // for k in range(i,n):
243  for( size_t k = i; k < n_ksp; ++k ) {
244  // tmp2 = s * H[ i+1, k ]
245  NonzeroType tmp2 = H[ ( k + 1 ) * n + i + 1 ];
246  rc = rc ? rc : grb::foldl( tmp2, s, ring.getMultiplicativeOperator() );
247 
248  // H[i+1,k] = -conjugate(s) * H[i,k] + c * H[i+1,k]
249  NonzeroType tmp4 = H[ ( k + 1 ) * n + i ];
250  rc = rc ? rc : grb::foldl( H[ ( k + 1 ) * n + i + 1 ], c,
251  ring.getMultiplicativeOperator() );
252  rc = rc ? rc : grb::foldl(
253  tmp4,
254  grb::utils::is_complex< NonzeroType >::conjugate( s ),
255  ring.getMultiplicativeOperator()
256  );
257  rc = rc ? rc : grb::foldl( H[ ( k + 1 ) * n + i + 1 ], tmp4, minus );
258 
259  // H[i,k] = c * H[i,k] + tmp2
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() );
264  }
265 
266  // tmp3 = vecx[i]
267  NonzeroType tmp3 = vecx[ i ];
268  NonzeroType tmp5 = vecx[ i + 1 ];
269 
270  // vecx[i] = c * tmp3 + s * 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() );
274 
275 
276  // vecx[i+1] = -conjugate(s) * tmp3 + c * vecx[i+1]
277  rc = rc ? rc : grb::foldl( vecx[ i + 1 ], c, ring.getMultiplicativeOperator() );
278  rc = rc ? rc : grb::foldl(
279  tmp3,
280  grb::utils::is_complex< NonzeroType >::conjugate( s ),
281  ring.getMultiplicativeOperator()
282  );
283  rc = rc ? rc : grb::foldl( vecx[ i + 1 ], tmp3, minus );
284  }
285 
286 #ifdef _DEBUG
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 ] << " ";
290  }
291  std::cout << "\n";
292 #endif
293 
294  // for i in range(n-1,-1,-1):
295  for( size_t m = 0; m < n_ksp; ++m ) {
296  size_t i = n_ksp - 1 - m;
297  // for j in range(i+1,n):
298  for( size_t j = i + 1; j < n_ksp; ++j ) {
299  // vecx[i] = vecx[i]-vecx[j]*H[i,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 );
304  }
305  // vecx[i] = vecx[i]/H[i,i]
306  if( grb::utils::is_complex< NonzeroType >::modulus( H[ ( i + 1 ) * n + i ] )
307  < tol
308  ) {
309  std::cerr << "Warning: small number in algorithms::hessolve\n";
310  }
311  rc = rc ? rc : grb::foldl( vecx[ i ], H[ ( i + 1 ) * n + i ], divide );
312  }
313 
314  // H = vecx
315  for( size_t i = 0; i < n; ++i ) {
316  H[ i ] = vecx[ i ];
317  }
318 
319  // done
320  return rc;
321  }
322 
323  namespace internal {
324 
411  template<
413  typename NonzeroType,
414  typename ResidualType,
415  class Ring = Semiring<
418  >,
420  class Divide = operators::divide< NonzeroType >
421  >
422  grb::RC gmres_step(
426  std::vector< NonzeroType > &Hmatrix,
427  std::vector< grb::Vector< NonzeroType > > &Q,
428  const size_t n_restart,
429  const ResidualType tol,
430  size_t &iterations,
433  const Ring &ring = Ring(),
434  const Minus &minus = Minus(),
435  const Divide &divide = Divide(),
436  const std::function< ResidualType( ResidualType ) > &sqrtX =
437  std_sqrt< ResidualType, ResidualType >
438  ) {
439  // static checks
440  static_assert( std::is_floating_point< ResidualType >::value,
441  "Can only use the Arnoldi algorithm with floating-point residual types." );
442 
443  bool useprecond = false;
444  if( (nrows( M ) != 0) && (ncols( M ) != 0) ) {
445  useprecond = true;
446  }
447 
448  constexpr const Descriptor descr_dense = descr | descriptors::dense;
449  const ResidualType zero = ring.template getZero< ResidualType >();
450 
451  // dynamic checks, main error checking done in GMRES main function
452 #ifndef NDEBUG
453  const size_t n = grb::ncols( A );
454  {
455  const size_t m = grb::nrows( A );
456  assert( m == n );
457  assert( size( x ) == n );
458  assert( size( b ) == m );
459  assert( size( Q[ 0 ] ) == n );
460  assert( size( temp ) == n );
461  assert( capacity( x ) == n );
462  assert( capacity( Q[ 0 ] ) == n );
463  assert( capacity( temp ) == n );
464  assert( tol > zero );
465  }
466 #endif
467 
468  ResidualType rho, tau;
469 
470  // (re)set Hmatrix to zero
471  std::fill( Hmatrix.begin(), Hmatrix.end(), zero );
472 
473  //Q[:,0]=b-A.dot(x) ;
474  // temp = 0
475  grb::RC ret = grb::set< descr_dense >( temp, zero );
476  assert( ret == SUCCESS );
477 
478  // temp = A * x
479  ret = ret ? ret : grb::mxv< descr_dense >( temp, A, x, ring );
480  assert( ret == SUCCESS );
481 
482  // Q[ 0 ] = b - temp;
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 );
489  assert( ret == SUCCESS );
490 
491  // precond
492  if( useprecond ) {
493  // Q[ 0 ] = M * Q[ 0 ]
494  ret = grb::set< descr_dense >( temp, Q[ 0 ] );
495  assert( ret == SUCCESS );
496 
497  ret = grb::set< descr_dense >( Q[ 0 ], zero );
498  assert( ret == SUCCESS );
499 
500  ret = ret ? ret : grb::mxv< descr_dense >( Q[ 0 ], M, temp, ring );
501  assert( ret == SUCCESS );
502  }
503 
504  //rho = norm(Q[:,0])
505  rho = zero;
506  ret = ret ? ret : grb::algorithms::norm2< descr_dense >( rho, Q[ 0 ], ring,
507  sqrtX );
508  assert( ret == SUCCESS );
509 
510  Hmatrix[ 0 ] = rho;
511 
512  tau = tol * rho;
513 
514  size_t k = 0;
515  while( ( rho > tau ) && ( k < n_restart ) ) {
516  // alpha = r' * r;
517 
518  if( grb::utils::is_complex< NonzeroType >::modulus(
519  Hmatrix[ k * ( n_restart + 1 ) + k ]
520  ) < tol
521  ) {
522  break;
523  }
524 
525  // Q[k] = Q[k] / alpha
526  ret = ret ? ret : grb::foldl< descr_dense >( Q[ k ],
527  Hmatrix[ k * ( n_restart + 1 ) + k ], divide );
528  assert( ret == SUCCESS );
529 
530  // Q[k+1] = 0
531  ret = ret ? ret : grb::set< descr_dense >( Q[ k + 1 ], zero );
532  assert( ret == SUCCESS );
533 
534  // Q[k+1] = A * Q[k+1]
535  ret = ret ? ret : grb::mxv< descr_dense >( Q[ k + 1 ], A, Q[ k ], ring );
536  assert( ret == SUCCESS );
537 
538  // precond
539  if( useprecond ) {
540  // Q[k+1]= M * Q[k+1]
541  ret = grb::set< descr_dense >( temp, Q[ k+1 ] );
542  assert( ret == SUCCESS );
543 
544  ret = grb::set< descr_dense >( Q[ k+1 ], zero );
545  assert( ret == SUCCESS );
546 
547  ret = ret ? ret : grb::mxv< descr_dense >( Q[ k+1 ], M, temp, ring );
548  assert( ret == SUCCESS );
549  }
550 
551  (void) ++k;
552 
553  for( size_t j = 0; j < std::min( k, n_restart ); j++ ) {
554  //H[j,k] = Q[:,j].dot(Q[:,k])
555  Hmatrix[ k * ( n_restart + 1 ) + j ] = zero;
556  ret = ret ? ret : grb::dot< descr_dense >(
557  Hmatrix[ k * ( n_restart + 1 ) + j ],
558  Q[ k ], Q[ j ],
559  ring.getAdditiveMonoid(),
561  );
562  assert( ret == SUCCESS );
563 
564  //Q[:,k] = Q[:,k]-H[j,k]*Q[:,i]
565  grb::RC ret = grb::set< descr_dense >( temp, zero );
566  assert( ret == SUCCESS );
567 
568  NonzeroType alpha1 = Hmatrix[ k * ( n_restart + 1 ) + j ];
569  ret = ret ? ret : grb::eWiseMul< descr_dense >( temp, alpha1, Q[ j ],
570  ring );
571  assert( ret == SUCCESS );
572 
573  ret = ret ? ret : grb::foldl< descr_dense >( Q[ k ], temp, minus );
574  assert( ret == SUCCESS );
575  } // while
576 
577  //alpha = norm(Q[:,k])
578  ResidualType alpha = zero;
579  ret = ret ? ret : grb::algorithms::norm2< descr_dense >( alpha, Q[ k ],
580  ring, sqrtX );
581  assert( ret == SUCCESS );
582 
583  //H[k,k] = alpha
584  Hmatrix[ k * ( n_restart + 1 ) + k ] = alpha;
585  }
586 
587  iterations += k;
588 
589  return ret;
590  }
591 
601  template<
603  bool no_preconditioning = true,
604  typename NonzeroType,
605  typename ResidualType,
606  class Ring = Semiring<
609  >,
610  class Minus = operators::subtract< NonzeroType >,
611  class Divide = operators::divide< NonzeroType >
612  >
613  grb::RC gmres_dispatch(
617  const size_t n_restart,
618  const size_t max_iterations,
619  const ResidualType tol,
620  size_t &iterations,
621  size_t &iterations_gmres,
622  size_t &iterations_arnoldi,
623  ResidualType &residual,
624  std::vector< grb::Vector< NonzeroType > > &Q,
625  std::vector< NonzeroType > &Hmatrix,
627  std::vector< NonzeroType > &temp3,
629  const Ring &ring = Ring(),
630  const Minus &minus = Minus(),
631  const Divide &divide = Divide(),
632  const std::function< ResidualType( ResidualType ) > &sqrtX =
633  std_sqrt< ResidualType, ResidualType >
634  ) {
635  grb::RC rc = grb::SUCCESS;
636  constexpr const Descriptor descr_dense = descr | descriptors::dense;
637  const ResidualType zero = ring.template getZero< ResidualType >();
638 
639  // dynamic checks
640  {
641  // mismatches
642  const size_t n = grb::ncols( A );
643  const size_t m = grb::nrows( A );
644  if( grb::size( x ) != n ) {
645  return MISMATCH;
646  }
647  if( grb::size( b ) != m ) {
648  return MISMATCH;
649  }
650  if( !no_preconditioning ) {
651  if( grb::ncols( M ) != n || grb::nrows( M ) != m ) {
652  return MISMATCH;
653  }
654  }
655 
656  // illegal inputs
657  if( capacity( x ) != n ) {
658  return ILLEGAL;
659  }
660  if( m != n ) {
661  std::cerr << "Warning: grb::algorithms::conjugate_gradient requires "
662  << "square input matrices, but a non-square input matrix was "
663  << "given instead.\n";
664  return ILLEGAL;
665  }
666  if( n_restart == 0 && max_iterations > 0 ) {
667  return ILLEGAL;
668  }
669  if( tol <= zero ) {
670  std::cerr << "Error: tolerance input to GMRES must be strictly"
671  << "positive\n";
672  return ILLEGAL;
673  }
674 
675  // workspace
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";
679  // FIXME this should become a MISMATCH once ALP/Dense is up
680  return ILLEGAL;
681  }
682  for( size_t i = 0; i <= n_restart; ++i ) {
683  if( grb::size( Q[ i ] ) != n || grb::capacity( Q[ i ] ) != n ) {
684  std::cerr << "Error: provided workspace vectors in Q are not of the "
685  << "correct length and/or capacity.\n";
686  return ILLEGAL;
687  }
688  }
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";
693  // FIXME H should become a structured matrix and this code should return
694  // MISMATCH if dimension check fails, once ALP/Dense is up
695  return ILLEGAL;
696  }
697  if( grb::size( temp ) < n || grb::capacity( temp ) < n ) {
698  std::cerr << "Error: provided temp workspace vector is not of the correct "
699  << "length and/or capacity.\n";
700  return ILLEGAL;
701  }
702  if( temp3.size() < n ) {
703  std::cerr << "Error: provided temp3 workspace vector (STL) is not of the "
704  << "correct length.\n";
705  return ILLEGAL;
706  }
707  }
708 
709  // no side effects: set initial values to outputs only after error checking
710  iterations = iterations_gmres = iterations_arnoldi = 0;
711  residual = 0;
712 
713  // get RHS vector norm
714  ResidualType bnorm = zero;
715  rc = rc ? rc : grb::algorithms::norm2< descr_dense >( bnorm, b, ring,
716  sqrtX );
717 
718 #ifdef DEBUG
719  {
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 << " ";
726  }
727  std::cout << " ... ";
728  for( size_t k = n - 10; k < n; ++k ) {
729  const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
730  std::cout << nonzeroValue << " ";
731  }
732  std::cout << "\n";
733  }
734 #endif
735  // guard against a trivial call
736  if( max_iterations == 0 ) {
737  rc = rc ? rc : grb::algorithms::norm2< descr_dense >( residual, b, ring,
738  sqrtX );
739  assert( rc == grb::SUCCESS );
740 
741  if( residual <= tol * bnorm ) {
742  return rc;
743  } else {
744  return FAILED;
745  }
746  }
747 
748  // perform gmres iterations
749  for( size_t gmres_iter = 0; gmres_iter < max_iterations; ++gmres_iter ) {
750  (void) ++iterations;
751  (void) ++iterations_gmres;
752  size_t kspspacesize = 0;
753  if( no_preconditioning ) {
754 #ifdef DEBUG
755  std::cout << "Call gmres without preconditioner.\n";
756 #endif
757  rc = rc ? rc : gmres_step< descr_dense >(
758  x, A, b,
759  Hmatrix, Q,
760  n_restart, tol,
761  kspspacesize,
762  temp, grb::Matrix< NonzeroType >( 0, 0 ),
763  ring, minus, divide, sqrtX
764  );
765  } else {
766 #ifdef DEBUG
767  std::cout << "Call gmres with preconditioner.\n";
768 #endif
769  rc = rc ? rc : gmres_step< descr_dense >(
770  x, A, b,
771  Hmatrix, Q,
772  n_restart, tol,
773  kspspacesize,
774  temp, M,
775  ring, minus, divide, sqrtX
776  );
777  }
778 #ifdef DEBUG
779  if( rc == grb::SUCCESS ) {
780  std::cout << "gmres iteration finished successfully, kspspacesize = "
781  << kspspacesize << "\n";
782  }
783 #endif
784  assert( rc == grb::SUCCESS );
785 
786  iterations_arnoldi += kspspacesize;
787 
788  rc = rc ? rc : hessolve(
789  Hmatrix, n_restart + 1, kspspacesize, tol, temp3,
790  ring, minus, divide, sqrtX
791  );
792  assert( rc == grb::SUCCESS );
793 
794 
795  // update x
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 ],
798  ring );
799  assert( rc == grb::SUCCESS );
800 
801  }
802 
803 #ifdef DEBUG
804  if( rc == grb::SUCCESS ) {
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 << " ";
811  }
812  std::cout << " ... ";
813  for( size_t k = n-10; k < n; ++k ) {
814  const NonzeroType &nonzeroValue = pinnedVector.getNonzeroValue( k );
815  std::cout << nonzeroValue << " ";
816  }
817  std::cout << "\n";
818  }
819 #endif
820 
821  // calculate residual
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,
826  sqrtX );
827  assert( rc == grb::SUCCESS );
828 
829 #ifdef DEBUG
830  std::cout << "Residual norm = " << residual << " \n";
831 #endif
832 
833  if( residual <= tol * bnorm ) {
834 #ifdef DEBUG
835  std::cout << "Convergence reached\n";
836 #endif
837  break;
838  }
839  } // gmres iterations
840 
841  if( rc == SUCCESS && residual > tol * bnorm ) {
842  return FAILED;
843  } else {
844  return rc;
845  }
846  }
847 
848  } // end namespace grb::algorithms::internal
849 
956  template<
958  typename NonzeroType,
959  typename ResidualType,
960  class Ring = Semiring<
963  >,
964  class Minus = operators::subtract< NonzeroType >,
965  class Divide = operators::divide< NonzeroType >
966  >
971  const size_t n_restart,
972  const size_t max_iterations,
973  const ResidualType tol,
974  size_t &iterations,
975  size_t &iterations_gmres,
976  size_t &iterations_arnoldi,
977  ResidualType &residual,
978  std::vector< grb::Vector< NonzeroType > > &Q,
979  std::vector< NonzeroType > &Hmatrix,
981  std::vector< NonzeroType > &temp3,
982  const Ring &ring = Ring(),
983  const Minus &minus = Minus(),
984  const Divide &divide = Divide(),
985  const std::function< ResidualType( ResidualType ) > &sqrtX =
986  std_sqrt< ResidualType, ResidualType >
987  ) {
988  grb::Matrix< NonzeroType > dummy( 0, 0 );
989  return internal::gmres_dispatch< descr, true >(
990  x, A, b,
991  n_restart, max_iterations,
992  tol,
993  iterations, iterations_gmres, iterations_arnoldi,
994  residual,
995  Q, Hmatrix, temp, temp3,
996  dummy,
997  ring, minus, divide, sqrtX
998  );
999  }
1000 
1109  template<
1111  typename NonzeroType,
1112  typename ResidualType,
1113  class Ring = Semiring<
1116  >,
1117  class Minus = operators::subtract< NonzeroType >,
1118  class Divide = operators::divide< NonzeroType >
1119  >
1122  const grb::Matrix< NonzeroType > &M,
1123  const grb::Matrix< NonzeroType > &A,
1124  const grb::Vector< NonzeroType > &b,
1125  const size_t n_restart,
1126  const size_t max_iterations,
1127  const ResidualType tol,
1128  size_t &iterations,
1129  size_t &iterations_gmres,
1130  size_t &iterations_arnoldi,
1131  ResidualType &residual,
1132  std::vector< grb::Vector< NonzeroType > > &Q,
1133  std::vector< NonzeroType > &Hmatrix,
1135  std::vector< NonzeroType > &temp3,
1136  const Ring &ring = Ring(),
1137  const Minus &minus = Minus(),
1138  const Divide &divide = Divide(),
1139  const std::function< ResidualType( ResidualType ) > &sqrtX =
1140  std_sqrt< ResidualType, ResidualType >
1141  ) {
1142  return internal::gmres_dispatch< descr, false >(
1143  x, A, b,
1144  n_restart, max_iterations,
1145  tol,
1146  iterations, iterations_gmres, iterations_arnoldi,
1147  residual,
1148  Q, Hmatrix, temp, temp3,
1149  M,
1150  ring, minus, divide, sqrtX
1151  );
1152  }
1153 
1154 
1155  } // namespace algorithms
1156 
1157 } // end namespace grb
1158 
1159 #endif // end _H_GRB_ALGORITHMS_GMRES
1160 
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=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=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=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
Implements the 2-norm.
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