function [x, r_norms] = tgcr(M,b,tol,maxiters) 
% Generalized conjugate residual method for solving Mx = b
% INPUTS
% M - matrix
% b - right hand side
% tol - convergence tolerance, terminate on norm(b - Mx) < tol * norm(b)
% maxiters - maximum number of iterations before giving up 
% OUTPUTS
% x - computed solution, returns null if no convergence
% r_norms - the scaled norm of the residual at each iteration (r_norms(1) = 1)

% Generate the initial guess for x (zero)
x = zeros(size(b));

% Set the initial residual to b - Mx^0 = b
r = b;

% Determine the norm of the initial residual
r_norms(1) = norm(r,2);

for iter = 1:maxiters
% Use the residual as the first guess for the new
% search direction and multiply by M
  p(:,iter) = r; 
  Mp(:, iter) = M * p(:,iter);
  
% Make the new Mp vector orthogonal to the previous Mp vectors,
% and the p vectors M^TM orthogonal to the previous p vectors
  for j=1:iter-1, 
    beta = Mp(:,iter)' * Mp(:,j); 
    p(:,iter) = p(:,iter) - beta * p(:,j); 
    Mp(:,iter) = Mp(:,iter) - beta * Mp(:,j);
  end; 

% Make the orthogonal Mp vector of unit length, and scale the
% p vector so that M * p  is of unit length
  norm_Mp = norm(Mp(:,iter),2);
  Mp(:,iter) = Mp(:,iter)/norm_Mp;
  p(:,iter) = p(:,iter)/norm_Mp;

% Determine the optimal amount to change x in the p direction
% by projecting r onto Mp
  alpha = r' * Mp(:,iter);

% Update x and r
  x = x + alpha * p(:,iter); 
  r = r - alpha * Mp(:,iter); 

% Save the norm of r
  r_norms(iter+1) = norm(r,2); 

% Print the norm during the iteration 
% fprintf('||r||=%g i=%d\n', norms(iter+1), iter+1);

% Check convergence.
  if r_norms(iter+1) < (tol * r_norms(1))
    break; 
  end; 
end;

% Notify user of convergence
if r_norms(iter+1) > (tol * r_norms(1))
  fprintf(1, 'GCR NONCONVERGENCE!!!\n');
  x = [];
else 
  fprintf(1, 'GCR converged in %d iterations\n', iter);
end; 

% Scale the r_norms with respect to the initial residual norm
r_norms = r_norms / r_norms(1);


