function [x, flag, relres, iter, resvec, lsvec] = lsqr(varargin)
%LSQR   lsqr Method for codistributed array.
%   X = LSQR(A,B)
%   X = LSQR(A,B)
%   X = LSQR(A,B,TOL)
%   X = LSQR(A,B,TOL,MAXIT)
%   X = LSQR(A,B,TOL,MAXIT,M)
%   X = LSQR(A,B,TOL,MAXIT,M1,M2)
%   X = LSQR(A,B,TOL,MAXIT,M1,M2,X0)
%   [X,FLAG] = LSQR(A,B,...)
%   [X,FLAG,RELRES] = LSQR(A,B,...)
%   [X,FLAG,RELRES,ITER] = LSQR(A,B,...)
%   [X,FLAG,RELRES,ITER,RESVEC] = LSQR(A,B,...)
%      
%   Note that B must be a non-sparse column vector.
%   
%   If M1 is a function it is applied independently to each row.
%   
%   Example:
%   Using LSQR to solve a large system of codistributed array data:
%   spmd
%       n = 1e6; 
%       dOnes = codistributed.ones(n,1); 
%       dA = spdiags([-2*dOnes 4*dOnes -dOnes],-1:1,n,n);
%       db = full(sum(dA,2)); 
%       tol = 1e-8; 
%       maxit = 50; 
%       
%       dX = LSQR(dA,db,tol,maxit)
%   end
%   
%   See also LSQR, CODISTRIBUTED.


%   Copyright 1984-2020 The MathWorks, Inc.

% Ensure that only the data inputs (args 1,2,5,6,7) are distributed
isData = [1 1 0 0 1 1 1];
varargin = distributedutil.CodistParser.prepareSolverInputs(varargin, isData);

% Check for an acceptable number of input arguments
if nargin < 2
    error(message('MATLAB:lsqr:NotEnoughInputs'));
end
[A, b, tol, maxit, M1, M2, x0] = iterCheckArgs(varargin{:});

% Check for all zero right hand side vector => all zero solution
isBzero = (nnz(b) == 0);           % is rhs vector, b, all zeros
if (isBzero)                       % if rhs vector is all zeros
    x = zeros(size(x0), 'like', b);% then  solution is all zeros
    flag = 0;                      % a valid solution has been obtained
    relres = 0;                    % the relative residual is actually 0/0
    iter = 0;                      % no iterations need be performed
    resvec = 0;                    % resvec(1) = norm(b-A*x) = norm(0)
    lsvec = zeros(0,1);            % no estimate for norm(A*inv(M),'fro') yet 
    if (nargout < 2)
        parallel.internal.flowthrough.itermsg('lsqr', tol, maxit, 0, flag, iter, NaN);
    end
    return
end

[localA, b, M1, M2, x0] = iterSetupArgs(A, b, M1, M2, x0);
if isa(x0, 'codistributed')
    workCodistrX = getCodistributor(x0);
else
    workCodistrX = getCodistributor(b);
end
emptyMaxit = ~(nargin>=4 && ~isempty(varargin{4}));

[localX, flag, relres, iter, resvec, lsvec] = hLsqrImpl(workCodistrX, ...
    localA, b, tol, maxit, M1, M2, x0, emptyMaxit);

% only display a message if the output flag is not used
if nargout < 2
    parallel.internal.flowthrough.itermsg('lsqr', tol, maxit, length(resvec),...
        flag, iter, relres);
end

% construct distributed result
x = codistributed.pDoBuildFromLocalPart(localX, workCodistrX);
end

    