SND@LHC Software
Loading...
Searching...
No Matches
minresmodule Module Reference

MINRES solves symmetric systems Ax = b or min ||Ax - b||_2, where the matrix A may be indefinite and/or singular. More...

Functions/Subroutines

subroutine, public minres (n, aprod, msolve, b, shift, checka, precon, x, itnlim, nout, rtol, istop, itn, anorm, acond, rnorm, arnorm, ynorm)
 Solution of linear equation system.
 

Detailed Description

MINRES solves symmetric systems Ax = b or min ||Ax - b||_2, where the matrix A may be indefinite and/or singular.

 The software for MINRES (f90 version) is provided by SOL, Stanford University
 under the terms of the OSI Common Public License (CPL):
 http://www.opensource.org/licenses/cpl1.0.php

 Contributors:
     Chris Paige <chris@cs.mcgill.ca>
     Sou-Cheng Choi <scchoi@stanford.edu>

     Michael Saunders <saunders@stanford.edu>
     Systems Optimization Laboratory (SOL)
     Stanford University
     Stanford, CA 94305-4026, USA
     (650)723-1875

 09 Oct 2007: F90 version constructed from the F77 version.
              Initially used compiler option -r8, but this is nonstandard.
 15 Oct 2007: Test on Arnorm = ||Ar|| added to recognize singular systems.
 15 Oct 2007: Temporarily used real(8) everywhere.
 16 Oct 2007: Use minresDataModule to define dp = selected_real_kind(15).
              We need "use minresDataModule"
              at the beginning of modules AND inside interfaces.

              g95 compiles successfully with the following options:
   g95 -c -g -O0 -pedantic -Wall -Wextra -fbounds-check -ftrace=full minresModule.f90

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function/Subroutine Documentation

◆ minres()

subroutine, public minresmodule::minres ( integer, intent(in)  n,
external subroutine(integer, intent(in) n, real(dp), dimension(n), intent(in) x, real(dp), dimension(n), intent(out) y)  aprod,
external subroutine(integer, intent(in) n, real(dp), dimension(n), intent(in) x, real(dp), dimension(n), intent(out) y)  msolve,
real(dp), dimension(n), intent(in)  b,
real(dp), intent(in)  shift,
logical, intent(in)  checka,
logical, intent(in)  precon,
real(dp), dimension(n), intent(out)  x,
integer, intent(in)  itnlim,
integer, intent(in)  nout,
real(dp), intent(in)  rtol,
integer, intent(out)  istop,
integer, intent(out)  itn,
real(dp), intent(out)  anorm,
real(dp), intent(out)  acond,
real(dp), intent(out)  rnorm,
real(dp), intent(out)  arnorm,
real(dp), intent(out)  ynorm 
)

Solution of linear equation system.

-------------------------------------------------------------------

 MINRES  is designed to solve the system of linear equations

    Ax = b

 or the least-squares problem

    min ||Ax - b||_2,

 where A is an n by n symmetric matrix and b is a given vector.
 The matrix A may be indefinite and/or singular.

 1. If A is known to be positive definite, the Conjugate Gradient
 Method might be preferred, since it requires the same number
 of iterations as MINRES but less work per iteration.

 2. If A is indefinite but Ax = b is known to have a solution
 (e.g. if A is nonsingular), SYMMLQ might be preferred,
 since it requires the same number of iterations as MINRES
 but slightly less work per iteration.

 The matrix A is intended to be large and sparse.  It is accessed
 by means of a subroutine call of the form
 SYMMLQ development:

    call Aprod ( n, x, y )

 which must return the product y = Ax for any given vector x.


 More generally, MINRES is designed to solve the system

    (A - shift*I) x = b
 or
    min ||(A - shift*I) x - b||_2,

 where  shift  is a specified scalar value.  Again, the matrix
 (A - shift*I) may be indefinite and/or singular.
 The work per iteration is very slightly less if  shift = 0.

 Note: If  shift  is an approximate eigenvalue of  A
 and  b  is an approximate eigenvector,  x  might prove to be
 a better approximate eigenvector, as in the methods of
 inverse iteration and/or Rayleigh-quotient iteration.
 However, we're not yet sure on that -- it may be better to use SYMMLQ.

 A further option is that of preconditioning, which may reduce
 the number of iterations required.  If M = C C' is a positive
 definite matrix that is known to approximate  (A - shift*I)
 in some sense, and if systems of the form  My = x  can be
 solved efficiently, the parameters precon and Msolve may be
 used (see below).  When  precon = .true., MINRES will
 implicitly solve the system of equations

    P (A - shift*I) P' xbar  =  P b,

 i.e.             Abar xbar  =  bbar
 where                    P  =  C**(-1),
                       Abar  =  P (A - shift*I) P',
                       bbar  =  P b,

 and return the solution       x  =  P' xbar.
 The associated residual is rbar  =  bbar - Abar xbar
                                  =  P (b - (A - shift*I)x)
                                  =  P r.

 In the discussion below, eps refers to the machine precision.

 Parameters
 ----------

 n       input      The dimension of the matrix A.
 b(n)    input      The rhs vector b.
 x(n)    output     Returns the computed solution x.

 Aprod   external   A subroutine defining the matrix A.
                       call Aprod ( n, x, y )
                    must return the product y = Ax
                    without altering the vector x.

 Msolve  external   An optional subroutine defining a
                    preconditioning matrix M, which should
                    approximate (A - shift*I) in some sense.
                    M must be positive definite.

                       call Msolve( n, x, y )

                    must solve the linear system My = x
                    without altering the vector x.

                    In general, M should be chosen so that Abar has
                    clustered eigenvalues.  For example,
                    if A is positive definite, Abar would ideally
                    be close to a multiple of I.
                    If A or A - shift*I is indefinite, Abar might
                    be close to a multiple of diag( I  -I ).

 checkA  input      If checkA = .true., an extra call of Aprod will
                    be used to check if A is symmetric.  Also,
                    if precon = .true., an extra call of Msolve
                    will be used to check if M is symmetric.

 precon  input      If precon = .true., preconditioning will
                    be invoked.  Otherwise, subroutine Msolve
                    will not be referenced; in this case the
                    actual parameter corresponding to Msolve may
                    be the same as that corresponding to Aprod.

 shift   input      Should be zero if the system Ax = b is to be
                    solved.  Otherwise, it could be an
                    approximation to an eigenvalue of A, such as
                    the Rayleigh quotient b'Ab / (b'b)
                    corresponding to the vector b.
                    If b is sufficiently like an eigenvector
                    corresponding to an eigenvalue near shift,
                    then the computed x may have very large
                    components.  When normalized, x may be
                    closer to an eigenvector than b.

 nout    input      A file number.
                    If nout > 0, a summary of the iterations
                    will be printed on unit nout.

 itnlim  input      An upper limit on the number of iterations.

 rtol    input      A user-specified tolerance.  MINRES terminates
                    if it appears that norm(rbar) is smaller than
                       rtol * norm(Abar) * norm(xbar),
                    where rbar is the transformed residual vector,
                       rbar = bbar - Abar xbar.

                    If shift = 0 and precon = .false., MINRES
                    terminates if norm(b - A*x) is smaller than
                       rtol * norm(A) * norm(x).

 istop   output     An integer giving the reason for termination...

          -1        beta2 = 0 in the Lanczos iteration; i.e. the
                    second Lanczos vector is zero.  This means the
                    rhs is very special.
                    If there is no preconditioner, b is an
                    eigenvector of A.
                    Otherwise (if precon is true), let My = b.
                    If shift is zero, y is a solution of the
                    generalized eigenvalue problem Ay = lambda My,
                    with lambda = alpha1 from the Lanczos vectors.

                    In general, (A - shift*I)x = b
                    has the solution         x = (1/alpha1) y
                    where My = b.

           0        b = 0, so the exact solution is x = 0.
                    No iterations were performed.

           1        Norm(rbar) appears to be less than
                    the value  rtol * norm(Abar) * norm(xbar).
                    The solution in  x  should be acceptable.

           2        Norm(rbar) appears to be less than
                    the value  eps * norm(Abar) * norm(xbar).
                    This means that the residual is as small as
                    seems reasonable on this machine.

           3        Norm(Abar) * norm(xbar) exceeds norm(b)/eps,
                    which should indicate that x has essentially
                    converged to an eigenvector of A
                    corresponding to the eigenvalue shift.

           4        Acond (see below) has exceeded 0.1/eps, so
                    the matrix Abar must be very ill-conditioned.
                    x may not contain an acceptable solution.

           5        The iteration limit was reached before any of
                    the previous criteria were satisfied.

           6        The matrix defined by Aprod does not appear
                    to be symmetric.
                    For certain vectors y = Av and r = Ay, the
                    products y'y and r'v differ significantly.

           7        The matrix defined by Msolve does not appear
                    to be symmetric.
                    For vectors satisfying My = v and Mr = y, the
                    products y'y and r'v differ significantly.

           8        An inner product of the form  x' M**(-1) x
                    was not positive, so the preconditioning matrix
                    M does not appear to be positive definite.

                    If istop >= 5, the final x may not be an
                    acceptable solution.

 itn     output     The number of iterations performed.

 Anorm   output     An estimate of the norm of the matrix operator
                    Abar = P (A - shift*I) P',   where P = C**(-1).

 Acond   output     An estimate of the condition of Abar above.
                    This will usually be a substantial
                    under-estimate of the true condition.

 rnorm   output     An estimate of the norm of the final
                    transformed residual vector,
                       P (b  -  (A - shift*I) x).

 ynorm   output     An estimate of the norm of xbar.
                    This is sqrt( x'Mx ).  If precon is false,
                    ynorm is an estimate of norm(x).
-------------------------------------------------------------------
 MINRES is an implementation of the algorithm described in
 the following reference:

 C. C. Paige and M. A. Saunders (1975),
 Solution of sparse indefinite systems of linear equations,
 SIAM J. Numer. Anal. 12(4), pp. 617-629.
-------------------------------------------------------------------


 MINRES development:
    1972: First version, similar to original SYMMLQ.
          Later lost @#%*!!
    Oct 1995: Tried to reconstruct MINRES from
              1995 version of SYMMLQ.
 30 May 1999: Need to make it more like LSQR.
              In middle of major overhaul.
 19 Jul 2003: Next attempt to reconstruct MINRES.
              Seems to need two vectors more than SYMMLQ.  (w1, w2)
              Lanczos is now at the top of the loop,
              so the operator Aprod is called in just one place
              (not counting the initial check for symmetry).
 22 Jul 2003: Success at last.  Preconditioning also works.
              minres.f added to http://www.stanford.edu/group/SOL/.

 16 Oct 2007: Added a stopping rule for singular systems,
              as derived in Sou-Cheng Choi's PhD thesis.
              Note that ||Ar|| small => r is a null vector for A.
              Subroutine minrestest2 in minresTestModule.f90
              tests this option.  (NB: Not yet working.)
-------------------------------------------------------------------

Definition at line 294 of file minresModule.f90.

297
298 integer, intent(in) :: n, itnlim, nout
299 logical, intent(in) :: checkA, precon
300 real(dp), intent(in) :: b(n)
301 real(dp), intent(in) :: shift, rtol
302 real(dp), intent(out) :: x(n)
303 integer, intent(out) :: istop, itn
304 real(dp), intent(out) :: Anorm, Acond, rnorm, Arnorm, ynorm
305
306 interface
307 subroutine aprod (n,x,y) ! y := A*x
309 integer, intent(in) :: n
310 real(dp), intent(in) :: x(n)
311 real(dp), intent(out) :: y(n)
312 end subroutine aprod
313
314 subroutine msolve(n,x,y) ! Solve M*y = x
316 integer, intent(in) :: n
317 real(dp), intent(in) :: x(n)
318 real(dp), intent(out) :: y(n)
319 end subroutine msolve
320 end interface
321
322! Local arrays and variables
323 real(dp) :: r1(n), r2(n), v(n), w(n), w1(n), w2(n), y(n)
324 real(dp) :: alfa , beta , beta1 , cs , &
325 dbar , delta , denom , diag , &
326 eps , epsa , epsln , epsr , epsx , &
327 gamma , gbar , gmax , gmin , &
328 oldb , oldeps, qrnorm, phi , phibar, &
329 rhs1 , rhs2 , rnorml, rootl , &
330 Arnorml, relArnorml, &
331 s , sn , t , tnorm2, ynorm2, z
332 integer :: i
333 logical :: debug, prnt
334
335 ! Local constants
336 real(dp), parameter :: zero = 0.0, one = 1.0
337 real(dp), parameter :: ten = 10.0
338 character(len=*), parameter :: enter = ' Enter MINRES. '
339 character(len=*), parameter :: exitt = ' Exit MINRES. '
340 character(len=*), parameter :: msg(-1:8) = &
341 (/ 'beta2 = 0. If M = I, b and x are eigenvectors of A', & ! -1
342 'beta1 = 0. The exact solution is x = 0 ', & ! 0
343 'Requested accuracy achieved, as determined by rtol ', & ! 1
344 'Reasonable accuracy achieved, given eps ', & ! 2
345 'x has converged to an eigenvector ', & ! 3
346 'Acond has exceeded 0.1/eps ', & ! 4
347 'The iteration limit was reached ', & ! 5
348 'Aprod does not define a symmetric matrix ', & ! 6
349 'Msolve does not define a symmetric matrix ', & ! 7
350 'Msolve does not define a pos-def preconditioner ' /) ! 8
351 !-------------------------------------------------------------------
352
353 intrinsic :: abs, dot_product, epsilon, min, max, sqrt
354
355 ! Print heading and initialize.
356
357 debug = .false.
358 eps = epsilon(eps)
359 if (nout > 0) then
360 write(nout, 1000) enter, n, checka, precon, itnlim, rtol, shift
361 end if
362 istop = 0
363 itn = 0
364 anorm = zero
365 acond = zero
366 rnorm = zero
367 ynorm = zero
368 x(1:n) = zero
369 arnorml = zero
370 gmin = zero
371 gmax = zero
372
373 !-------------------------------------------------------------------
374 ! Set up y and v for the first Lanczos vector v1.
375 ! y = beta1 P' v1, where P = C**(-1).
376 ! v is really P' v1.
377 !-------------------------------------------------------------------
378 y = b
379 r1 = b
380 if ( precon ) call msolve( n, b, y )
381 beta1 = dot_product(b,y)
382
383 if (beta1 < zero) then ! M must be indefinite.
384 istop = 8
385 go to 900
386 end if
387
388 if (beta1 == zero) then ! b = 0 exactly. Stop with x = 0.
389 istop = 0
390 go to 900
391 end if
392
393 beta1 = sqrt( beta1 ) ! Normalize y to get v1 later.
394
395 !-------------------------------------------------------------------
396 ! See if Msolve is symmetric.
397 !-------------------------------------------------------------------
398 if (checka .and. precon) then
399 call msolve( n, y, r2 )
400 s = dot_product(y ,y )
401 t = dot_product(r1,r2)
402 z = abs(s - t)
403 epsa = (s + eps) * eps**0.33333
404 if (z > epsa) then
405 istop = 7
406 go to 900
407 end if
408 end if
409
410 !-------------------------------------------------------------------
411 ! See if Aprod is symmetric. Initialize Arnorm.
412 !-------------------------------------------------------------------
413 if (checka) then
414 call aprod ( n, y, w )
415 call aprod ( n, w, r2 )
416 s = dot_product(w,w )
417 t = dot_product(y,r2)
418 z = abs(s - t)
419 epsa = (s + eps) * eps**0.33333
420 if (z > epsa) then
421 istop = 6
422 go to 900
423 end if
424 arnorml = sqrt(s);
425 else
426 call aprod ( n, y, w )
427 arnorml = sqrt( dot_product(w,w) )
428 end if
429
430 !-------------------------------------------------------------------
431 ! Initialize other quantities.
432 !-------------------------------------------------------------------
433 oldb = zero
434 beta = beta1
435 dbar = zero
436 epsln = zero
437 qrnorm = beta1
438 phibar = beta1
439 rhs1 = beta1
440 rhs2 = zero
441 tnorm2 = zero
442 ynorm2 = zero
443 cs = - one
444 sn = zero
445 w(1:n) = zero
446 w2(1:n)= zero
447 r2(1:n)= r1
448
449 if (debug) then
450 write(*,*) ' '
451 write(*,*) 'b ', b
452 write(*,*) 'beta ', beta
453 write(*,*) ' '
454 end if
455
456 !===================================================================
457 ! Main iteration loop.
458 !===================================================================
459 do
460 itn = itn + 1 ! k = itn = 1 first time through
461
462 !----------------------------------------------------------------
463 ! Obtain quantities for the next Lanczos vector vk+1, k = 1, 2,...
464 ! The general iteration is similar to the case k = 1 with v0 = 0:
465 !
466 ! p1 = Operator * v1 - beta1 * v0,
467 ! alpha1 = v1'p1,
468 ! q2 = p2 - alpha1 * v1,
469 ! beta2^2 = q2'q2,
470 ! v2 = (1/beta2) q2.
471 !
472 ! Again, y = betak P vk, where P = C**(-1).
473 ! .... more description needed.
474 !----------------------------------------------------------------
475 s = one / beta ! Normalize previous vector (in y).
476 v = s*y(1:n) ! v = vk if P = I
477
478 call aprod ( n, v, y )
479 y = y - shift*v ! call daxpy ( n, (- shift), v, 1, y, 1 )
480 if (itn >= 2) then
481 y = y - (beta/oldb)*r1 ! call daxpy ( n, (- beta/oldb), r1, 1, y, 1 )
482 end if
483
484 alfa = dot_product(v,y) ! alphak
485 y = y - (alfa/beta)*r2 ! call daxpy ( n, (- alfa/beta), r2, 1, y, 1 )
486 r1 = r2
487 r2 = y
488 if ( precon ) call msolve( n, r2, y )
489
490 oldb = beta ! oldb = betak
491 beta = dot_product(r2,y) ! beta = betak+1^2
492 if (beta < zero) then
493 istop = 6
494 go to 900
495 end if
496
497 beta = sqrt( beta ) ! beta = betak+1
498 tnorm2 = tnorm2 + alfa**2 + oldb**2 + beta**2
499
500 if (itn == 1) then ! Initialize a few things.
501 if (beta/beta1 <= ten*eps) then ! beta2 = 0 or ~ 0.
502 istop = -1 ! Terminate later.
503 end if
504 !tnorm2 = alfa**2
505 gmax = abs( alfa ) ! alpha1
506 gmin = gmax ! alpha1
507 end if
508
509 ! Apply previous rotation Qk-1 to get
510 ! [deltak epslnk+1] = [cs sn][dbark 0 ]
511 ! [gbar k dbar k+1] [sn -cs][alfak betak+1].
512
513 oldeps = epsln
514 delta = cs * dbar + sn * alfa ! delta1 = 0 deltak
515 gbar = sn * dbar - cs * alfa ! gbar 1 = alfa1 gbar k
516 epsln = sn * beta ! epsln2 = 0 epslnk+1
517 dbar = - cs * beta ! dbar 2 = beta2 dbar k+1
518
519 ! Compute the next plane rotation Qk
520
521 gamma = sqrt( gbar**2 + beta**2 ) ! gammak
522 cs = gbar / gamma ! ck
523 sn = beta / gamma ! sk
524 phi = cs * phibar ! phik
525 phibar = sn * phibar ! phibark+1
526
527 if (debug) then
528 write(*,*) ' '
529 write(*,*) 'v ', v
530 write(*,*) 'alfa ', alfa
531 write(*,*) 'beta ', beta
532 write(*,*) 'gamma', gamma
533 write(*,*) 'delta', delta
534 write(*,*) 'gbar ', gbar
535 write(*,*) 'epsln', epsln
536 write(*,*) 'dbar ', dbar
537 write(*,*) 'phi ', phi
538 write(*,*) 'phiba', phibar
539 write(*,*) ' '
540 end if
541
542 ! Update x.
543
544 denom = one/gamma
545
546 do i = 1, n
547 w1(i) = w2(i)
548 w2(i) = w(i)
549 w(i) = ( v(i) - oldeps*w1(i) - delta*w2(i) ) * denom
550 x(i) = x(i) + phi * w(i)
551 end do
552
553 ! Go round again.
554
555 gmax = max( gmax, gamma )
556 gmin = min( gmin, gamma )
557 z = rhs1 / gamma
558 ynorm2 = z**2 + ynorm2
559 rhs1 = rhs2 - delta * z
560 rhs2 = - epsln * z
561
562 ! Estimate various norms and test for convergence.
563
564 anorm = sqrt( tnorm2 )
565 ynorm = sqrt( ynorm2 )
566 epsa = anorm * eps
567 epsx = anorm * ynorm * eps
568 epsr = anorm * ynorm * rtol
569 diag = gbar
570 if (diag == zero) diag = epsa
571
572 qrnorm = phibar
573 rnorml = rnorm
574 rnorm = qrnorm
575 rootl = sqrt( gbar**2 +dbar**2 ) ! norm([gbar; dbar]);
576 arnorml = rnorml*rootl ! ||A r_{k-1} ||
577 relarnorml = rootl / anorm; ! ||Ar|| / (||A|| ||r||)
578 !relArnorml = Arnorml / Anorm; ! ||Ar|| / ||A||
579
580 ! Estimate cond(A).
581 ! In this version we look at the diagonals of R in the
582 ! factorization of the lower Hessenberg matrix, Q * H = R,
583 ! where H is the tridiagonal matrix from Lanczos with one
584 ! extra row, beta(k+1) e_k^T.
585
586 acond = gmax / gmin
587
588 ! See if any of the stopping criteria are satisfied.
589 ! In rare cases, istop is already -1 from above (Abar = const*I).
590
591 if (istop == 0) then
592 if (itn >= itnlim ) istop = 5
593 if (acond >= 0.1d+0/eps) istop = 4
594 if (epsx >= beta1 ) istop = 3
595 ! original
596 !if (qrnorm <= epsx .or. relArnorml <= epsx) istop = 2
597 !if (qrnorm <= epsr .or. relArnorml <= epsr) istop = 1
598 ! C. Kleinwort, DESY, 131002
599 if (qrnorm <= epsx .or. relarnorml <= eps) istop = 2
600 if (qrnorm <= epsr .or. relarnorml <= rtol) istop = 1
601 end if
602
603
604 ! See if it is time to print something.
605
606 if (nout > 0) then
607 prnt = .false.
608 if (n <= 40 ) prnt = .true.
609 if (itn <= 10 ) prnt = .true.
610 if (itn >= itnlim - 10) prnt = .true.
611 if (mod(itn,10) == 0) prnt = .true.
612 if (qrnorm <= ten * epsx) prnt = .true.
613 if (qrnorm <= ten * epsr) prnt = .true.
614 if (relarnorml<= ten*epsx) prnt = .true.
615 if (relarnorml<= ten*epsr) prnt = .true.
616 if (acond >= 1.0d-2/eps ) prnt = .true.
617 if (istop /= 0 ) prnt = .true.
618
619 if ( prnt ) then
620 if ( itn == 1) write(nout, 1200)
621 write(nout, 1300) itn, x(1), qrnorm, anorm, acond
622 if (mod(itn,10) == 0) write(nout, 1500)
623 end if
624 end if
625 if (istop /= 0) exit
626
627 end do
628 !===================================================================
629 ! End of iteration loop.
630 !===================================================================
631
632 ! Display final status.
633
634900 arnorm = arnorml
635 if (nout > 0) then
636 write(nout, 2000) exitt, istop, itn, &
637 exitt, anorm, acond, &
638 exitt, rnorm, ynorm, arnorm
639 write(nout, 3000) exitt, msg(istop)
640 end if
641
642 return
643
644 1000 format(// 1p, a, 5x, 'Solution of symmetric Ax = b' &
645 / ' n =', i7, 5x, 'checkA =', l4, 12x, &
646 'precon =', l4 &
647 / ' itnlim =', i7, 5x, 'rtol =', e11.2, 5x, &
648 'shift =', e23.14)
649 1200 format(// 5x, 'itn', 8x, 'x(1)', 10x, &
650 'norm(r)', 3x, 'norm(A)', 3x, 'cond(A)')
651 1300 format(1p, i8, e19.10, 3e10.2)
652 1500 format(1x)
653 2000 format(/ 1p, a, 5x, 'istop =', i3, 14x, 'itn =', i8 &
654 / a, 5x, 'Anorm =', e12.4, 5x, 'Acond =', e12.4 &
655 / a, 5x, 'rnorm =', e12.4, 5x, 'ynorm =', e12.4, 5x, 'Arnorml =', e12.4)
656 3000 format( a, 5x, a )
657
subroutine precon(p, n, c, cu, a, s, nrkd)
Constrained preconditioner, decomposition.
Definition mpnum.f90:2172
Defines real(kind=dp) and a few constants for use in other modules.