'Incoming gate:     i(t) = f_i(x(t) @ W_xi + h(t-1) @ W_hi + w_ci * c(t-1) + b_i)
Forget gate:       f(t) = f_f(x(t) @ W_xf + h(t-1) @ W_hf + w_cf * c(t-1) + b_f)
Cell gate:         c(t) = f(t) * c(t - 1) + i(t) * f_c(x(t) @ W_xc + h(t-1) @ W_hc + b_c)
Out gate:          o(t) = f_o(x(t) @ W_xo + h(t-1) W_ho + w_co * c(t) + b_o)
New hidden state:  h(t) = o(t) * f_h(c(t))'

def step(self, hcprev, x):

    hprev = hcprev[:, :self.num_units]
    cprev = hcprev[:, self.num_units:]
    if self.layer_normalization:
        ln = apply_ln(self)
    else:
        ln = (lambda x, *args: x)
    x_ifco = ln(tf.matmul(x, self.W_x_ifco), 'x_ifco')
    h_ifco = ln(tf.matmul(hprev, self.W_h_ifco), 'h_ifco')
    (x_i, x_f, x_c, x_o) = tf.split(axis=1, num_or_size_splits=4, value=x_ifco)
    (h_i, h_f, h_c, h_o) = tf.split(axis=1, num_or_size_splits=4, value=h_ifco)
    if self.use_peepholes:
        i = self.gate_nonlinearity((((x_i + h_i) + (self.w_ci * cprev)) + self.b_i))
        f = self.gate_nonlinearity(((((x_f + h_f) + (self.w_cf * cprev)) + self.b_f) + self.forget_bias))
        o = self.gate_nonlinearity((((x_o + h_o) + (self.w_co * cprev)) + self.b_o))
    else:
        i = self.gate_nonlinearity(((x_i + h_i) + self.b_i))
        f = self.gate_nonlinearity((((x_f + h_f) + self.b_f) + self.forget_bias))
        o = self.gate_nonlinearity(((x_o + h_o) + self.b_o))
    c = ((f * cprev) + (i * self.nonlinearity(((x_c + h_c) + self.b_c))))
    h = (o * self.nonlinearity(ln(c, 'c')))
    return tf.concat(axis=1, values=[h, c])
