Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/array_api_extra/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Extra array functions built on top of the array API standard."""

from ._delegation import expand_dims, isclose, nan_to_num, one_hot, pad
from ._delegation import expand_dims, isclose, nan_to_num, one_hot, pad, sinc
from ._lib._at import at
from ._lib._funcs import (
apply_where,
Expand All @@ -12,7 +12,6 @@
kron,
nunique,
setdiff1d,
sinc,
)
from ._lib._lazy import lazy_apply

Expand Down
96 changes: 95 additions & 1 deletion src/array_api_extra/_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ._lib._utils._helpers import asarrays
from ._lib._utils._typing import Array, DType

__all__ = ["expand_dims", "isclose", "nan_to_num", "one_hot", "pad"]
__all__ = ["expand_dims", "isclose", "nan_to_num", "one_hot", "pad", "sinc"]


def expand_dims(
Expand Down Expand Up @@ -414,3 +414,97 @@ def pad(
return xp.nn.functional.pad(x, tuple(pad_width), value=constant_values) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]

return _funcs.pad(x, pad_width, constant_values=constant_values, xp=xp)


def sinc(x: Array, /, *, xp: ModuleType | None = None) -> Array:
r"""
Return the normalized sinc function.

The sinc function is equal to :math:`\sin(\pi x)/(\pi x)` for any argument
:math:`x\ne 0`. ``sinc(0)`` takes the limit value 1, making ``sinc`` not
only everywhere continuous but also infinitely differentiable.

.. note::

Note the normalization factor of ``pi`` used in the definition.
This is the most commonly used definition in signal processing.
Use ``sinc(x / xp.pi)`` to obtain the unnormalized sinc function
:math:`\sin(x)/x` that is more common in mathematics.

Parameters
----------
x : array
Array (possibly multi-dimensional) of values for which to calculate
``sinc(x)``. Must have a real floating point dtype.
xp : array_namespace, optional
The standard-compatible namespace for `x`. Default: infer.

Returns
-------
array
``sinc(x)`` calculated elementwise, which has the same shape as the input.

Notes
-----
The name sinc is short for "sine cardinal" or "sinus cardinalis".

The sinc function is used in various signal processing applications,
including in anti-aliasing, in the construction of a Lanczos resampling
filter, and in interpolation.

For bandlimited interpolation of discrete-time signals, the ideal
interpolation kernel is proportional to the sinc function.

References
----------
#. Weisstein, Eric W. "Sinc Function." From MathWorld--A Wolfram Web
Resource. https://mathworld.wolfram.com/SincFunction.html
#. Wikipedia, "Sinc function",
https://en.wikipedia.org/wiki/Sinc_function

Examples
--------
>>> import array_api_strict as xp
>>> import array_api_extra as xpx
>>> x = xp.linspace(-4, 4, 41)
>>> xpx.sinc(x, xp=xp)
Array([-3.89817183e-17, -4.92362781e-02,
-8.40918587e-02, -8.90384387e-02,
-5.84680802e-02, 3.89817183e-17,
6.68206631e-02, 1.16434881e-01,
1.26137788e-01, 8.50444803e-02,
-3.89817183e-17, -1.03943254e-01,
-1.89206682e-01, -2.16236208e-01,
-1.55914881e-01, 3.89817183e-17,
2.33872321e-01, 5.04551152e-01,
7.56826729e-01, 9.35489284e-01,
1.00000000e+00, 9.35489284e-01,
7.56826729e-01, 5.04551152e-01,
2.33872321e-01, 3.89817183e-17,
-1.55914881e-01, -2.16236208e-01,
-1.89206682e-01, -1.03943254e-01,
-3.89817183e-17, 8.50444803e-02,
1.26137788e-01, 1.16434881e-01,
6.68206631e-02, 3.89817183e-17,
-5.84680802e-02, -8.90384387e-02,
-8.40918587e-02, -4.92362781e-02,
-3.89817183e-17], dtype=array_api_strict.float64)
"""

if xp is None:
xp = array_namespace(x)

if not xp.isdtype(x.dtype, "real floating"):
err_msg = "`x` must have a real floating data type."
raise ValueError(err_msg)

if (
is_numpy_namespace(xp)
or is_cupy_namespace(xp)
or is_jax_namespace(xp)
or is_torch_namespace(xp)
or is_dask_namespace(xp)
):
return xp.sinc(x)

return _funcs.sinc(x, xp=xp)
82 changes: 3 additions & 79 deletions src/array_api_extra/_lib/_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,86 +864,10 @@ def setdiff1d(
return x1_[_helpers.in1d(x1_, x2_, assume_unique=True, invert=True, xp=xp)]


def sinc(x: Array, /, *, xp: ModuleType | None = None) -> Array:
r"""
Return the normalized sinc function.

The sinc function is equal to :math:`\sin(\pi x)/(\pi x)` for any argument
:math:`x\ne 0`. ``sinc(0)`` takes the limit value 1, making ``sinc`` not
only everywhere continuous but also infinitely differentiable.

.. note::

Note the normalization factor of ``pi`` used in the definition.
This is the most commonly used definition in signal processing.
Use ``sinc(x / xp.pi)`` to obtain the unnormalized sinc function
:math:`\sin(x)/x` that is more common in mathematics.

Parameters
----------
x : array
Array (possibly multi-dimensional) of values for which to calculate
``sinc(x)``. Must have a real floating point dtype.
xp : array_namespace, optional
The standard-compatible namespace for `x`. Default: infer.

Returns
-------
array
``sinc(x)`` calculated elementwise, which has the same shape as the input.

Notes
-----
The name sinc is short for "sine cardinal" or "sinus cardinalis".

The sinc function is used in various signal processing applications,
including in anti-aliasing, in the construction of a Lanczos resampling
filter, and in interpolation.

For bandlimited interpolation of discrete-time signals, the ideal
interpolation kernel is proportional to the sinc function.

References
----------
#. Weisstein, Eric W. "Sinc Function." From MathWorld--A Wolfram Web
Resource. https://mathworld.wolfram.com/SincFunction.html
#. Wikipedia, "Sinc function",
https://en.wikipedia.org/wiki/Sinc_function

Examples
--------
>>> import array_api_strict as xp
>>> import array_api_extra as xpx
>>> x = xp.linspace(-4, 4, 41)
>>> xpx.sinc(x, xp=xp)
Array([-3.89817183e-17, -4.92362781e-02,
-8.40918587e-02, -8.90384387e-02,
-5.84680802e-02, 3.89817183e-17,
6.68206631e-02, 1.16434881e-01,
1.26137788e-01, 8.50444803e-02,
-3.89817183e-17, -1.03943254e-01,
-1.89206682e-01, -2.16236208e-01,
-1.55914881e-01, 3.89817183e-17,
2.33872321e-01, 5.04551152e-01,
7.56826729e-01, 9.35489284e-01,
1.00000000e+00, 9.35489284e-01,
7.56826729e-01, 5.04551152e-01,
2.33872321e-01, 3.89817183e-17,
-1.55914881e-01, -2.16236208e-01,
-1.89206682e-01, -1.03943254e-01,
-3.89817183e-17, 8.50444803e-02,
1.26137788e-01, 1.16434881e-01,
6.68206631e-02, 3.89817183e-17,
-5.84680802e-02, -8.90384387e-02,
-8.40918587e-02, -4.92362781e-02,
-3.89817183e-17], dtype=array_api_strict.float64)
"""
if xp is None:
xp = array_namespace(x)
def sinc(x: Array, /, *, xp: ModuleType) -> Array:
# numpydoc ignore=PR01,RT01
"""See docstring in `array_api_extra._delegation.py`."""

if not xp.isdtype(x.dtype, "real floating"):
err_msg = "`x` must have a real floating data type."
raise ValueError(err_msg)
# no scalars in `where` - array-api#807
y = xp.pi * xp.where(
xp.astype(x, xp.bool),
Expand Down