Full:
    - it = f(Xt*Wi + Ht_1*Ri + Pi . Ct_1 + Wbi + Rbi)
    - ft = f(Xt*Wf + Ht_1*Rf + Pf . Ct_1 + Wbf + Rbf)
    - ct = g(Xt*Wc + Ht_1*Rc + Wbc + Rbc)
    - Ct =  ft . Ct_1  + it . ct
    - ot = f(Xt*Wo + Ht_1*Ro + Po . Ct + Wbo + Rbo)
    - Ht =  ot . h(Ct)

def lstm(name, input, state_c, state_h, kernel_i, kernel_j, kernel_f, kernel_o, bias_i, bias_j, bias_f, bias_o, new_state_c, new_state_h):
    ''' Full:
    - it = f(Xt*Wi + Ht_1*Ri + Pi . Ct_1 + Wbi + Rbi)
    - ft = f(Xt*Wf + Ht_1*Rf + Pf . Ct_1 + Wbf + Rbf)
    - ct = g(Xt*Wc + Ht_1*Rc + Wbc + Rbc)
    - Ct =  ft . Ct_1  + it . ct
    - ot = f(Xt*Wo + Ht_1*Ro + Po . Ct + Wbo + Rbo)
    - Ht =  ot . h(Ct)
    '''

    ''' No peephole:
    - it = f(Xt*Wi + Ht_1*Ri + Wbi + Rbi)
    - ft = f(Xt*Wf + Ht_1*Rf + Wbf + Rbf)
    - ct = g(Xt*Wc + Ht_1*Rc + Wbc + Rbc)
    - Ct =   ft . Ct_  + it . ct
    - ot = f(Xt*Wo + Ht_1*Ro + Wbo + Rbo)
    - Ht =   ot . h(Ct)
    '''

    nn = Build(name)
    inputs = nn.concat(input, state_h)

    i = nn.sigmoid(nn.mad(x=inputs, kernel=kernel_i, bias=bias_i))
    j =    nn.tanh(nn.mad(inputs, kernel_j, bias_j))
    f = nn.sigmoid(nn.mad(inputs, kernel_f, bias_f))
    o = nn.sigmoid(nn.mad(inputs, kernel_o, bias_o))

    # new_c = state_c * f' + i' * j'
    nn.add(
        nn.mul(state_c, f), nn.mul(i, j),
        out=new_state_c)

    # new_h = 
    nn.mul(o, nn.tanh(new_state_c),
        out=new_state_h)

    return nn.layers