'X should be of shape (n,b,input_size), where n = length of sequence, b = batch size'

@staticmethod
def forward(X, WLSTM, c0=None, h0=None):

    (n, b, input_size) = X.shape
    d = (WLSTM.shape[1] // 4)
    if (c0 is None):
        c0 = np.zeros((b, d))
    if (h0 is None):
        h0 = np.zeros((b, d))
    xphpb = WLSTM.shape[0]
    Hin = np.zeros((n, b, xphpb))
    Hout = np.zeros((n, b, d))
    IFOG = np.zeros((n, b, (d * 4)))
    IFOGf = np.zeros((n, b, (d * 4)))
    C = np.zeros((n, b, d))
    Ct = np.zeros((n, b, d))
    for t in range(n):
        prevh = (Hout[(t - 1)] if (t > 0) else h0)
        Hin[t, :, 0] = 1
        Hin[t, :, 1:(input_size + 1)] = X[t]
        Hin[t, :, (input_size + 1):] = prevh
        IFOG[t] = Hin[t].dot(WLSTM)
        IFOGf[t, :, :(3 * d)] = (1.0 / (1.0 + np.exp((- IFOG[t, :, :(3 * d)]))))
        IFOGf[t, :, (3 * d):] = np.tanh(IFOG[t, :, (3 * d):])
        prevc = (C[(t - 1)] if (t > 0) else c0)
        C[t] = ((IFOGf[t, :, :d] * IFOGf[t, :, (3 * d):]) + (IFOGf[t, :, d:(2 * d)] * prevc))
        Ct[t] = np.tanh(C[t])
        Hout[t] = (IFOGf[t, :, (2 * d):(3 * d)] * Ct[t])
    cache = {}
    cache['WLSTM'] = WLSTM
    cache['Hout'] = Hout
    cache['IFOGf'] = IFOGf
    cache['IFOG'] = IFOG
    cache['C'] = C
    cache['Ct'] = Ct
    cache['Hin'] = Hin
    cache['c0'] = c0
    cache['h0'] = h0
    return (Hout, C[t], Hout[t], cache)
