function varargout = scalaNonSymmetricEig(A, isvec, balance)
% SCALANONSYMMETRICEIG  ScaLAPACK non-symmetric eigenvalue solver
% Compute eigenvalues and optionally eigenvectors of codistributed input A.
%
% The boolean flag 'isvec' is true if the user provided the input flag
% 'vector' or by default for the single output case. It is false if the
% user provided the input flag 'matrix' or by default for the two or three
% output case.
% The boolean flag 'balance' is false if the
% user provides 'nobalance' as input flag amd true otherwise.

%   Copyright 2018-2022 The MathWorks, Inc.

nargoutchk(0, 3);

% When there are no output arguments, the function should still return
% the eigenvalues.
numOutputs = max(1, nargout);

% Redistribute input if not 2dbc or if WorkerGrid does not fulfill nprow==1
distA = getCodistributor(A);
if ~isa(distA, 'codistributor2dbc') || distA.WorkerGrid(1)>1
    % Redistribute A with non-default 2dbc WorkerGrid such that nprow==1 (g2603210)
    A = redistribute(A, codistributor2dbc([1 spmdSize]));

    % Extract new completed codistributor
    distA = getCodistributor(A);
end

localA = hGetLocalPartWithCorrectComplexity(A);
lbgrid = distA.WorkerGrid;

% Create array descriptor required by ScaLAPACK
descA = arraydescriptor(distA);

% Because of g1871484, we complexify the input and always go through the complex C++ code path.
localA = complex(localA);

% Output from ScalaPack is ordered with eigenvalues first, then eigenvectors.
[eigOut{1:numOutputs}] = parallel.internal.codistextern.denseNonSymmetricEig(...
    localA, descA, lbgrid(1), lbgrid(2), distA.Orientation, balance);
  
% We always need the eigenvalues.
% The ScaLAPACK output is replicated but we want codistributed output.
eigenVals = codistributed.pConstructFromReplicated( eigOut{1}, codistributor1d(1) );
if ~isvec
    eigenVals = diag(eigenVals);
end

if numOutputs == 1
    varargout{1} = eigenVals;
else 
    % When there are multiple output arguments, they need to be rearranged.  The
    % ScaLAPACK ordering is [evals, right-evecs, left-evecs] while MATLAB
    % expects [right-evecs, evals, left-evecs]
    REV = codistributed.pDoBuildFromLocalPart(eigOut{2}, distA);
    varargout{1} = redistribute(REV, codistributor1d());
    varargout{2} = eigenVals;
    if numOutputs == 3
        LEV = codistributed.pDoBuildFromLocalPart(eigOut{3}, distA);
        varargout{3} = redistribute(LEV, codistributor1d());
    end
end
end
   