diff --git a/ivy/data_classes/array/experimental/elementwise.py b/ivy/data_classes/array/experimental/elementwise.py index ae3b6dec23fa2..9e11971ec727f 100644 --- a/ivy/data_classes/array/experimental/elementwise.py +++ b/ivy/data_classes/array/experimental/elementwise.py @@ -8,6 +8,41 @@ class _ArrayWithElementWiseExperimental(abc.ABC): + def lgamma(self: ivy.Array, *, out: Optional[ivy.Array] = None) -> ivy.Array: + """ + ivy.Array instance method variant of ivy.lgamma. This method simply wraps the + function, and so the docstring for ivy.lgamma also applies to this method with + minimal changes. + + Parameters + ---------- + self + input array. Should have a real-valued floating-point data type. + out + optional output array, for writing the result to. It must have a shape that + the inputs broadcast to. + + Returns + ------- + ret + an array containing the evaluated result for each element in ``self``. + The returned array must have a real-valued floating-point data + type determined by :ref:`type-promotion`. + + Examples + -------- + >>> x = ivy.array([1 , 2 , 3 ]) + >>> y = x.lgamma() + >>> print(y) + ivy.array([0., 0., 0.69314718]) + + >>> x = ivy.array([4.5, -4, -5.6]) + >>> x.lgamma(out = x) + >>> print(x) + ivy.array([2.45373654, inf, -4.6477685 ]) + """ + return ivy.lgamma(self._data, out=out) + def sinc(self: ivy.Array, *, out: Optional[ivy.Array] = None) -> ivy.Array: """ ivy.Array instance method variant of ivy.sinc. This method simply wraps the diff --git a/ivy/data_classes/container/experimental/elementwise.py b/ivy/data_classes/container/experimental/elementwise.py index cfc93e6cfb946..4d1d79e3fe42c 100644 --- a/ivy/data_classes/container/experimental/elementwise.py +++ b/ivy/data_classes/container/experimental/elementwise.py @@ -8,6 +8,137 @@ class _ContainerWithElementWiseExperimental(ContainerBase): + @staticmethod + def static_lgamma( + x: Union[ivy.Container, ivy.Array, ivy.NativeArray], + /, + *, + 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.lgamma. This method simply wraps the + function, and so the docstring for ivy.lgamma also applies to this method with + minimal changes. + + Parameters + ---------- + x + input container. Should have a real-valued floating-point data type. + 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 container, for writing the result to. It must have a shape + that the inputs broadcast to. + + Returns + ------- + ret + a container containing the evaluated result for each element in ``x``. + The returned array must have a real-valued floating-point data type + determined by :ref:`type-promotion`. + + Examples + -------- + >>> x = ivy.Container(a=ivy.array([0., 1., 2.]), b=ivy.array([3., 4., 5.1])) + >>> y = ivy.Container.static_lgamma(x) + >>> print(y) + { + a: ivy.array([inf, 0., 0.]), + b: ivy.array([0.69314718, 1.79175949, 3.32976389]) + } + + + >>> x = ivy.Container(a=ivy.array([0., 2.]), b=ivy.array([ 4., 5.1])) + >>> ivy.Container.static_lgamma(x, out = x) + >>> print(y) + { + a: ivy.array([inf, 0.]), + b: ivy.array([1.79175949, 3.32976389]) + } + """ + return ContainerBase.cont_multi_map_in_function( + "lgamma", + x, + key_chains=key_chains, + to_apply=to_apply, + prune_unapplied=prune_unapplied, + map_sequences=map_sequences, + out=out, + ) + + def lgamma( + self: ivy.Container, + *, + 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 instance method variant of ivy.lgamma. This method simply wraps + the function, and so the docstring for ivy.lgamma also applies to this method + with minimal changes. + + Parameters + ---------- + self + input container. Should have a real-valued floating-point data type. + 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 container, for writing the result to. It must have a shape + that the inputs broadcast to. + + Returns + ------- + ret + a container containing the evaluated result for each element in ``self``. + The returned array must have a real-valued floating-point data type + determined by :ref:`type-promotion`. + + Examples + -------- + >>> x = ivy.Container(a=ivy.array([1.6, 2.6, 3.5]), + ... b=ivy.array([4.5, 5.3, 2.3])) + >>> y = x.lgamma() + >>> print(y) + { + a: ivy.array([-0.11259222, 0.3574121, 1.20097375]), + b: ivy.array([2.45373821, 3.63963795, 0.15418935]) + } + """ + return self.static_lgamma( + self, + key_chains=key_chains, + to_apply=to_apply, + prune_unapplied=prune_unapplied, + map_sequences=map_sequences, + out=out, + ) + @staticmethod def static_sinc( x: ivy.Container, diff --git a/ivy/functional/backends/jax/experimental/elementwise.py b/ivy/functional/backends/jax/experimental/elementwise.py index 2d3503ee02215..3d75ad0268a04 100644 --- a/ivy/functional/backends/jax/experimental/elementwise.py +++ b/ivy/functional/backends/jax/experimental/elementwise.py @@ -7,9 +7,14 @@ default_float_dtype, is_float_dtype, ) +from ivy.func_wrapper import ( + with_supported_dtypes, +) from ivy.functional.backends.jax import JaxArray import jax.numpy as jnp import jax.scipy as js +import jax.lax as jlax +from .. import backend_version jax_ArrayLike = Union[JaxArray, Number] @@ -18,6 +23,13 @@ def sinc(x: JaxArray, /, *, out: Optional[JaxArray] = None) -> JaxArray: return jnp.sinc(x) +@with_supported_dtypes( + {"0.4.13 and below": ("float16", "float32", "float64")}, backend_version +) +def lgamma(x: JaxArray, /, *, out: Optional[JaxArray] = None) -> JaxArray: + return jlax.lgamma(x) + + def fmax( x1: JaxArray, x2: JaxArray, diff --git a/ivy/functional/backends/mxnet/experimental/elementwise.py b/ivy/functional/backends/mxnet/experimental/elementwise.py index f00d6aec6f29d..ce69fe9e91ed3 100644 --- a/ivy/functional/backends/mxnet/experimental/elementwise.py +++ b/ivy/functional/backends/mxnet/experimental/elementwise.py @@ -3,6 +3,21 @@ import mxnet as mx from ivy.utils.exceptions import IvyNotImplementedException +from ivy.func_wrapper import with_supported_dtypes +from .. import backend_version + + +@with_supported_dtypes( + {"1.9.1 and below": ("float16", "float32", "float64")}, + backend_version, +) +def lgamma( + x: Union[(None, mx.ndarray.NDArray)], + /, + *, + out: Optional[Union[(None, mx.ndarray.NDArray)]] = None, +) -> Union[(None, mx.ndarray.NDArray)]: + return mx.np.log(mx.npx.gamma(x)) def sinc( diff --git a/ivy/functional/backends/numpy/experimental/elementwise.py b/ivy/functional/backends/numpy/experimental/elementwise.py index 06c7bd29748ba..2edebc609bf1b 100644 --- a/ivy/functional/backends/numpy/experimental/elementwise.py +++ b/ivy/functional/backends/numpy/experimental/elementwise.py @@ -7,6 +7,11 @@ from ivy.functional.backends.numpy.helpers import _scalar_output_to_0d_array from ivy.func_wrapper import with_unsupported_dtypes from . import backend_version +from ivy.utils.exceptions import IvyNotImplementedException + + +def lgamma(x: np.ndarray, /, *, out: Optional[np.ndarray] = None) -> np.ndarray: + raise IvyNotImplementedException() @_scalar_output_to_0d_array diff --git a/ivy/functional/backends/paddle/experimental/elementwise.py b/ivy/functional/backends/paddle/experimental/elementwise.py index 528b9cf406257..1dba17b9cf54b 100644 --- a/ivy/functional/backends/paddle/experimental/elementwise.py +++ b/ivy/functional/backends/paddle/experimental/elementwise.py @@ -17,6 +17,16 @@ from .. import backend_version +@with_supported_dtypes( + {"2.5.0 and below": ("float32", "float64")}, + backend_version, +) +def lgamma( + x: paddle.Tensor, /, *, out: Optional[paddle.Tensor] = None +) -> paddle.Tensor: + return paddle.lgamma(x) + + @with_supported_dtypes( {"2.5.0 and below": ("float64", "float32", "int32", "int64")}, backend_version, diff --git a/ivy/functional/backends/tensorflow/experimental/elementwise.py b/ivy/functional/backends/tensorflow/experimental/elementwise.py index 7dee858858b6a..3bd70c83ff1ea 100644 --- a/ivy/functional/backends/tensorflow/experimental/elementwise.py +++ b/ivy/functional/backends/tensorflow/experimental/elementwise.py @@ -11,6 +11,19 @@ from .. import backend_version +@with_supported_dtypes( + {"2.13.0 and below": ("float16", "float32", "float64")}, + backend_version, +) +def lgamma( + x: Union[tf.Tensor, tf.Variable], + /, + *, + out: Optional[Union[tf.Tensor, tf.Variable]] = None, +) -> Union[tf.Tensor, tf.Variable]: + return tf.math.lgamma(x) + + def sinc( x: Union[tf.Tensor, tf.Variable], /, diff --git a/ivy/functional/backends/torch/experimental/elementwise.py b/ivy/functional/backends/torch/experimental/elementwise.py index d8e3f05d7ee52..427843cc2d9f1 100644 --- a/ivy/functional/backends/torch/experimental/elementwise.py +++ b/ivy/functional/backends/torch/experimental/elementwise.py @@ -14,6 +14,11 @@ from .. import backend_version +@with_supported_dtypes({"2.0.1 and below": ("float32", "float64")}, backend_version) +def lgamma(x: torch.Tensor, /, *, out: Optional[torch.Tensor] = None) -> torch.Tensor: + return torch.lgamma(x, out=out) + + @with_unsupported_dtypes({"2.0.1 and below": ("complex",)}, backend_version) def fmax( x1: torch.Tensor, diff --git a/ivy/functional/ivy/experimental/elementwise.py b/ivy/functional/ivy/experimental/elementwise.py index 6a3ad58ef0a78..b334957b3a320 100644 --- a/ivy/functional/ivy/experimental/elementwise.py +++ b/ivy/functional/ivy/experimental/elementwise.py @@ -16,6 +16,60 @@ from ivy.utils.exceptions import handle_exceptions +@handle_exceptions +@handle_nestable +@handle_array_like_without_promotion +@handle_out_argument +@to_native_arrays_and_back +@handle_array_function +def lgamma( + x: Union[ivy.Array, ivy.NativeArray], + /, + *, + out: Optional[ivy.Array] = None, +) -> ivy.Array: + """ + Compute the natural logarithm of the absolute value of the gamma function on x. + + Parameters + ---------- + x + input array. Should have a floating-point data type. + out + optional output array, for writing the result to. It must have a shape that the + inputs broadcast to. + + Returns + ------- + ret + an array containing the natural log of Gamma(x) of each element in x. + The returned array must have a floating-point data type determined + by :ref:`type-promotion`. + + Examples + -------- + >>> x = ivy.Container(a=ivy.array([1.6, 2.6, 3.5]), + ... b=ivy.array([4.5, 5.3, 2.3])) + >>> y = x.lgamma() + >>> print(y) + { + a: ivy.array([-0.11259222, 0.3574121, 1.20097375]), + b: ivy.array([2.45373821, 3.63963795, 0.15418935]) + } + + >>> x = ivy.array([1 , 2 , 3 ]) + >>> y = x.lgamma() + >>> print(y) + ivy.array([0., 0., 0.69314718]) + + >>> x = ivy.array([4.5, -4, -5.6]) + >>> x.lgamma(out = x) + >>> print(x) + ivy.array([2.45373654, inf, -4.6477685 ]) + """ + return ivy.current_backend(x).lgamma(x, out=out) + + @handle_exceptions @handle_nestable @handle_array_like_without_promotion diff --git a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_elementwise.py b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_elementwise.py index b675736aeca93..e472c881067ce 100644 --- a/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_elementwise.py +++ b/ivy_tests/test_ivy/test_functional/test_experimental/test_core/test_elementwise.py @@ -9,6 +9,32 @@ # Helpers # # ------- # +# lgamma +@handle_test( + fn_tree="functional.ivy.experimental.lgamma", + dtype_and_x=helpers.dtype_and_values( + available_dtypes=helpers.get_dtypes("float"), + safety_factor_scale="log", + ), + test_gradients=st.just(False), +) +def test_lgamma( + *, + 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, + fw=backend_fw, + fn_name=fn_name, + x=x[0], + ) # sinc @@ -400,7 +426,7 @@ def test_diff( test_flags, backend_fw, fn_name, - on_device + on_device, ): input_dtype, x, axis = dtype_n_x_n_axis _, prepend = dtype_prepend