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

% Common backward method for d-dimensional convolution followed by relu on
% a CPU array, gpuArray or RecordingArray.
%
% 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/G) x G array. G is the
%                     number of groups and G must divide C and K.
%   permX           = 1 x d+2 array giving the data to view permutation of X
%                     or 1 x 0 if trivial.
%   permW           = 1 x d+3 array giving the data to view permutation of W
%                     or 1 x 0 if trivial.
%   Z               = O1 x O2 x...x Od x  K  x N array (output from convolution)
%   stride          = [s1,...,sd] where si is stride in the ith dimension.
%   dilation        = [c1,...,cd] where ci is dilation in the ith dimension.
%   paddingSize     = [L1,H1,...,Ld,Hd] where Li and Hi are the start and
%                     end padding sizes in the ith dimension.
%   paddingStrategy = strategy for padding the input array.
%   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/G) x G array.
%   dbias       = 1  x 1  x...x 1  x  K array.

%   Copyright 2020-2022 The MathWorks, Inc.

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

import deep.internal.recording.errorOnComplexGradientOutputs
import deep.internal.recording.errorOnComplexGradientInputs

dZ = errorOnComplexGradientOutputs(dZ, 'relu');
X = errorOnComplexGradientInputs(X, 'dlconv');
weights = errorOnComplexGradientInputs(weights, 'dlconv');
Z = errorOnComplexGradientInputs(Z, 'dlconv');

dZ = internal_reluBackward(dZ, Z);
[dX,dweights,dbias] = internal_dlconvBackward(dZ,X,weights,permX,permW,stride,dilation,paddingSize,paddingStrategy,numGroups,flags);

dX = errorOnComplexGradientInputs(dX, 'dlconv');
dweights = errorOnComplexGradientInputs(dweights, 'dlconv');
dbias = errorOnComplexGradientInputs(dbias, 'dlconv');

end