- zt = f(Xt*Wz + Ht_1*Rz        + Wbz + Rbz)
        - rt = f(Xt*Wr + Ht_1*Rr        + Wbr + Rbr)
        - ht = g(Xt*Wh + (rt . Ht_1)*Rh + Rbh + Wbh)
        - Ht = (1-zt).ht + zt.Ht_1

def gru(name, input, state, kernel_r, kernel_u, kernel_c, bias_r, bias_u, bias_c, new_state, number_of_gates = 2):
    ''' - zt = f(Xt*Wz + Ht_1*Rz        + Wbz + Rbz)
        - rt = f(Xt*Wr + Ht_1*Rr        + Wbr + Rbr)
        - ht = g(Xt*Wh + (rt . Ht_1)*Rh + Rbh + Wbh)
        - Ht = (1-zt).ht + zt.Ht_1
    '''
    nn = Build(name)
    inputs = nn.concat(input, state)

    u = nn.sigmoid(nn.mad(inputs, kernel_u, bias_u))
    r = nn.sigmoid(nn.mad(inputs, kernel_r, bias_r))
    r_state = nn.mul(r, state)

    c = nn.tanh(nn.mad(kernel=kernel_c, bias=bias_c,
        x=nn.concat(input, r_state)))

    # new_h = u' * state + (1 - u') * c'
    #       = u' * state + c' - u' * c'

    # u' * state + c'
    nn.add(nn.mul(u, state), c)
    # - u' * c'
    nn.sub(nn._, nn.mul(u, c),
        out=new_state)

    return nn.layers;