//  [python]
def map_layer_inputs_to_op(cls, X, V_h, V_v, W, i, previous_state=None, previous_output=None, iteration=None):
        """
        Just like NativeOp.LstmGenericBase.map_layer_inputs_to_op().
        :param tf.Tensor X: inputs: shape (timeT,timeS,batch,n_hidden*5)
        :param tf.Tensor V_h: W_re: shape (n_hidden,n_hidden*5)
        :param tf.Tensor V_v: W_re: shape (n_hidden,n_hidden*5)
        :param tf.Tensor W:
        :param tf.Tensor i: index: shape (time,batch)
        :param tf.Tensor previous_state:
        :param tf.Tensor previous_output:
        :param tf.Tensor iteration:
        :rtype: (tf.Tensor,tf.Tensor,tf.Tensor,tf.Tensor)
        """
        assert X.get_shape().ndims == 4
        assert V_h.get_shape().ndims == 2
        assert V_v.get_shape().ndims == 2
        assert W.get_shape().ndims == 2
        assert i.get_shape().ndims == 2
        if i.dtype != tf.float32:
            if not hasattr(i, "cast_float32"):
                from returnn.tf.util.basic import reuse_name_scope_of_tensor

                with reuse_name_scope_of_tensor(i):
                    i_cast_float32 = tf.cast(i, dtype=tf.float32, name="index_cast_float32")
                i.cast_float32 = i_cast_float32
            i = i.cast_float32
        # n_batch = tf.shape(X)[2]
        n_out = tf.shape(V_h)[0]

        # ptr_storage_fwd
        height = tf.shape(X)[0]
        width = tf.shape(X)[1]
        max_diag_size = tf.minimum(height, width)
        ptr_storage_fwd = tf.zeros(
            (1 * 6 * max_diag_size * 2,), dtype=tf.float32
        )  # 1 * 5 * max_diag_size * sizeof(float*) / sizeof(float)
        # ptr_storage_bwd
        height = tf.shape(X)[0]
        width = tf.shape(X)[1]
        max_diag_size = tf.minimum(height, width)
        ptr_storage_bwd = tf.zeros(
            (1 * 10 * max_diag_size * 2,), dtype=tf.float32
        )  # 1 * 10 * max_diag_size * sizeof(float*) / sizeof(float)

        # valid
        n_minibatch = tf.shape(X)[2]
        valid = tf.zeros((1 * max_diag_size * n_minibatch,), dtype=tf.float32)

        # workmem
        workmem = tf.zeros((2, 2, tf.shape(X)[1] + tf.shape(X)[0], tf.shape(X)[2], tf.shape(X)[3]), dtype=tf.float32)
        # workmem2
        workmem2 = tf.zeros((tf.shape(X)[0], tf.shape(X)[2], 5 * tf.shape(X)[3]), dtype=tf.float32)

        i_trg = tf.ones([tf.shape(X)[0], tf.shape(X)[2]])
        sizes = tf.stack([tf.reduce_sum(i_trg, axis=0), tf.reduce_sum(i, axis=0)], axis=1)  # target, source
        # sizes = tf.Print(sizes, [tf.shape(sizes), sizes], "sizes", summarize=5000)

        # X = tf.Print(X, ["2D-LSTM: X", tf.shape(X)], summarize=4)
        # sizes = tf.Print(sizes, ["2D-LSTM: sizes", sizes], summarize=999)
        # i = tf.Print(i, ["2D-LSTM: i", i], summarize=999)

        # bias
        b = tf.zeros((5 * n_out,), dtype=tf.float32)

        DYDummy = tf.zeros((tf.shape(X)[0], tf.shape(X)[1], tf.shape(X)[2], tf.shape(V_h)[0]), dtype=tf.float32)

        return (
            X,
            V_h,
            V_v,
            W,
            b,
            ptr_storage_fwd,
            ptr_storage_bwd,
            valid,
            workmem,
            workmem2,
            sizes,
            DYDummy,
            previous_state,
            previous_output,
            iteration,
        )