function [isMeshGrid, isNdGrid, exception] = checkGrid(varargin)
%CHECKGRID determines whether the inputs are a meshgrid or ndgrod.
%   [ISMESHGRID, ISNDGRID, EXCEPTION] = CHECKGRID(X1,X2,X3,...Xn, V) for a grid
%   defined by X1,X2,X3,...Xn and corresponding grid point values V checks
%   whether it is a meshgrid or an ndgrid. It first checks that the input
%   arrays are the same size as the values array.  It works with either
%   replicated or distributed inputs.  This function is a prerequisite for
%   calling getGridVectors.  The exception return can be either
%   'DimensionMismatch' if the input arrays have different numbers of
%   dimensions or 'SizeMismatch' if the input arrays differ in size from V.

%   Copyright 2021 The MathWorks, Inc.

n1 = nargin-1;
V = varargin{end};
isMeshGrid = false;
isNdGrid = false;
exception = '';

% Make sure grid arrays are the same size.
X = varargin(1:n1);
ndimXi = cellfun(@ndims, X);
if n1 ~= ndimXi(1) % Wrong number of arguments
    exception = 'ArgMismatch';
    return
end
if any(ndimXi ~= ndimXi(1))  % One of the X's has a different number of dimensions
    exception = 'DimensionMismatch';
    return
end
sizeV = size(V);
equalSize = cellfun(@(x) all(size(x) == sizeV), X);
if ~all(equalSize)
    exception = 'SizeMismatch';
    return
end
clx = cellfun(@(x) string(underlyingType(x)), X);
if any(clx ~= clx{1})
    exception = 'TypeMismatch';
    return
end

% Do checking.  The checks array should have nonzeros only on the diagonal
% if the inputs define an ndgrid.  If it is a meshgrid, the checks array
% would be diagonal if the first two rows are interchanged.
[vec, dim] = meshgrid(1:n1, 1:n1);
checks = arrayfun(@(x, y) iCheckDiff(X{x}, y), vec, dim);
isNdGrid = isdiag(real(checks));
checks([1, 2], :) = checks([2, 1], :); % Swap first two rows for meshgrid check.
isMeshGrid = isdiag(real(checks));
end

function tf = iCheckDiff(X, dim)
% ICHECKDIFF calculates the diff of a (possibly distributed) matrix
% and checks whether any of the diff values is nonzero.  It returns true if
% the array X has varying values along dimension dim.

diffX = diff(X, 1, dim);
tf = gather(any(diffX, 'all'));
end
