module cdstep_mod use ddot_mod use llist_mod implicit none type (list), private :: steps contains subroutine cdstep_init () steps = llist_init () end subroutine cdstep_init subroutine cdstep_close () call llist_close (steps) end subroutine cdstep_close function cdstep (forget, x, g, rr, gg) result (stat) integer :: stat real, dimension(:) :: x, g, rr, gg logical :: forget real, dimension(:), pointer :: s, ss, si double precision :: alpha, beta double precision, parameter :: eps = 1.d-30 integer :: i, n, nm, nr nm = size (x) nr = size (rr) allocate (s (nm + nr)) ; ss => s (: nr) s (nr + 1:) = g ; ss = gg call llist_rewind (steps) n = llist_depth (steps) do i = 1, n call llist_down (steps, si, beta) alpha = ddot (gg, si (:nr)) / beta s = s - alpha * si end do beta = ddot (ss, ss) if (beta > eps) then call llist_add (steps, s, beta) if (forget) call llist_chop (steps) alpha = - ddot (rr, ss) / beta x = x + alpha * s (nr+1:) rr = rr + alpha * ss end if stat = 0 end function cdstep subroutine cdstep_diag(res) real, dimension (:), intent (out) :: res integer :: i, nr real, dimension (:), pointer :: s, ss double precision :: sn res = 0. ; nr = size (res) call llist_rewind (steps) do i = 1, llist_depth (steps) call llist_down (steps, s, sn) ; ss => s (:nr) res = res + dprod (ss, ss) / sn end do end subroutine cdstep_diag subroutine cdstep_mat (res) real, dimension (:,:), intent (out) :: res integer :: i, j, nr real, dimension (:), pointer :: s, ss double precision :: sn res = 0. ; nr = size (res, 1) call llist_rewind (steps) do i = 1, llist_depth (steps) call llist_down (steps, s, sn) ; ss => s (:nr) do j = 1, nr res (:,j) = res (:,j) + dprod (ss (j), ss) / sn end do end do end subroutine cdstep_mat end module cdstep_mod