function [dX,dweights,dbias] = internal_dlconvBackward(dZ,X,weights,paddingSize,stride,dilation,numGroups,flags)
% This function is undocumented and will change in a future release.

% Backward method for d-dimensional convolution on the CPU.
%
% Inputs:
%   dZ          = O1 x O2 x...x Od x  K  x N array.
%   X           = N1 x N2 x...x Nd x  C  x N array.
%   weights     = M1 x M2 x...x Md x(C/G)x K array. G is the number of
%                 groups and G must divide C and K.
%   paddingSize = [L1,H1,...,Ld,Hd] where Li and Hi are the start and end
%                 padding sizes in the ith dimension.
%   stride      = [s1,...,sd] where si is stride in the ith dimension.
%   dilation    = [c1,...,cd] where ci is dilation in the ith dimension.
%   numGroups   = number of groups G.
%   flags       = logical vector indicating which outputs to compute.
%
% Outputs:
%   dX          = N1 x N2 x...x Nd x  C  x N array.
%   dweights    = M1 x M2 x...x Md x(C/G)x K array.
%   dbias       = 1  x 1  x...x 1  x  K      array.

%   Copyright 2019-2020 The MathWorks, Inc.

if nargin < 8
    flags = true(3,1);
end

dXNeeded = flags(1);
dweightsNeeded = flags(2);
dbiasNeeded = flags(3);

dX = [];
dweights = [];
dbias = [];

% Mixed precision is not supported by builtin.
[dZ, X, weights] = nnet.internal.cnnhost.castToSuperiorFloat(dZ, X, weights);

d = numel(stride);
[paddingStart, paddingEnd] = iConvertPaddingToHostAPIformat(paddingSize);
numFilters = size(weights,d+2);
filterGrouping = iConvertNumGroupsToHostAPIformat(numFilters,numGroups);

if dXNeeded
    imageSize = size(X,1:d);
    dX = builtin('_batchconvBackwardData', ...
        imageSize, dZ, weights, ...
        [paddingStart, paddingEnd], ...
        stride, dilation, filterGrouping);
end

if dweightsNeeded
    weightsSize = size(weights,1:d);
    dweights = builtin('_batchconvBackwardFilter', ...
        weightsSize, dZ, X, ...
        [paddingStart, paddingEnd],...
        stride, dilation, filterGrouping);
end

if dbiasNeeded
    dbias = sum(dZ, [1:d d+2]);
end
end

function [paddingStart, paddingEnd] = iConvertPaddingToHostAPIformat(paddingSize)
n = numel(paddingSize);
paddingStart = paddingSize(1:2:n);
paddingEnd = paddingSize(2:2:n);
end

function filterGrouping = iConvertNumGroupsToHostAPIformat(numFilters,numGroups)
filterGrouping = repmat(numFilters/numGroups,1,numGroups);
end