From f0550d6fe1a99019e06c67a7bc08e8234982a67c Mon Sep 17 00:00:00 2001 From: yash goel Date: Mon, 14 Aug 2023 19:23:36 +0530 Subject: [PATCH 1/6] add optional get element function --- .../array/experimental/utility.py | 31 +++++++- .../container/experimental/utility.py | 76 ++++++++++++++++++- ivy/functional/ivy/experimental/utility.py | 40 ++++++++++ .../test_core/test_utility.py | 36 +++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) diff --git a/ivy/data_classes/array/experimental/utility.py b/ivy/data_classes/array/experimental/utility.py index 421c007589869..354651e59f9d0 100644 --- a/ivy/data_classes/array/experimental/utility.py +++ b/ivy/data_classes/array/experimental/utility.py @@ -1,6 +1,35 @@ # global +from typing import Optional import abc +# local +import ivy + class _ArrayWithUtilityExperimental(abc.ABC): - pass + def optional_get_element( + self: Optional[ivy.Array] = None, + /, + *, + out: Optional[ivy.Array] = None, + ) -> ivy.Array: + """ + If the input is a tensor or sequence type, it returns the input. + If the input is an optional type, it outputs the element in the input. + It is an error if the input is an empty optional-type (i.e. does not have an element) + and the behavior is undefined in this case. + + Parameters + ---------- + self + Input array + out + Optional output array, for writing the result to. + + Returns + ------- + ret + Input array if it is not None + + """ + return ivy.optional_get_element(self._data, out=out) diff --git a/ivy/data_classes/container/experimental/utility.py b/ivy/data_classes/container/experimental/utility.py index b21273ff50669..0ecfecc098097 100644 --- a/ivy/data_classes/container/experimental/utility.py +++ b/ivy/data_classes/container/experimental/utility.py @@ -1,5 +1,79 @@ +# global +from typing import Optional, Union, Dict, List + +# local +import ivy from ivy.data_classes.container.base import ContainerBase class _ContainerWithUtilityExperimental(ContainerBase): - pass + @staticmethod + def static_optional_get_element( + x: Optional[Union[ivy.Array, ivy.Container]] = None, + /, + *, + key_chains: Optional[Union[List[str], Dict[str, str]]] = None, + to_apply: bool = True, + prune_unapplied: bool = False, + map_sequences: bool = False, + out: Optional[ivy.Container] = None, + ) -> ivy.Container: + """ + ivy.Container static method variant of ivy.optional_get_element. + This method simply wraps the function, and so the docstring for + ivy.optional_get_element also applies to this method + with minimal changes. + Parameters + ---------- + x + container with array inputs. + key_chains + The keychains 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 container, for writing the result to. + Returns + ------- + ret + Container with arrays flattened at leaves. + """ + return ContainerBase.cont_multi_map_in_function( + "optional_get_element", + x, + key_chains=key_chains, + to_apply=to_apply, + prune_unapplied=prune_unapplied, + map_sequences=map_sequences, + out=out, + ) + + def optional_get_element( + self: ivy.Container, + /, + *, + out: Optional[ivy.Container] = None, + ) -> ivy.Container: + """ivy.Container instance method variant of ivy.optional_get_element. + This method simply wraps the function, and so the docstring for + ivy.optional_get_element also applies to this method with minimal + changes. + Parameters + ---------- + self + Input container + out + Optional output container, for writing the result to. + Returns + ------- + ret + Output container. + """ + return self.static_optional_get_element(self, out=out) diff --git a/ivy/functional/ivy/experimental/utility.py b/ivy/functional/ivy/experimental/utility.py index e69de29bb2d1d..57b8b3ec30a4f 100644 --- a/ivy/functional/ivy/experimental/utility.py +++ b/ivy/functional/ivy/experimental/utility.py @@ -0,0 +1,40 @@ +# global +from typing import Optional + +# local +import ivy +from ivy import handle_out_argument, handle_nestable +from ivy.utils.exceptions import handle_exceptions + + +@handle_out_argument +@handle_nestable +@handle_exceptions +def optional_get_element( + x: Optional[ivy.Array] = None, + /, + *, + out: Optional[ivy.Array] = None, +) -> ivy.Array: + """ + If the input is a tensor or sequence type, it returns the input. + If the input is an optional type, it outputs the element in the input. + It is an error if the input is an empty optional-type (i.e. does not have an element) + and the behavior is undefined in this case. + + Parameters + ---------- + x + Input array + out + Optional output array, for writing the result to. + + Returns + ------- + ret + Input array if it is not None + + """ + if x is None: + raise ivy.utils.exceptions.IvyError("The requested optional input has no value.") + return x diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py index e69de29bb2d1d..042bba981f360 100644 --- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py +++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py @@ -0,0 +1,36 @@ +# local +import ivy_tests.test_ivy.helpers as helpers +from ivy_tests.test_ivy.helpers import handle_test + + +@handle_test( + fn_tree="functional.ivy.experimental.optional_get_element", + + dtype_and_x= helpers.dtype_and_values( + min_value=-100, + max_value=100, + min_num_dims=0, + max_num_dims=5, + min_dim_size=0, + max_dim_size=5, + allow_nan= True, + ), +) +def test_optional_get_element( + *, + dtype_and_x, + test_flags, + backend_fw, + fn_name, + on_device, +): + input_dtype, x = dtype_and_x + + helpers.test_function( + input_dtypes=input_dtype, + test_flags=test_flags, + on_device=on_device, + backend_to_test=backend_fw, + fn_name=fn_name, + x=x[0], + ) \ No newline at end of file From 7984976176923b79f4a053607a9a8d626e23c7de Mon Sep 17 00:00:00 2001 From: yash goel Date: Mon, 14 Aug 2023 22:02:28 +0530 Subject: [PATCH 2/6] lint --- .../array/experimental/utility.py | 17 ++++---- .../container/experimental/utility.py | 43 ++++++++++--------- ivy/functional/ivy/experimental/utility.py | 13 +++--- .../test_core/test_utility.py | 23 ++++++++-- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/ivy/data_classes/array/experimental/utility.py b/ivy/data_classes/array/experimental/utility.py index 354651e59f9d0..46aaccd3510ad 100644 --- a/ivy/data_classes/array/experimental/utility.py +++ b/ivy/data_classes/array/experimental/utility.py @@ -8,16 +8,16 @@ class _ArrayWithUtilityExperimental(abc.ABC): def optional_get_element( - self: Optional[ivy.Array] = None, - /, - *, - out: Optional[ivy.Array] = None, + self: Optional[ivy.Array] = None, + /, + *, + out: Optional[ivy.Array] = None, ) -> ivy.Array: """ - If the input is a tensor or sequence type, it returns the input. - If the input is an optional type, it outputs the element in the input. - It is an error if the input is an empty optional-type (i.e. does not have an element) - and the behavior is undefined in this case. + If the input is a tensor or sequence type, it returns the input. If the input is + an optional type, it outputs the element in the input. It is an error if the + input is an empty optional-type (i.e. does not have an element) and the behavior + is undefined in this case. Parameters ---------- @@ -30,6 +30,5 @@ def optional_get_element( ------- ret Input array if it is not None - """ return ivy.optional_get_element(self._data, out=out) diff --git a/ivy/data_classes/container/experimental/utility.py b/ivy/data_classes/container/experimental/utility.py index 0ecfecc098097..876a9fad339e5 100644 --- a/ivy/data_classes/container/experimental/utility.py +++ b/ivy/data_classes/container/experimental/utility.py @@ -9,20 +9,20 @@ class _ContainerWithUtilityExperimental(ContainerBase): @staticmethod def static_optional_get_element( - x: Optional[Union[ivy.Array, ivy.Container]] = None, - /, - *, - key_chains: Optional[Union[List[str], Dict[str, str]]] = None, - to_apply: bool = True, - prune_unapplied: bool = False, - map_sequences: bool = False, - out: Optional[ivy.Container] = None, + x: Optional[Union[ivy.Array, ivy.Container]] = None, + /, + *, + key_chains: Optional[Union[List[str], Dict[str, str]]] = None, + to_apply: bool = True, + prune_unapplied: bool = False, + map_sequences: bool = False, + out: Optional[ivy.Container] = None, ) -> ivy.Container: """ - ivy.Container static method variant of ivy.optional_get_element. - This method simply wraps the function, and so the docstring for - ivy.optional_get_element also applies to this method - with minimal changes. + ivy.Container static method variant of ivy.optional_get_element. This method + simply wraps the function, and so the docstring for ivy.optional_get_element + also applies to this method with minimal changes. + Parameters ---------- x @@ -40,6 +40,7 @@ def static_optional_get_element( Default is ``False``. out optional output container, for writing the result to. + Returns ------- ret @@ -56,21 +57,23 @@ def static_optional_get_element( ) def optional_get_element( - self: ivy.Container, - /, - *, - out: Optional[ivy.Container] = None, + self: ivy.Container, + /, + *, + out: Optional[ivy.Container] = None, ) -> ivy.Container: - """ivy.Container instance method variant of ivy.optional_get_element. - This method simply wraps the function, and so the docstring for - ivy.optional_get_element also applies to this method with minimal - changes. + """ + ivy.Container instance method variant of ivy.optional_get_element. This method + simply wraps the function, and so the docstring for ivy.optional_get_element + also applies to this method with minimal changes. + Parameters ---------- self Input container out Optional output container, for writing the result to. + Returns ------- ret diff --git a/ivy/functional/ivy/experimental/utility.py b/ivy/functional/ivy/experimental/utility.py index 57b8b3ec30a4f..e33383151b01c 100644 --- a/ivy/functional/ivy/experimental/utility.py +++ b/ivy/functional/ivy/experimental/utility.py @@ -17,10 +17,10 @@ def optional_get_element( out: Optional[ivy.Array] = None, ) -> ivy.Array: """ - If the input is a tensor or sequence type, it returns the input. - If the input is an optional type, it outputs the element in the input. - It is an error if the input is an empty optional-type (i.e. does not have an element) - and the behavior is undefined in this case. + If the input is a tensor or sequence type, it returns the input. If the input is an + optional type, it outputs the element in the input. It is an error if the input is + an empty optional-type (i.e. does not have an element) and the behavior is undefined + in this case. Parameters ---------- @@ -33,8 +33,9 @@ def optional_get_element( ------- ret Input array if it is not None - """ if x is None: - raise ivy.utils.exceptions.IvyError("The requested optional input has no value.") + raise ivy.utils.exceptions.IvyError( + "The requested optional input has no value." + ) return x diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py index 042bba981f360..128829d4db70f 100644 --- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py +++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py @@ -5,15 +5,30 @@ @handle_test( fn_tree="functional.ivy.experimental.optional_get_element", - - dtype_and_x= helpers.dtype_and_values( + dtype_and_x=helpers.dtype_and_values( + dtype=[ + "int8", + "int16", + "int32", + "int64", + "complex64", + "complex128", + "bool", + "float16", + "float32", + "float64", + "string", + "uint8", + "uint16", + "uint32", + ], min_value=-100, max_value=100, min_num_dims=0, max_num_dims=5, min_dim_size=0, max_dim_size=5, - allow_nan= True, + allow_nan=True, ), ) def test_optional_get_element( @@ -33,4 +48,4 @@ def test_optional_get_element( backend_to_test=backend_fw, fn_name=fn_name, x=x[0], - ) \ No newline at end of file + ) From c04fd41fb8d6cde8bbc23e4e5b952415b53a809d Mon Sep 17 00:00:00 2001 From: yash goel Date: Thu, 17 Aug 2023 14:04:34 +0530 Subject: [PATCH 3/6] remove constraints --- .../test_core/test_utility.py | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py index 128829d4db70f..d1215d27ea027 100644 --- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py +++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py @@ -5,31 +5,7 @@ @handle_test( fn_tree="functional.ivy.experimental.optional_get_element", - dtype_and_x=helpers.dtype_and_values( - dtype=[ - "int8", - "int16", - "int32", - "int64", - "complex64", - "complex128", - "bool", - "float16", - "float32", - "float64", - "string", - "uint8", - "uint16", - "uint32", - ], - min_value=-100, - max_value=100, - min_num_dims=0, - max_num_dims=5, - min_dim_size=0, - max_dim_size=5, - allow_nan=True, - ), + dtype_and_x=helpers.dtype_and_values(), ) def test_optional_get_element( *, From 564fa30539f3246468cd5189d93c89d3b0066df0 Mon Sep 17 00:00:00 2001 From: yash goel Date: Sat, 19 Aug 2023 15:14:30 +0530 Subject: [PATCH 4/6] retrigger checks From d511aecf6df2a8da2d792b9827c745418b4a3931 Mon Sep 17 00:00:00 2001 From: Kareem Morsy Date: Mon, 21 Aug 2023 15:58:28 +0000 Subject: [PATCH 5/6] Add support for lists in `optional_get_element` --- .../test_experimental/test_core/test_utility.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py index d1215d27ea027..8789c46a529eb 100644 --- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py +++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_utility.py @@ -1,3 +1,6 @@ +# global +from hypothesis import strategies as st + # local import ivy_tests.test_ivy.helpers as helpers from ivy_tests.test_ivy.helpers import handle_test @@ -6,16 +9,19 @@ @handle_test( fn_tree="functional.ivy.experimental.optional_get_element", dtype_and_x=helpers.dtype_and_values(), + input_tensor=st.booleans(), ) def test_optional_get_element( *, dtype_and_x, + input_tensor, test_flags, backend_fw, fn_name, on_device, ): input_dtype, x = dtype_and_x + fn_input = x[0] if input_tensor else x helpers.test_function( input_dtypes=input_dtype, @@ -23,5 +29,5 @@ def test_optional_get_element( on_device=on_device, backend_to_test=backend_fw, fn_name=fn_name, - x=x[0], + x=fn_input, ) From 351dd56458ececb2a8ed9496eeb021ee20a3dc6a Mon Sep 17 00:00:00 2001 From: theRealBird <75845929+theRealBird@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:37:49 +0000 Subject: [PATCH 6/6] add copy_ method to Torch frontend --- ivy/functional/frontends/torch/tensor.py | 9 +++++ .../test_frontends/test_torch/test_tensor.py | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/ivy/functional/frontends/torch/tensor.py b/ivy/functional/frontends/torch/tensor.py index d3d18a0b4f498..a6915fb7a1ec9 100644 --- a/ivy/functional/frontends/torch/tensor.py +++ b/ivy/functional/frontends/torch/tensor.py @@ -392,6 +392,15 @@ def log2(self): def relu(self): return torch_frontend_nn.relu(self) + @with_unsupported_dtypes({"2.0.1 and below": ("bfloat16", "uint16")}, "torch") + def copy_(self, other, non_blocking=False): + ivy.utils.assertions.check_one_way_broadcastable( + self.ivy_array.shape, + torch_frontend.tensor(other).ivy_array.shape + ) + self._ivy_array = torch_frontend.tensor(other).ivy_array + return self + @numpy_to_torch_style_args @with_unsupported_dtypes({"2.0.1 and below": ("complex",)}, "torch") def amax(self, dim=None, keepdim=False): diff --git a/ivy_tests/test_ivy/test_frontends/test_torch/test_tensor.py b/ivy_tests/test_ivy/test_frontends/test_torch/test_tensor.py index 07a418658f32e..2f7d9eca67129 100644 --- a/ivy_tests/test_ivy/test_frontends/test_torch/test_tensor.py +++ b/ivy_tests/test_ivy/test_frontends/test_torch/test_tensor.py @@ -6042,6 +6042,44 @@ def test_torch_tensor_cumsum_( ) +# copy_ +@handle_frontend_method( + class_tree=CLASS_TREE, + init_tree="torch.tensor", + method_name="copy_", + dtype_and_x=helpers.dtype_and_values( + available_dtypes=helpers.get_dtypes("valid"), + num_arrays=2, + ), +) +def test_torch_tensor_copy_( + dtype_and_x, + frontend_method_data, + init_flags, + method_flags, + frontend, + on_device, + backend_fw, +): + input_dtype, x = dtype_and_x + helpers.test_frontend_method( + init_input_dtypes=input_dtype, + backend_to_test=backend_fw, + init_all_as_kwargs_np={ + "data": x[0], + }, + method_input_dtypes=input_dtype, + method_all_as_kwargs_np={ + "other": x[1], + }, + frontend_method_data=frontend_method_data, + init_flags=init_flags, + method_flags=method_flags, + frontend=frontend, + on_device=on_device, + ) + + # sort @handle_frontend_method( class_tree=CLASS_TREE,