Skip to content

Commit

Permalink
Igamma added in experimental (#15717)
Browse files Browse the repository at this point in the history
Co-authored-by: Shehryar Tariq <sherrytst30@gmail.com>
  • Loading branch information
selvaraj-sembulingam and sherry30 authored May 26, 2023
1 parent 13fef50 commit ace246a
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 0 deletions.
40 changes: 40 additions & 0 deletions ivy/data_classes/array/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,43 @@ def bincount(
minlength=minlength,
out=out,
)

def igamma(
self: ivy.Array,
/,
*,
x: Union[ivy.Array, ivy.NativeArray],
out: Optional[ivy.Array] = None,
) -> ivy.Array:
"""
ivy.Array instance method variant of ivy.igamma. This method simply wraps the
function, and so the docstring for ivy.igamma also applies to this method with
minimal changes.
Parameters
----------
self
Input array.
x
An additional input array.
`x` has the same type as `a`.
out
optional output array, for writing the result to.
Returns
-------
ret
The lower incomplete gamma function of the array elements.
Examples
--------
>>> a = ivy.array([2.5])
>>> x = ivy.array([1.7, 1.2])
>>> a.igamma(x)
ivy.array([0.3614, 0.2085])
"""
return ivy.igamma(
self._data,
x=x,
out=out,
)
86 changes: 86 additions & 0 deletions ivy/data_classes/container/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,3 +1011,89 @@ def bincount(
array([6.5, 2. , 2.5])
"""
return self.static_bincount(self, weights=weights, minlength=minlength, out=out)

@staticmethod
def static_igamma(
a: Union[ivy.Container, ivy.Array, ivy.NativeArray],
/,
*,
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.igamma. This method simply wraps the
function, and so the docstring for ivy.igamma also applies to this method with
minimal changes.
Parameters
----------
self
Input array.
x
An additional input array.
`x` has the same type as `a`.
out
optional output array, for writing the result to.
Returns
-------
ret
The lower incomplete gamma function of the array elements.
Examples
--------
>>> a = ivy.array([2.5])
>>> x = ivy.array([1.7, 1.2])
>>> a.igamma(x)
ivy.array([0.3614, 0.2085])
"""
return ContainerBase.cont_multi_map_in_function(
"igamma",
a,
x=x,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
out=out,
)

def igamma(
self: ivy.Container,
/,
*,
x: Union[ivy.Container, ivy.Array, ivy.NativeArray],
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""
ivy.Container instance method variant of ivy.igamma. This method simply wraps
the function, and so the docstring for ivy.igamma also applies to this method
with minimal changes.
Parameters
----------
self
Input array.
x
An additional input array.
`x` has the same type as `a`.
out
optional output array, for writing the result to.
Returns
-------
ret
The lower incomplete gamma function of the array elements.
Examples
--------
>>> a = ivy.array([2.5])
>>> x = ivy.array([1.7, 1.2])
>>> a.igamma(x)
ivy.array([0.3614, 0.2085])
"""
return self.static_igamma(self, x=x, out=out)
10 changes: 10 additions & 0 deletions ivy/functional/backends/jax/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,13 @@ def einsum(
equation: str, *operands: JaxArray, out: Optional[JaxArray] = None
) -> JaxArray:
return jnp.einsum(equation, *operands)


def igamma(
a: JaxArray,
/,
*,
x: JaxArray,
out: Optional[JaxArray] = None,
) -> JaxArray:
return jlax.igamma(a=a, x=x)
18 changes: 18 additions & 0 deletions ivy/functional/backends/numpy/statistical.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# global
import math
import numpy as np
from typing import Union, Optional, Sequence, Tuple

Expand Down Expand Up @@ -376,3 +377,20 @@ def einsum(


einsum.support_native_out = True


def igamma(
a: np.ndarray,
/,
*,
x: np.ndarray,
out: Optional[np.ndarray] = None,
) -> np.ndarray:
def igamma_cal(a, x):
t = np.linspace(0, x, 10000, dtype=np.float64)
y = np.exp(-t) * (t ** (a - 1))
integral = np.trapz(y, t)
return np.float32(integral / math.gamma(a))

igamma_vec = np.vectorize(igamma_cal)
return igamma_vec(a, x)
25 changes: 25 additions & 0 deletions ivy/functional/backends/paddle/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,28 @@ def bincount(
return paddle.bincount(x, weights=weights, minlength=minlength).cast(
x.dtype if weights is None else weights.dtype
)


def igamma(
a: paddle.Tensor,
/,
*,
x: paddle.Tensor,
out: Optional[paddle.Tensor] = None,
) -> paddle.Tensor:
results = []
for ai, xi in zip(a.flatten(), x.flatten()):
ai = ai.astype("float64")
xi = xi.astype("float64")

def integrand(t):
return paddle.exp(-t) * paddle.pow(t, ai - 1)

intervals = paddle.linspace(0, xi, 10001).astype("float64")
interval_width = xi / 10000
values = integrand(intervals)
integral = paddle.multiply((values[:-1] + values[1:]) / 2, interval_width)
result = paddle.divide(paddle.sum(integral), paddle.exp(paddle.lgamma(ai)))
results.append(result)

return paddle.to_tensor(results, dtype="float32").reshape(a.shape)
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,9 @@ def bincount(
minlength=minlength,
dtype=x.dtype if weights is None else weights.dtype,
)


def igamma(
a: tf.Tensor, /, *, x: tf.Tensor, out: Optional[tf.Tensor] = None
) -> tf.Tensor:
return tf.math.igamma(a, x)
13 changes: 13 additions & 0 deletions ivy/functional/backends/torch/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,16 @@ def bincount(


bincount.support_native_out = False


def igamma(
a: torch.Tensor,
/,
*,
x: torch.Tensor,
out: Optional[torch.Tensor] = None,
) -> torch.Tensor:
return torch.special.gammainc(a, x, out=out)


igamma.support_native_out = True
39 changes: 39 additions & 0 deletions ivy/functional/ivy/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,42 @@ def bincount(
return ivy.current_backend(x).bincount(
x, weights=weights, minlength=minlength, out=out
)


@handle_exceptions
@handle_nestable
@handle_out_argument
@to_native_arrays_and_back
def igamma(
a: Union[ivy.Array, ivy.NativeArray],
/,
*,
x: Union[ivy.Array, ivy.NativeArray],
out: Optional[Union[ivy.Array, ivy.NativeArray]] = None,
) -> ivy.Array:
"""
Compute the regularized lower gamma function of ``a`` and ``x``.
Parameters
----------
self
Input array.
x
An additional input array.
`x` has the same type as `a`.
out
optional output array, for writing the result to.
Returns
-------
ret
The lower incomplete gamma function of the array elements.
Examples
--------
>>> a = ivy.array([2.5])
>>> x = ivy.array([1.7, 1.2])
>>> a.igamma(x)
ivy.array([0.3614, 0.2085])
"""
return ivy.current_backend().igamma(a, x=x, out=out)
Original file line number Diff line number Diff line change
Expand Up @@ -435,3 +435,45 @@ def test_bincount(
weights=x[1],
minlength=min_length,
)


# igamma
@handle_test(
fn_tree="functional.ivy.experimental.igamma",
dtype_and_x=helpers.dtype_and_values(
available_dtypes=["float32"],
num_arrays=2,
shared_dtype=True,
abs_smallest_val=1e-5,
min_num_dims=2,
max_num_dims=2,
min_dim_size=3,
max_dim_size=3,
min_value=2,
max_value=100,
allow_nan=False,
),
test_gradients=st.just(False),
test_with_out=st.just(False),
)
def test_igamma(
*,
dtype_and_x,
test_flags,
backend_fw,
fn_name,
on_device,
ground_truth_backend,
):
input_dtype, x = dtype_and_x
helpers.test_function(
ground_truth_backend=ground_truth_backend,
input_dtypes=input_dtype,
test_flags=test_flags,
on_device=on_device,
fw=backend_fw,
fn_name=fn_name,
rtol_=1e-04,
a=x[0],
x=x[1],
)

0 comments on commit ace246a

Please sign in to comment.