Skip to content

Spectral Transforms

DST and DCT transforms (types I–IV) with optional orthonormal normalization. See the theory page for mathematical definitions.

1-D Transforms

dct(x, type=2, norm=None)

Discrete Cosine Transform of a 1-D vector.

Computes the DCT of x using an FFT-based O(N log N) algorithm. The default type is DCT-II:

Y[k] = 2 Sigma_{n=0}^{N-1} x[n] cos(pi k(2n+1) / (2N)),  k = 0, ..., N-1

All four types (I-IV) follow the scipy convention.

Parameters

x : Float[Array, " N"] Input 1-D array of length N. type : {1, 2, 3, 4} DCT variant. Default: 2. norm : {None, "ortho"} Normalization mode. None (default) gives the unnormalized transform (scipy.fft.dct(x, type, norm=None)). "ortho" scales the output so the transform matrix is orthogonal.

Returns

Float[Array, " N"] DCT of x, same shape as input.

Raises

ValueError If x is not 1-D, type is invalid, or norm is unrecognised.

Source code in spectraldiffx/_src/fourier/transforms.py
def dct(
    x: Float[Array, " N"],
    type: Literal[1, 2, 3, 4] = 2,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, " N"]:
    """Discrete Cosine Transform of a 1-D vector.

    Computes the DCT of *x* using an FFT-based O(N log N) algorithm.
    The default type is DCT-II:

        Y[k] = 2 Sigma_{n=0}^{N-1} x[n] cos(pi k(2n+1) / (2N)),  k = 0, ..., N-1

    All four types (I-IV) follow the scipy convention.

    Parameters
    ----------
    x : Float[Array, " N"]
        Input 1-D array of length N.
    type : {1, 2, 3, 4}
        DCT variant.  Default: 2.
    norm : {None, "ortho"}
        Normalization mode.  ``None`` (default) gives the unnormalized
        transform (``scipy.fft.dct(x, type, norm=None)``).  ``"ortho"``
        scales the output so the transform matrix is orthogonal.

    Returns
    -------
    Float[Array, " N"]
        DCT of *x*, same shape as input.

    Raises
    ------
    ValueError
        If *x* is not 1-D, *type* is invalid, or *norm* is unrecognised.
    """
    if x.ndim != 1:
        raise ValueError(
            f"dct expects a 1-D array, got ndim={x.ndim}. Use dctn for multi-dimensional input."
        )
    if type not in _DCT_IMPLS:
        raise ValueError(f"DCT type must be 1, 2, 3, or 4; got {type}")
    _validate_norm(norm)
    # DCT-I ortho requires a custom implementation (asymmetric weights)
    if norm == "ortho" and type == 1:
        return _dct1_ortho(x, axis=0)
    # Type 3 ortho requires pre-scaling the input
    if norm == "ortho" and type == 3:
        x = _prescale_type3(x, axis=0, transform="dct")
    y = _DCT_IMPLS[type](x, 0)
    if norm == "ortho":
        y = _apply_ortho_forward(y, type, axis=0, transform="dct")
    return y

dst(x, type=1, norm=None)

Discrete Sine Transform of a 1-D vector.

Computes the DST of x using an FFT-based O(N log N) algorithm. The default type is DST-I:

Y[k] = 2 Sigma_{n=0}^{N-1} x[n] sin(pi(n+1)(k+1) / (N+1)),  k = 0, ..., N-1

All four types (I-IV) follow the scipy convention.

Parameters

x : Float[Array, " N"] Input 1-D array of length N. type : {1, 2, 3, 4} DST variant. Default: 1. norm : {None, "ortho"} Normalization mode. None (default) gives the unnormalized transform. "ortho" scales the output so the transform matrix is orthogonal.

Returns

Float[Array, " N"] DST of x, same shape as input.

Raises

ValueError If x is not 1-D, type is invalid, or norm is unrecognised.

Source code in spectraldiffx/_src/fourier/transforms.py
def dst(
    x: Float[Array, " N"],
    type: Literal[1, 2, 3, 4] = 1,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, " N"]:
    """Discrete Sine Transform of a 1-D vector.

    Computes the DST of *x* using an FFT-based O(N log N) algorithm.
    The default type is DST-I:

        Y[k] = 2 Sigma_{n=0}^{N-1} x[n] sin(pi(n+1)(k+1) / (N+1)),  k = 0, ..., N-1

    All four types (I-IV) follow the scipy convention.

    Parameters
    ----------
    x : Float[Array, " N"]
        Input 1-D array of length N.
    type : {1, 2, 3, 4}
        DST variant.  Default: 1.
    norm : {None, "ortho"}
        Normalization mode.  ``None`` (default) gives the unnormalized
        transform.  ``"ortho"`` scales the output so the transform matrix
        is orthogonal.

    Returns
    -------
    Float[Array, " N"]
        DST of *x*, same shape as input.

    Raises
    ------
    ValueError
        If *x* is not 1-D, *type* is invalid, or *norm* is unrecognised.
    """
    if x.ndim != 1:
        raise ValueError(
            f"dst expects a 1-D array, got ndim={x.ndim}. Use dstn for multi-dimensional input."
        )
    if type not in _DST_IMPLS:
        raise ValueError(f"DST type must be 1, 2, 3, or 4; got {type}")
    _validate_norm(norm)
    if norm == "ortho" and type == 3:
        x = _prescale_type3(x, axis=0, transform="dst")
    y = _DST_IMPLS[type](x, 0)
    if norm == "ortho":
        y = _apply_ortho_forward(y, type, axis=0, transform="dst")
    return y

idct(x, type=2, norm=None)

Inverse Discrete Cosine Transform of a 1-D vector.

Satisfies idct(dct(x, t, norm=m), t, norm=m) == x for all types t in {1, 2, 3, 4} and normalization modes m in {None, "ortho"}.

Parameters

x : Float[Array, " N"] DCT-transformed 1-D array of length N. type : {1, 2, 3, 4} DCT variant of the forward transform to invert. norm : {None, "ortho"} Normalization mode — must match the mode used in the forward transform.

Returns

Float[Array, " N"] Reconstructed signal, same shape as x.

Raises

ValueError If x is not 1-D, type is invalid, or norm is unrecognised.

Source code in spectraldiffx/_src/fourier/transforms.py
def idct(
    x: Float[Array, " N"],
    type: Literal[1, 2, 3, 4] = 2,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, " N"]:
    """Inverse Discrete Cosine Transform of a 1-D vector.

    Satisfies ``idct(dct(x, t, norm=m), t, norm=m) == x`` for all types
    t in {1, 2, 3, 4} and normalization modes m in {None, "ortho"}.

    Parameters
    ----------
    x : Float[Array, " N"]
        DCT-transformed 1-D array of length N.
    type : {1, 2, 3, 4}
        DCT variant of the *forward* transform to invert.
    norm : {None, "ortho"}
        Normalization mode — must match the mode used in the forward transform.

    Returns
    -------
    Float[Array, " N"]
        Reconstructed signal, same shape as *x*.

    Raises
    ------
    ValueError
        If *x* is not 1-D, *type* is invalid, or *norm* is unrecognised.
    """
    if x.ndim != 1:
        raise ValueError(
            f"idct expects a 1-D array, got ndim={x.ndim}. Use idctn for multi-dimensional input."
        )
    _validate_norm(norm)
    # Ortho DCT-I is self-inverse (symmetric orthogonal matrix)
    if norm == "ortho" and type == 1:
        return _dct1_ortho(x, axis=0)
    if norm == "ortho":
        x = _remove_ortho_forward(x, type, axis=0, transform="dct")
    y = _idct_along_axis(x, type, axis=0)
    # Type 3 ortho: undo the pre-scaling applied in the forward pass
    if norm == "ortho" and type == 3:
        y = _undo_prescale_type3(y, axis=0, transform="dct")
    return y

idst(x, type=1, norm=None)

Inverse Discrete Sine Transform of a 1-D vector.

Satisfies idst(dst(x, t, norm=m), t, norm=m) == x for all types t in {1, 2, 3, 4} and normalization modes m in {None, "ortho"}.

Parameters

x : Float[Array, " N"] DST-transformed 1-D array of length N. type : {1, 2, 3, 4} DST variant of the forward transform to invert. norm : {None, "ortho"} Normalization mode — must match the mode used in the forward transform.

Returns

Float[Array, " N"] Reconstructed signal, same shape as x.

Raises

ValueError If x is not 1-D, type is invalid, or norm is unrecognised.

Source code in spectraldiffx/_src/fourier/transforms.py
def idst(
    x: Float[Array, " N"],
    type: Literal[1, 2, 3, 4] = 1,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, " N"]:
    """Inverse Discrete Sine Transform of a 1-D vector.

    Satisfies ``idst(dst(x, t, norm=m), t, norm=m) == x`` for all types
    t in {1, 2, 3, 4} and normalization modes m in {None, "ortho"}.

    Parameters
    ----------
    x : Float[Array, " N"]
        DST-transformed 1-D array of length N.
    type : {1, 2, 3, 4}
        DST variant of the *forward* transform to invert.
    norm : {None, "ortho"}
        Normalization mode — must match the mode used in the forward transform.

    Returns
    -------
    Float[Array, " N"]
        Reconstructed signal, same shape as *x*.

    Raises
    ------
    ValueError
        If *x* is not 1-D, *type* is invalid, or *norm* is unrecognised.
    """
    if x.ndim != 1:
        raise ValueError(
            f"idst expects a 1-D array, got ndim={x.ndim}. Use idstn for multi-dimensional input."
        )
    _validate_norm(norm)
    if norm == "ortho":
        x = _remove_ortho_forward(x, type, axis=0, transform="dst")
    y = _idst_along_axis(x, type, axis=0)
    if norm == "ortho" and type == 3:
        y = _undo_prescale_type3(y, axis=0, transform="dst")
    return y

N-D Transforms

dctn(x, type=2, axes=None, norm=None)

N-dimensional DCT: apply DCT sequentially along each axis.

For a 2-D array with axes=[0, 1], this computes the separable transform DCT_y(DCT_x(x)). The result is identical to applying the 1-D DCT independently along each axis in sequence.

Parameters

x : Float[Array, "..."] Input array of any dimensionality. type : {1, 2, 3, 4} DCT variant. Default: 2. axes : sequence of int or None Axes to transform. None transforms all axes. norm : {None, "ortho"} Normalization mode.

Returns

Float[Array, "..."] N-D DCT of x, same shape as input.

Source code in spectraldiffx/_src/fourier/transforms.py
def dctn(
    x: Float[Array, ...],
    type: Literal[1, 2, 3, 4] = 2,
    axes: Sequence[int] | None = None,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, ...]:
    """N-dimensional DCT: apply DCT sequentially along each axis.

    For a 2-D array with ``axes=[0, 1]``, this computes the separable
    transform ``DCT_y(DCT_x(x))``.  The result is identical to applying the
    1-D DCT independently along each axis in sequence.

    Parameters
    ----------
    x : Float[Array, "..."]
        Input array of any dimensionality.
    type : {1, 2, 3, 4}
        DCT variant.  Default: 2.
    axes : sequence of int or None
        Axes to transform.  ``None`` transforms all axes.
    norm : {None, "ortho"}
        Normalization mode.

    Returns
    -------
    Float[Array, "..."]
        N-D DCT of *x*, same shape as input.
    """
    if type not in _DCT_IMPLS:
        raise ValueError(f"DCT type must be 1, 2, 3, or 4; got {type}")
    _validate_norm(norm)
    if axes is None:
        axes = list(range(x.ndim))
    y = x
    for ax in axes:
        a = _norm_axis(ax, y.ndim)
        if norm == "ortho" and type == 1:
            y = _dct1_ortho(y, a)
        else:
            if norm == "ortho" and type == 3:
                y = _prescale_type3(y, a, "dct")
            y = _DCT_IMPLS[type](y, a)
            if norm == "ortho":
                y = _apply_ortho_forward(y, type, a, "dct")
    return y

dstn(x, type=1, axes=None, norm=None)

N-dimensional DST: apply DST sequentially along each axis.

For a 2-D array with axes=[0, 1], this computes the separable transform DST_y(DST_x(x)). The result is identical to applying the 1-D DST independently along each axis in sequence.

Parameters

x : Float[Array, "..."] Input array of any dimensionality. type : {1, 2, 3, 4} DST variant. Default: 1. axes : sequence of int or None Axes to transform. None transforms all axes. norm : {None, "ortho"} Normalization mode.

Returns

Float[Array, "..."] N-D DST of x, same shape as input.

Source code in spectraldiffx/_src/fourier/transforms.py
def dstn(
    x: Float[Array, ...],
    type: Literal[1, 2, 3, 4] = 1,
    axes: Sequence[int] | None = None,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, ...]:
    """N-dimensional DST: apply DST sequentially along each axis.

    For a 2-D array with ``axes=[0, 1]``, this computes the separable
    transform ``DST_y(DST_x(x))``.  The result is identical to applying the
    1-D DST independently along each axis in sequence.

    Parameters
    ----------
    x : Float[Array, "..."]
        Input array of any dimensionality.
    type : {1, 2, 3, 4}
        DST variant.  Default: 1.
    axes : sequence of int or None
        Axes to transform.  ``None`` transforms all axes.
    norm : {None, "ortho"}
        Normalization mode.

    Returns
    -------
    Float[Array, "..."]
        N-D DST of *x*, same shape as input.
    """
    if type not in _DST_IMPLS:
        raise ValueError(f"DST type must be 1, 2, 3, or 4; got {type}")
    _validate_norm(norm)
    if axes is None:
        axes = list(range(x.ndim))
    y = x
    for ax in axes:
        a = _norm_axis(ax, y.ndim)
        if norm == "ortho" and type == 3:
            y = _prescale_type3(y, a, "dst")
        y = _DST_IMPLS[type](y, a)
        if norm == "ortho":
            y = _apply_ortho_forward(y, type, a, "dst")
    return y

idctn(x, type=2, axes=None, norm=None)

N-dimensional inverse DCT: apply IDCT sequentially along each axis.

Satisfies idctn(dctn(x, t, axes, norm=m), t, axes, norm=m) == x. The inverse is separable — each axis is inverted independently.

Parameters

x : Float[Array, "..."] DCT-transformed array. type : {1, 2, 3, 4} DCT variant of the forward transform to invert. axes : sequence of int or None Axes to inverse-transform. None transforms all axes. norm : {None, "ortho"} Normalization mode — must match the forward transform.

Returns

Float[Array, "..."] Reconstructed N-D array, same shape as input.

Source code in spectraldiffx/_src/fourier/transforms.py
def idctn(
    x: Float[Array, ...],
    type: Literal[1, 2, 3, 4] = 2,
    axes: Sequence[int] | None = None,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, ...]:
    """N-dimensional inverse DCT: apply IDCT sequentially along each axis.

    Satisfies ``idctn(dctn(x, t, axes, norm=m), t, axes, norm=m) == x``.
    The inverse is separable — each axis is inverted independently.

    Parameters
    ----------
    x : Float[Array, "..."]
        DCT-transformed array.
    type : {1, 2, 3, 4}
        DCT variant of the *forward* transform to invert.
    axes : sequence of int or None
        Axes to inverse-transform.  ``None`` transforms all axes.
    norm : {None, "ortho"}
        Normalization mode — must match the forward transform.

    Returns
    -------
    Float[Array, "..."]
        Reconstructed N-D array, same shape as input.
    """
    _validate_norm(norm)
    if axes is None:
        axes = list(range(x.ndim))
    y = x
    for ax in axes:
        a = _norm_axis(ax, y.ndim)
        if norm == "ortho" and type == 1:
            y = _dct1_ortho(y, a)
        else:
            if norm == "ortho":
                y = _remove_ortho_forward(y, type, a, "dct")
            y = _idct_along_axis(y, type, a)
            if norm == "ortho" and type == 3:
                y = _undo_prescale_type3(y, a, "dct")
    return y

idstn(x, type=1, axes=None, norm=None)

N-dimensional inverse DST: apply IDST sequentially along each axis.

Satisfies idstn(dstn(x, t, axes, norm=m), t, axes, norm=m) == x. The inverse is separable — each axis is inverted independently.

Parameters

x : Float[Array, "..."] DST-transformed array. type : {1, 2, 3, 4} DST variant of the forward transform to invert. axes : sequence of int or None Axes to inverse-transform. None transforms all axes. norm : {None, "ortho"} Normalization mode — must match the forward transform.

Returns

Float[Array, "..."] Reconstructed N-D array, same shape as input.

Source code in spectraldiffx/_src/fourier/transforms.py
def idstn(
    x: Float[Array, ...],
    type: Literal[1, 2, 3, 4] = 1,
    axes: Sequence[int] | None = None,
    norm: Literal["ortho"] | None = None,
) -> Float[Array, ...]:
    """N-dimensional inverse DST: apply IDST sequentially along each axis.

    Satisfies ``idstn(dstn(x, t, axes, norm=m), t, axes, norm=m) == x``.
    The inverse is separable — each axis is inverted independently.

    Parameters
    ----------
    x : Float[Array, "..."]
        DST-transformed array.
    type : {1, 2, 3, 4}
        DST variant of the *forward* transform to invert.
    axes : sequence of int or None
        Axes to inverse-transform.  ``None`` transforms all axes.
    norm : {None, "ortho"}
        Normalization mode — must match the forward transform.

    Returns
    -------
    Float[Array, "..."]
        Reconstructed N-D array, same shape as input.
    """
    _validate_norm(norm)
    if axes is None:
        axes = list(range(x.ndim))
    y = x
    for ax in axes:
        a = _norm_axis(ax, y.ndim)
        if norm == "ortho":
            y = _remove_ortho_forward(y, type, a, "dst")
        y = _idst_along_axis(y, type, a)
        if norm == "ortho" and type == 3:
            y = _undo_prescale_type3(y, a, "dst")
    return y