Source code for dpnp.scipy.linalg._decomp_cholesky

# *****************************************************************************
# Copyright (c) 2026, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
#   this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
# - Neither the name of the copyright holder nor the names of its contributors
#   may be used to endorse or promote products derived from this software
#   without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
# *****************************************************************************


"""
Interface of the SciPy-compatible Linear Algebra subset for DPNP.

Notes
-----
This module exposes the public API for ``dpnp.scipy.linalg``.
It contains:
 - SciPy-like interface functions
 - documentation for the functions

"""

import dpnp

from ._utils import (
    dpnp_cho_factor,
    dpnp_cho_solve,
)


def _lower_to_bool(lower, empty_ok=False):
    """
    Convert `lower` to bool, also accepting an array or a sequence of equal
    values. An empty `lower` is accepted only if `empty_ok` is ``True``
    (a zero-size batch of factors).

    """

    lower = dpnp.asnumpy(lower)
    if lower.dtype.kind not in "biuf":
        raise ValueError("`lower` must be a bool or an array of bool.")

    if lower.size != 1:
        if lower.size == 0:
            if empty_ok:
                return False
            raise ValueError("`lower` must not be empty.")
        if not (lower == lower.flat[0]).all():
            raise ValueError("All values of `lower` must be equal.")
        lower = lower.flat[0]
    return bool(lower)


[docs] def cho_factor(a, lower=False, overwrite_a=False, check_finite=True): """ Compute the Cholesky decomposition of a matrix, to use in :obj:`dpnp.scipy.linalg.cho_solve`. Returns a matrix containing the Cholesky decomposition, ``A = L L*`` or ``A = U* U`` of a Hermitian positive-definite matrix `a`. The return value can be directly used as the first parameter to :obj:`dpnp.scipy.linalg.cho_solve`. For full documentation refer to :obj:`scipy.linalg.cho_factor`. Parameters ---------- a : (..., M, M) {dpnp.ndarray, usm_ndarray} Matrix to be decomposed. lower : {bool, array_like of bool}, optional Whether to compute the upper or lower triangular Cholesky factorization. An array or a sequence is accepted if all its values are equal. Default: ``False``. overwrite_a : bool, optional Whether to overwrite data in `a` (may improve performance). Default: ``False``. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: ``True``. Returns ------- c : (..., M, M) dpnp.ndarray Matrix whose upper or lower triangle contains the Cholesky factor of `a`. If `a` is not overwritten, the other triangle is zeroed, otherwise it contains the data of `a` not used by the decomposition. lower : bool Flag indicating whether the factor is in the lower or upper triangle. Unlike SciPy, which returns it as an array tiled to the batch shape, a Python bool is returned. Raises ------ dpnp.linalg.LinAlgError If the decomposition fails. ValueError If `a` is not square, if `lower` is empty, not bool or its values are not all equal, or if ``check_finite=True`` and `a` contains infinities or NaNs. Warnings -------- This function synchronizes in order to validate array elements when ``check_finite=True``, and to check the factorization status. See Also -------- :func:`dpnp.scipy.linalg.cho_solve` : Solve a linear set equations using the Cholesky factorization of a matrix. :func:`dpnp.linalg.cholesky` : Cholesky decomposition of a matrix. Notes ----- During the finiteness check (if selected), the entire matrix `a` is checked. During decomposition, `a` is assumed to be symmetric or Hermitian (as applicable), and only the half selected by option `lower` is referenced. Examples -------- >>> import dpnp as np >>> A = np.array([[9., 3., 1., 5.], [3., 7., 5., 1.], ... [1., 5., 9., 2.], [5., 1., 2., 6.]]) >>> c, low = np.scipy.linalg.cho_factor(A) >>> c array([[ 3. , 1. , 0.33333333, 1.66666667], [ 0. , 2.44948974, 1.90515869, -0.27216553], [ 0. , 0. , 2.29330749, 0.8559528 ], [ 0. , 0. , 0. , 1.55418563]]) >>> np.allclose(c.T @ c, A) array(True) Batched input: >>> B = np.stack([A, 2 * A]) >>> c, low = np.scipy.linalg.cho_factor(B, lower=True) >>> np.allclose(c @ c.mT, B) array(True) """ dpnp.check_supported_arrays_type(a) # as in SciPy, a 0-D or 1-D input is viewed as a matrix a1 = dpnp.atleast_2d(a) if a1.shape[-1] != a1.shape[-2]: raise ValueError( "Expected a square matrix or batch thereof, " f"got a1.shape={a1.shape}" ) return dpnp_cho_factor( a1, lower=_lower_to_bool(lower), overwrite_a=overwrite_a, check_finite=check_finite, )
[docs] def cho_solve(c_and_lower, b, overwrite_b=False, check_finite=True): """ Solve the linear equations ``A x = b``, given the Cholesky factorization of `A`. For full documentation refer to :obj:`scipy.linalg.cho_solve`. Parameters ---------- (c, lower) : tuple, ({dpnp.ndarray, usm_ndarray}, bool) Cholesky factorization of `A` (..., M, M), as given by :obj:`dpnp.scipy.linalg.cho_factor`. `lower` can also be an array or a sequence whose values are all equal. b : {(M,), (..., M, K)} {dpnp.ndarray, usm_ndarray} Right-hand side. overwrite_b : bool, optional Whether to overwrite data in `b` (may improve performance). Default: ``False``. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: ``True``. Returns ------- x : {(M,), (..., M, K)} dpnp.ndarray The solution to the system ``A x = b``. Raises ------ ValueError If `c` is not square, if the shapes of `c` and `b` are incompatible, if `lower` is empty for a non-empty batch of factors, not bool or its values are not all equal, or if ``check_finite=True`` and `c` or `b` contains infinities or NaNs. Warnings -------- This function synchronizes in order to validate array elements when ``check_finite=True``, and to read `lower` given as a dpnp array. See Also -------- :func:`dpnp.scipy.linalg.cho_factor` : Cholesky factorization of a matrix. Notes ----- Unlike SciPy, a zero-size batch is supported and gives an empty solution. Examples -------- >>> import dpnp as np >>> A = np.array([[9., 3., 1., 5.], [3., 7., 5., 1.], ... [1., 5., 9., 2.], [5., 1., 2., 6.]]) >>> c, low = np.scipy.linalg.cho_factor(A) >>> x = np.scipy.linalg.cho_solve((c, low), np.ones(4)) >>> x array([-0.01749271, 0.11953353, 0.01166181, 0.1574344 ]) >>> np.allclose(A @ x, np.ones(4)) array(True) """ c, lower = c_and_lower dpnp.check_supported_arrays_type(c, b) if c.ndim < 2 or c.shape[-1] != c.shape[-2]: raise ValueError("The factored matrix c is not square.") return dpnp_cho_solve( c, _lower_to_bool(lower, empty_ok=0 in c.shape[:-2]), b, overwrite_b=overwrite_b, check_finite=check_finite, )