# Path: scvelo/core/_arithmetic.py
# def prod_sum(
#     a1: Union[ndarray, spmatrix], a2: Union[ndarray, spmatrix], axis: Optional[int]
# ) -> ndarray:
#     """Take sum of product of two arrays along given axis.
# 
#     Arguments
#     ---------
#     a1
#         First array.
#     a2
#         Second array.
#     axis
#         Axis along which to sum elements. If `None`, all elements will be summed.
#         Defaults to `None`.
# 
#     Returns
#     -------
#     ndarray
#         Sum of product of arrays along given axis.
#     """
# 
#     if issparse(a1):
#         return a1.multiply(a2).sum(axis=axis).A1
#     elif axis == 0:
#         return np.einsum("ij, ij -> j", a1, a2) if a1.ndim > 1 else (a1 * a2).sum()
#     elif axis == 1:
#         return np.einsum("ij, ij -> i", a1, a2) if a1.ndim > 1 else (a1 * a2).sum()
# 
# def sum(a: Union[ndarray, spmatrix], axis: Optional[int] = None) -> ndarray:
#     """Sum array elements over a given axis.
# 
#     Arguments
#     ---------
#     a
#         Elements to sum.
#     axis
#         Axis along which to sum elements. If `None`, all elements will be summed.
#         Defaults to `None`.
# 
#     Returns
#     -------
#     ndarray
#         Sum of array along given axis.
#     """
# 
#     if a.ndim == 1:
#         axis = 0
# 
#     with warnings.catch_warnings():
#         warnings.simplefilter("ignore")
#         return a.sum(axis=axis).A1 if issparse(a) else a.sum(axis=axis)


from typing import List, Optional, Tuple, Union
from numpy import ndarray
from scipy.sparse import csr_matrix, issparse
from ._arithmetic import prod_sum, sum
import numpy as np

        if constrain_ratio is None:
            self.constrain_ratio = [-np.inf, np.inf]
        elif len(constrain_ratio) == 1:
            self.constrain_ratio = [-np.inf, constrain_ratio]
        else:
            self.constrain_ratio = constrain_ratio

    def _trim_data(self, data: List) -> List:
        """Trim data to extreme values.

        Arguments
        ---------
        data
            Data to be trimmed to extreme quantiles.

        Returns
        -------
        List
            Number of non-trivial entries per column and trimmed data.
        """

        if not isinstance(data, List):
            data = [data]

        data = np.array(
            [data_mat.A if issparse(data_mat) else data_mat for data_mat in data]
        )

        # TODO: Add explanatory comment

# Path: scvelo/core/_arithmetic.py
# def prod_sum(
#     a1: Union[ndarray, spmatrix], a2: Union[ndarray, spmatrix], axis: Optional[int]
# ) -> ndarray:
#     """Take sum of product of two arrays along given axis.
# 
#     Arguments
#     ---------
#     a1
#         First array.
#     a2
#         Second array.
#     axis
#         Axis along which to sum elements. If `None`, all elements will be summed.
#         Defaults to `None`.
# 
#     Returns
#     -------
#     ndarray
#         Sum of product of arrays along given axis.
#     """
# 
#     if issparse(a1):
#         return a1.multiply(a2).sum(axis=axis).A1
#     elif axis == 0:
#         return np.einsum("ij, ij -> j", a1, a2) if a1.ndim > 1 else (a1 * a2).sum()
#     elif axis == 1:
#         return np.einsum("ij, ij -> i", a1, a2) if a1.ndim > 1 else (a1 * a2).sum()
# 
# def sum(a: Union[ndarray, spmatrix], axis: Optional[int] = None) -> ndarray:
#     """Sum array elements over a given axis.
# 
#     Arguments
#     ---------
#     a
#         Elements to sum.
#     axis
#         Axis along which to sum elements. If `None`, all elements will be summed.
#         Defaults to `None`.
# 
#     Returns
#     -------
#     ndarray
#         Sum of array along given axis.
#     """
# 
#     if a.ndim == 1:
#         axis = 0
# 
#     with warnings.catch_warnings():
#         warnings.simplefilter("ignore")
#         return a.sum(axis=axis).A1 if issparse(a) else a.sum(axis=axis)


# Path: scvelo/core/_linear_models.py
from typing import List, Optional, Tuple, Union
from numpy import ndarray
from scipy.sparse import csr_matrix, issparse
from ._arithmetic import prod_sum, sum
import numpy as np


        if constrain_ratio is None:
            self.constrain_ratio = [-np.inf, np.inf]
        elif len(constrain_ratio) == 1:
            self.constrain_ratio = [-np.inf, constrain_ratio]
        else:
            self.constrain_ratio = constrain_ratio

    def _trim_data(self, data: List) -> List:
        """Trim data to extreme values.

        Arguments
        ---------
        data
            Data to be trimmed to extreme quantiles.

        Returns
        -------
        List
            Number of non-trivial entries per column and trimmed data.
        """

        if not isinstance(data, List):
            data = [data]

        data = np.array(
            [data_mat.A if issparse(data_mat) else data_mat for data_mat in data]
        )

        # TODO: Add explanatory comment

        normalized_data = np.sum(