Stitch two RNN models into a bidirectional layer.

def Bidirectional(l2r, r2l):
    """Stitch two RNN models into a bidirectional layer."""
    nO = l2r.nO

    def birnn_fwd(Xs, drop=0.0):
        l2r_Zs, bp_l2r_Zs = l2r.begin_update(Xs, drop=drop)
        r2l_Zs, bp_r2l_Zs = r2l.begin_update(
            [l2r.ops.xp.ascontiguousarray(X[::-1]) for X in Xs]
        )

        def birnn_bwd(dZs, sgd=None):
            d_l2r_Zs = []
            d_r2l_Zs = []
            for dZ in dZs:
                l2r_fwd = dZ[:, :nO]
                r2l_fwd = dZ[:, nO:]
                d_l2r_Zs.append(l2r.ops.xp.ascontiguousarray(l2r_fwd))
                d_r2l_Zs.append(l2r.ops.xp.ascontiguousarray(r2l_fwd[::-1]))
            dXs_l2r = bp_l2r_Zs(d_l2r_Zs, sgd=sgd)
            dXs_r2l = bp_r2l_Zs(d_r2l_Zs, sgd=sgd)
            dXs = [dXf + dXb[::-1] for dXf, dXb in zip(dXs_l2r, dXs_r2l)]
            return dXs

        Zs = [l2r.ops.xp.hstack((Zf, Zb[::-1])) for Zf, Zb in zip(l2r_Zs, r2l_Zs)]
        return Zs, birnn_bwd

    return wrap(birnn_fwd, l2r, r2l)