function dZ = internal_maxpoolBackward(dZ, X, Z, poolSize, padding, stride)
% This function is undocumented and will change in a future release.

%   Copyright 2019-2021 The MathWorks, Inc.

if ~isreal(dZ)
     error(message('deep:dlarray:ComplexGradientOutput', 'maxpool'));
end

% Ensure all inputs have the same data type
[dZ, X, Z] = nnet.internal.cnngpu.castToSuperiorFloat(dZ, X, Z);

% Convert padding to values expected by the builtin
padStart = padding(1:2:end);
padEnd = padding(2:2:end);

% Pad the input if necessary 
symmetric = all(padStart == padEnd);
if ~symmetric || iIsInputSizeLessThanPoolSize(X, poolSize)
    linearIdxOrder = 1:numel(padding)/2;
    X = nnet.internal.cnnhost.padding.padArray(X, padding, linearIdxOrder, -Inf);
    padStart(:) = 0;
    padEnd(:) = 0;
    % Call the builtin
    dZ = nnet.internal.cnngpu.poolingMaxBackwardND(Z, dZ, X, poolSize, padStart, padEnd, stride);
    % Unpad the output
    dZ = nnet.internal.cnnhost.padding.unpadArray(dZ, padding);
else 
    % Call the builtin
    dZ = nnet.internal.cnngpu.poolingMaxBackwardND(Z, dZ, X, poolSize, padStart, padEnd, stride);
end

end

function tf = iIsInputSizeLessThanPoolSize(X, poolSize)
tf = false;
dims = length(poolSize);
for i=1:dims
    tf = tf | (size(X,i) < poolSize(i));
end
end

