module smallsolver   
  implicit none
  logical, parameter, private  :: T = .true., F = .false.
  logical             private  :: forget
  contains
  subroutine solver( oper, solv, x, dat, niter, x0, res)
    optional                                 :: x0, res   
    interface  
      integer function oper( adj, add, x, dat)
        logical, intent (in) :: adj, add
        real, dimension (:)  :: x, dat
      end function 
      integer function solv( forget, x, g, rr, gg)
        logical             :: forget
        real, dimension (:) :: x, g, rr, gg
      end function
    end interface 
    real,    dimension (:),   intent (in)  :: dat, x0     
    ! data, initial
    real,    dimension (:),   intent (out) :: x, res      
    ! solution, residual
    integer,                  intent (in)  :: niter       
    ! iterations
    real, dimension (size (x))             :: g           ! gradient
    real, dimension (size (dat))           :: rr, gg      
    ! residual, conj grad
    integer                                :: i, stat
    rr = - dat
    if ( present( x0)) then
      stat = oper( F, T, x0, rr)                        
      ! rr <- F x0 - dat
      x = x0                                            
      ! start with x0
    else
      x = 0.                                            
      ! start with zero
    end if 
    forget = F
    do i = 1, niter   
      stat = oper( T, F, g, rr)                          
      ! g  <- F' rr
      stat = oper( F, F, g, gg)                          ! gg <- F  g
      stat = solv( forget, x, g, rr, gg)                      
      ! step in x and rr
    end do 
    if ( present( res)) then
      res = rr
    end if
  end subroutine 
end module 
