Repository: ivy-llc/ivy

Issue:
ConcatFromSequence



Discussion:

Resolving patch:
diff --git a/ivy/data_classes/container/experimental/manipulation.py b/ivy/data_classes/container/experimental/manipulation.py
--- a/ivy/data_classes/container/experimental/manipulation.py
+++ b/ivy/data_classes/container/experimental/manipulation.py
@@ -3859,3 +3859,93 @@ def put_along_axis(
             map_sequences=map_sequences,
             out=out,
         )
+
+
+def concat_from_sequence(
+    self: ivy.Container,
+    /,
+    input_sequence: Union[
+        Tuple[Union[ivy.Array, ivy.NativeArray, ivy.Container]],
+        List[Union[ivy.Array, ivy.NativeArray, ivy.Container]],
+    ],
+    *,
+    new_axis: Union[int, ivy.Container] = 0,
+    axis: Union[int, ivy.Container] = 0,
+    key_chains: Optional[Union[List[str], Dict[str, str], ivy.Container]] = None,
+    to_apply: Union[bool, ivy.Container] = True,
+    prune_unapplied: Union[bool, ivy.Container] = False,
+    map_sequences: Union[bool, ivy.Container] = False,
+    out: Optional[ivy.Container] = None,
+) -> ivy.Container:
+    """
+    ivy.Container instance method variant of ivy.stack. This method simply wraps the
+    function, and so the docstring for ivy.stack also applies to this method with
+    minimal changes.
+
+    Parameters
+    ----------
+    self
+    Container with leaves to join with leaves of other arrays/containers.
+    Each array leave must have the same shape.
+    input_sequence
+    Container with other leaves to join.
+    Each array leave must have the same shape.
+    new_axis
+    Insert and concatenate on a new axis or not,
+    default 0 means do not insert new axis.
+    new_axis = 0: concatenate
+    new_axis = 1: stack
+    axis
+    axis along which the array leaves will be concatenated. More details can be found in
+    the docstring for ivy.stack.
+    key_chains
+    The key-chains to apply or not apply the method to. Default is ``None``.
+    to_apply
+    If True, the method will be applied to key_chains, otherwise key_chains
+    will be skipped. Default is ``True``.
+    prune_unapplied
+    Whether to prune key_chains for which the function was not applied.
+    Default is ``False``.
+    map_sequences
+    Whether to also map method to sequences (lists, tuples).
+    Default is ``False``.
+    out
+    optional output array, for writing the result to. It must have a shape
+    that the inputs broadcast to.
+
+    Returns
+    -------
+    ret
+    an output container with the results.
+
+    Examples
+    --------
+    >>> x = ivy.Container(a=ivy.array([[0, 1], [2,3]]), b=ivy.array([[4, 5]]))
+    >>> y = ivy.Container(a=ivy.array([[3, 2], [1,0]]), b=ivy.array([[1, 0]]))
+    >>> z = ivy.Container.static_concat_from_sequence([x,y],axis=1)
+    >>> print(z)
+    {
+    'a': ivy.array([[[0, 1],
+                     [3, 2]],
+                     [[2, 3],
+                     [1, 0]]]),
+    'b': ivy.array([[[4, 5],
+                     [1, 0]]])
+    }
+    """
+    new_input_sequence = (
+        input_sequence.cont_copy()
+        if ivy.is_ivy_container(input_sequence)
+        else input_sequence.copy()
+    )
+    new_input_sequence.insert(0, self.cont_copy())
+    return self.concat_from_sequence(
+        new_input_sequence,
+        new_axis=new_axis,
+        axis=axis,
+        key_chains=key_chains,
+        to_apply=to_apply,
+        prune_unapplied=prune_unapplied,
+        map_sequences=map_sequences,
+        out=out,
+    )
diff --git a/ivy/functional/backends/torch/creation.py b/ivy/functional/backends/torch/creation.py
--- a/ivy/functional/backends/torch/creation.py
+++ b/ivy/functional/backends/torch/creation.py
@@ -607,3 +607,15 @@ def triu_indices(
             row=n_rows, col=n_cols, offset=k, dtype=torch.int64, device=device
         )
     )
+
+
+def pad(tensor, sizes_of_pad, mode="constant", value=0):
+    if len(sizes_of_pad) == tensor.dim():
+        pad_pairs = []
+        for size in sizes_of_pad:
+            if size >= 0:
+                pad_pairs.append((size // 2, size - size // 2))
+        pad_pairs = pad_pairs[::-1]
+        pad_list = [item for pair in pad_pairs for item in pair]
+
+        return torch.nn.functional.pad(tensor, pad_list, mode, value)
diff --git a/ivy/functional/backends/torch/experimental/manipulation.py b/ivy/functional/backends/torch/experimental/manipulation.py
--- a/ivy/functional/backends/torch/experimental/manipulation.py
+++ b/ivy/functional/backends/torch/experimental/manipulation.py
@@ -13,6 +13,8 @@
 from numbers import Number
 from collections import namedtuple
 import torch
+from ivy.functional.backends.torch.creation import ivy_zeros_like
+from ivy.functional.utils import handle_view
 
 # local
 from ivy.func_wrapper import with_unsupported_dtypes, with_supported_dtypes
@@ -390,25 +392,6 @@ def expand(
 expand.support_native_out = False
 
 
-def concat_from_sequence(
-    input_sequence: Union[Tuple[torch.Tensor], List[torch.Tensor]],
-    /,
-    *,
-    new_axis: int = 0,
-    axis: int = 0,
-    out: Optional[torch.Tensor] = None,
-) -> torch.Tensor:
-    is_tuple = type(input_sequence) is tuple
-    if is_tuple:
-        input_sequence = list(input_sequence)
-    if new_axis == 0:
-        ret = torch.cat(input_sequence, dim=axis)
-        return ret
-    elif new_axis == 1:
-        ret = torch.stack(input_sequence, dim=axis)
-        return ret
-
-
 @with_unsupported_dtypes({"2.0.1 and below": ("complex", "float16")}, backend_version)
 def unique_consecutive(
     x: torch.Tensor,
@@ -473,3 +456,44 @@ def put_along_axis(
     "max",
     "min",
 ]
+
+
+@handle_view
+def concat_from_sequence(
+    array_sequence: ivy.ArraySequence,
+    *,
+    new_axis: int = 0,
+    axis: int = 0,
+    out: Optional[ivy.Array] = None,
+) -> ivy.Array:
+    """
+    Concatenates a sequence of arrays along a specified axis.
+
+    Parameters
+    ----------
+    array_sequence: A sequence of arrays.
+    new_axis: The axis along which to concatenate the arrays.
+    axis: The axis along which to concatenate the arrays.
+    out: Optional output array, for writing the result to.
+
+    Returns
+    -------
+    An array that is the concatenation of the arrays in the sequence.
+    """
+
+    if new_axis == 0:
+        return ivy.concat_from_sequence(
+            array_sequence, new_axis=new_axis, axis=axis, out=out
+        )
+    elif new_axis == 1:
+        if not isinstance(array_sequence, (tuple, list)):
+            array_sequence = [array_sequence]
+        if isinstance(array_sequence, tuple):
+            array_sequence = (ivy_zeros_like(array_sequence[0]),) + array_sequence
+        else:
+            array_sequence = [ivy_zeros_like(array_sequence)] + array_sequence
+        return handle_view(
+            ivy.concat_from_sequence(
+                array_sequence, new_axis=new_axis, axis=axis, out=out
+            )
+        )


Test patch:
diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_manipulation.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_manipulation.py
--- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_manipulation.py
+++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_manipulation.py
@@ -675,7 +675,7 @@ def test_column_stack(*, arrays_dtypes, test_flags, backend_fw, fn_name, on_devi
     test_instance_method=st.just(False),
 )
 def test_concat_from_sequence(
-    *, dtypes_arrays_axis, new_axis, test_flags, backend_fw, fn_name, on_device
+    *, dtypes_arrays_axis, new_axis, test_flags, backend_fw, fn_name, on_device: str
 ):
     dtypes, arrays, axis = dtypes_arrays_axis
 
@@ -685,7 +685,7 @@ def test_concat_from_sequence(
         backend_to_test=backend_fw,
         fn_name=fn_name,
         on_device=on_device,
-        input_sequence=arrays,
+        *arrays,
         new_axis=new_axis,
         axis=axis,
     )
@@ -694,13 +694,6 @@ def test_concat_from_sequence(
 # dsplit
 @handle_test(
     fn_tree="functional.ivy.experimental.dsplit",
-    dtype_and_x=helpers.dtype_and_values(
-        available_dtypes=helpers.get_dtypes("valid"),
-        shape=st.shared(helpers.get_shape(min_num_dims=3), key="value_shape"),
-    ),
-    indices_or_sections=_get_splits(allow_none=False, min_num_dims=3, axis=2),
-    test_gradients=st.just(False),
-    test_with_out=st.just(False),
 )
 def test_dsplit(
     dtype_and_x, indices_or_sections, test_flags, backend_fw, fn_name, on_device
@@ -708,10 +701,10 @@ def test_dsplit(
     input_dtype, x = dtype_and_x
     helpers.test_function(
         input_dtypes=input_dtype,
+        on_device=on_device,
         test_flags=test_flags,
         backend_to_test=backend_fw,
         fn_name=fn_name,
-        on_device=on_device,
         x=x[0],
         indices_or_sections=indices_or_sections,
     )