function [X, H, Ws] = internal_gru(X, h0, W, R, b)
% This function is undocumented and will change in a future release.

%   [X, H, Ws] = internal_gru(X, h0, W, R, b) computes the Gated Recurrent
%   Unit operation using input data X, initial hidden units h0, input
%   weights W, recurrent weights R and bias term b.
%
%   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               (3*nH)x(nF) matrix
%   R - Recurrent weights           (3*nH)x(nH) matrix
%   b - Bias                        (3*nH)x(1) vector
%   h0 - Initial hidden units       (nH)x(N) matrix
%
%   Outputs:
%   Z  - Output                      (nH)x(N)x(nS) array
%   H  - Hidden state                (nH)x(N) matrix
%   Ws - Workspace

%   Copyright 2019 The MathWorks, Inc.

% Cast inputs to common type
[X, h0, W, R, b] = nnet.internal.cnnhost.castToSuperiorFloat(X, h0, W, R, b);

% Prepare the inputs for cnnhost implementation
learnable.W = W;
learnable.R = R;
learnable.b = b;
state.h0 = h0;
options.ReturnLast = false; % Always return the full output
options.GateActivationFunction = @internal_sigmoid;
options.StateActivationFunction = @tanh;
% Call cnnhost implementation
[X, H] = nnet.internal.cnnhost.gruForwardGeneral(X,learnable,state,options);

% This output is required for the GPU implementation. Set to empty for CPU.
Ws = [];

end
