function varargout = collate(varargin)
%COLLATE Concatenate cell arrays
%
%   [Y1,...,YN] = COLLATE(X1,...,XN) concatenates input cell arrays
%   X1,...,XN into numeric arrays Y1,...,YN. Each cell in input cell array
%   Xi must contain a numeric array with the same size as all other cells
%   in input Xi. Nested cell arrays are not supported.
%
%   The dimension along which numeric arrays are concatenated depends on
%   the content of the cells. If the cells contain scalars or row vectors,
%   they are concatenated along the first dimension. Column vectors are
%   concatenated along the second dimension. Otherwise, numeric arrays are
%   concatenated along the M+1 dimension, where M is the number of
%   dimensions of the numeric array inside the cell.
%
%   Example
%       % Create a 1000x1 cell array containing 28x28 double arrays.
%       X = squeeze(num2cell(ones(28,28,1000), [1 2]));
%
%       % Use collate to obtain a 28x28x1000 double array.
%       Y = minibatchqueue.collate(X);
%

%   Copyright 2020 The MathWorks, Inc.

if nargout>nargin
    error(message('deep:minibatchqueue:CollateTooManyOutputs'))
end

varargout = cell(1,nargout);

for i = 1:nargout
    currentData = varargin{i};
    if ~iscell(currentData) || isempty(currentData)
        error(message('deep:minibatchqueue:CollateInvalidInput',i))
    end
    % Concatenate
    catDim = iGetCollationDimensions(currentData{1});
    try
        varargout{i} = cat(catDim,currentData{:});
    catch caughtException
        if caughtException.identifier == "MATLAB:catenate:dimensionMismatch"
            % Reformulate a failed concatenation
            e = MException(message('deep:minibatchqueue:CollateNotConsistent',i));
            throw(e);
        else
            throw(caughtException);
        end
    end
end
end

function collationDimension = iGetCollationDimensions(array)
% getCollationDimensions  Return the dimensions that will be used for
% concatenation

% Find the concatenation dimension
if isscalar(array) || isrow(array)
    collationDimension = 1;
elseif iscolumn(array)
    collationDimension = 2;
else
    collationDimension = ndims(array)+1;
end
end
