function [dZ, dh0, dc0, dW, dR, db] = internal_lstmBackward(dZ, dh0, dc0, X, h0, c0, W, R, b, Z, H, C, ~, stateActivation, gateActivation)
% This function is undocumented and will change in a future release.

%   [dZ,dh0,dc0,dW,dR,db] = internal_lstmBackward(dZ,dH,dC,X,h0,c0,W,R,b,Z,H,C,Ws,stateActivation,gateActivation)
%   computes the backward propagation of the Long Short-Term Memory
%   operation using outputs derivative dZ, DH and DC, input data X, initial
%   hidden units h0, initial cell state c0, input weights W, recurrent
%   weights R, bias term b, activation functions stateActivation and
%   gateActivation, output data Z, hidden state H and cell state C.
%
%   Definitions:
%   nF := Number of features of the input data
%   N := Number of input observations (mini-batch size)
%   nS := Sequence length
%   nH := Hidden units size
%
%   Inputs:
%   X - Input data                          (nF)x(N)x(nS) array
%
%   W - Input weights                       (4*nH)x(nF) matrix
%   R - Recurrent weights                   (4*nH)x(nH) matrix
%   b - Bias                                (4*nH)x(1) vector
%
%   c0 - Initial cell state                 (nH)x(N) matrix
%   h0 - Initial hidden units               (nH)x(N) matrix
%
%   stateActivation                         'tanh' or 'softsign' or 'relu'
%   gateActivation                          'sigmoid' or 'hard-sigmoid'
%
%   Z - Forward output                      (nH)x(N)x(nS) array
%   H - Hidden state                        (nH)x(N)x(nS) array
%   C - Cell state                          (nH)x(N) matrix
%
%   dZ - Next layer derivative              (nH)x(N)x(nS) array
%   dH - Hidden state derivative            (nH)x(N) array
%   dC - Cell state derivative              (nH)x(N) array
%
%   Outputs:
%   dX - Input data derivative              (nF)x(N)x(nS) array
%   dW - Input weights derivative           (4*nH)x(nF) array
%   dR - Recurrent weights derivative       (4*nH)x(nH) array
%   db - Bias derivative                    (4*nH)x(1) vector
%   dc0 - Initial cell state derivative     (nH)x(N) array
%   dh0 - Initial hidden state derivative   (nH)x(N) array

%   Copyright 2019-2023 The MathWorks, Inc.

import deep.internal.recording.errorOnComplexGradientOutputs

dZ = errorOnComplexGradientOutputs(dZ, 'lstm');
dh0 = errorOnComplexGradientOutputs(dh0, 'lstm');
dc0 = errorOnComplexGradientOutputs(dc0, 'lstm');

% Prepare the inputs for cnnhost implementation
learnable.W = W;
learnable.R = R;
learnable.b = b;
state.c0 = c0;
state.y0 = h0;
outputs.Y = Z;
outputs.CS = C;
outputs.HS = H;
derivatives.dZ = dZ;
derivatives.dHS = dh0;
derivatives.dCS = dc0;

% Specify output as sequence or last
options.ReturnLast = false; % Always return the full output

% Set activation functions
options.RecurrentActivationStr = gateActivation;
options.ActivationStr = stateActivation;

% Call cnnhost implementation
[dZ, dW, dR, db, dh0, dc0] = ...
    nnet.internal.cnnhost.lstmBackwardGeneral(X, learnable, state, outputs, derivatives, options);

end
