NumPy 源码解析(四十)

.\numpy\numpy\lib\_stride_tricks_impl.py

"""
Utilities that manipulate strides to achieve desirable effects.

An explanation of strides can be found in the :ref:`arrays.ndarray`.

Functions
---------

.. autosummary::
   :toctree: generated/

"""
import numpy as np
from numpy._core.numeric import normalize_axis_tuple
from numpy._core.overrides import array_function_dispatch, set_module

__all__ = ['broadcast_to', 'broadcast_arrays', 'broadcast_shapes']


class DummyArray:
    """Dummy object that just exists to hang __array_interface__ dictionaries
    and possibly keep alive a reference to a base array.
    """

    def __init__(self, interface, base=None):
        self.__array_interface__ = interface
        self.base = base


def _maybe_view_as_subclass(original_array, new_array):
    if type(original_array) is not type(new_array):
        # if input was an ndarray subclass and subclasses were OK,
        # then view the result as that subclass.
        new_array = new_array.view(type=type(original_array))
        # Since we have done something akin to a view from original_array, we
        # should let the subclass finalize (if it has it implemented, i.e., is
        # not None).
        if new_array.__array_finalize__:
            new_array.__array_finalize__(original_array)
    return new_array


@set_module("numpy.lib.stride_tricks")
def as_strided(x, shape=None, strides=None, subok=False, writeable=True):
    """
    Create a view into the array with the given shape and strides.

    .. warning:: This function has to be used with extreme care, see notes.

    Parameters
    ----------
    x : ndarray
        Array to create a new.
    shape : sequence of int, optional
        The shape of the new array. Defaults to ``x.shape``.
    strides : sequence of int, optional
        The strides of the new array. Defaults to ``x.strides``.
    subok : bool, optional
        .. versionadded:: 1.10

        If True, subclasses are preserved.
    writeable : bool, optional
        .. versionadded:: 1.12

        If set to False, the returned array will always be readonly.
        Otherwise it will be writable if the original array was. It
        is advisable to set this to False if possible (see Notes).

    Returns
    -------
    view : ndarray

    See also
    --------
    broadcast_to : broadcast an array to a given shape.
    reshape : reshape an array.
    lib.stride_tricks.sliding_window_view :
        userfriendly and safe function for a creation of sliding window views.

    Notes
    -----
    ``as_strided`` creates a view into the array given the exact strides
    and shape. This means it manipulates the internal data structure of
    ndarray and, if done incorrectly, the array elements can point to
    invalid memory and can corrupt results or crash your program.
    It is advisable to always use the original ``x.strides`` when
    calculating new strides to avoid reliance on a contiguous memory
    layout.
    """
    # 设置所返回数组的默认形状为输入数组的形状
    shape = x.shape if shape is None else shape
    # 设置所返回数组的默认步幅为输入数组的步幅
    strides = x.strides if strides is None else strides
    # 返回一个数组视图,这个函数要谨慎使用,遵循函数中的警告和注意事项
    return np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides, subok=subok, writeable=writeable)
    """
        Furthermore, arrays created with this function often contain self
        overlapping memory, so that two elements are identical.
        Vectorized write operations on such arrays will typically be
        unpredictable. They may even give different results for small, large,
        or transposed arrays.
    
        Since writing to these arrays has to be tested and done with great
        care, you may want to use ``writeable=False`` to avoid accidental write
        operations.
    
        For these reasons it is advisable to avoid ``as_strided`` when
        possible.
    """
    # 首先将输入转换为数组,可能保留子类
    x = np.array(x, copy=None, subok=subok)
    # 获取数组的 __array_interface__,并存储为字典
    interface = dict(x.__array_interface__)
    # 如果指定了形状,则将其设置到接口字典中
    if shape is not None:
        interface['shape'] = tuple(shape)
    # 如果指定了步幅,则将其设置到接口字典中
    if strides is not None:
        interface['strides'] = tuple(strides)
    
    # 创建一个虚拟的 DummyArray 对象,并转换为 NumPy 数组
    array = np.asarray(DummyArray(interface, base=x))
    # 由于通过 `__interface__` 创建的数组不保留结构化 dtype,我们显式设置 dtype
    array.dtype = x.dtype
    
    # 尝试将结果视图返回为原始数组的子类视图
    view = _maybe_view_as_subclass(x, array)
    
    # 如果视图可写而且不允许写入,则将视图设置为不可写
    if view.flags.writeable and not writeable:
        view.flags.writeable = False
    
    # 返回视图对象
    return view
# 定义函数 `_sliding_window_view_dispatcher`,用于分派到适当的函数处理器
def _sliding_window_view_dispatcher(x, window_shape, axis=None, *,
                                    subok=None, writeable=None):
    # 返回输入数组 `x` 本身,表示暂时只做了分派的处理
    return (x,)


# 使用装饰器 `array_function_dispatch`,将函数 `_sliding_window_view_dispatcher` 注册到模块 `numpy.lib.stride_tricks`
@array_function_dispatch(
    _sliding_window_view_dispatcher, module="numpy.lib.stride_tricks"
)
# 定义函数 `sliding_window_view`,创建一个滑动窗口视图,从给定的数组 `x` 中生成
def sliding_window_view(x, window_shape, axis=None, *,
                        subok=False, writeable=False):
    """
    Create a sliding window view into the array with the given window shape.

    Also known as rolling or moving window, the window slides across all
    dimensions of the array and extracts subsets of the array at all window
    positions.

    .. versionadded:: 1.20.0

    Parameters
    ----------
    x : array_like
        Array to create the sliding window view from.
    window_shape : int or tuple of int
        Size of window over each axis that takes part in the sliding window.
        If `axis` is not present, must have same length as the number of input
        array dimensions. Single integers `i` are treated as if they were the
        tuple `(i,)`.
    axis : int or tuple of int, optional
        Axis or axes along which the sliding window is applied.
        By default, the sliding window is applied to all axes and
        `window_shape[i]` will refer to axis `i` of `x`.
        If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to
        the axis `axis[i]` of `x`.
        Single integers `i` are treated as if they were the tuple `(i,)`.
    subok : bool, optional
        If True, sub-classes will be passed-through, otherwise the returned
        array will be forced to be a base-class array (default).
    writeable : bool, optional
        When true, allow writing to the returned view. The default is false,
        as this should be used with caution: the returned view contains the
        same memory location multiple times, so writing to one location will
        cause others to change.

    Returns
    -------
    view : ndarray
        Sliding window view of the array. The sliding window dimensions are
        inserted at the end, and the original dimensions are trimmed as
        required by the size of the sliding window.
        That is, ``view.shape = x_shape_trimmed + window_shape``, where
        ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less
        than the corresponding window size.

    See Also
    --------
    lib.stride_tricks.as_strided: A lower-level and less safe routine for
        creating arbitrary views from custom shape and strides.
    broadcast_to: broadcast an array to a given shape.

    Notes
    -----
    For many applications using a sliding window view can be convenient, but
    potentially very slow. Often specialized solutions exist, for example:

    - `scipy.signal.fftconvolve`

    - filtering functions in `scipy.ndimage`

    - moving window functions provided by
      `bottleneck <https://github.com/pydata/bottleneck>`_.
    """
    # 返回滑动窗口视图的 ndarray 对象,通过 numpy 的库函数来实现
    # 参数 `subok` 和 `writeable` 默认为 `False`
    return np.lib.stride_tricks.sliding_window_view(x, window_shape, axis, subok=subok, writeable=writeable)
    """
    As a rough estimate, a sliding window approach with an input size of `N`
    and a window size of `W` will scale as `O(N*W)` where frequently a special
    algorithm can achieve `O(N)`. That means that the sliding window variant
    for a window size of 100 can be a 100 times slower than a more specialized
    version.

    Nevertheless, for small window sizes, when no custom algorithm exists, or
    as a prototyping and developing tool, this function can be a good solution.

    Examples
    --------
    >>> from numpy.lib.stride_tricks import sliding_window_view
    >>> x = np.arange(6)
    >>> x.shape
    (6,)
    >>> v = sliding_window_view(x, 3)
    >>> v.shape
    (4, 3)
    >>> v
    array([[0, 1, 2],
           [1, 2, 3],
           [2, 3, 4],
           [3, 4, 5]])

    This also works in more dimensions, e.g.

    >>> i, j = np.ogrid[:3, :4]
    >>> x = 10*i + j
    >>> x.shape
    (3, 4)
    >>> x
    array([[ 0,  1,  2,  3],
           [10, 11, 12, 13],
           [20, 21, 22, 23]])
    >>> shape = (2,2)
    >>> v = sliding_window_view(x, shape)
    >>> v.shape
    (2, 3, 2, 2)
    >>> v
    array([[[[ 0,  1],
             [10, 11]],
            [[ 1,  2],
             [11, 12]],
            [[ 2,  3],
             [12, 13]]],
           [[[10, 11],
             [20, 21]],
            [[11, 12],
             [21, 22]],
            [[12, 13],
             [22, 23]]]])

    The axis can be specified explicitly:

    >>> v = sliding_window_view(x, 3, 0)
    >>> v.shape
    (1, 4, 3)
    >>> v
    array([[[ 0, 10, 20],
            [ 1, 11, 21],
            [ 2, 12, 22],
            [ 3, 13, 23]]])

    The same axis can be used several times. In that case, every use reduces
    the corresponding original dimension:

    >>> v = sliding_window_view(x, (2, 3), (1, 1))
    >>> v.shape
    (3, 1, 2, 3)
    >>> v
    array([[[[ 0,  1,  2],
             [ 1,  2,  3]]],
           [[[10, 11, 12],
             [11, 12, 13]]],
           [[[20, 21, 22],
             [21, 22, 23]]]])

    Combining with stepped slicing (`::step`), this can be used to take sliding
    views which skip elements:

    >>> x = np.arange(7)
    >>> sliding_window_view(x, 5)[:, ::2]
    array([[0, 2, 4],
           [1, 3, 5],
           [2, 4, 6]])

    or views which move by multiple elements

    >>> x = np.arange(7)
    >>> sliding_window_view(x, 3)[::2, :]
    array([[0, 1, 2],
           [2, 3, 4],
           [4, 5, 6]])

    A common application of `sliding_window_view` is the calculation of running
    statistics. The simplest example is the
    `moving average <https://en.wikipedia.org/wiki/Moving_average>`_:

    >>> x = np.arange(6)
    >>> x.shape
    (6,)
    >>> v = sliding_window_view(x, 3)
    >>> v.shape
    (4, 3)
    >>> v
    array([[0, 1, 2],
           [1, 2, 3],
           [2, 3, 4],
           [3, 4, 5]])
    >>> moving_average = v.mean(axis=-1)
    >>> moving_average
    array([1., 2., 3., 4.])
    """
    Note that a sliding window approach is often **not** optimal (see Notes).
    """
    # 将窗口形状转换为元组,如果window_shape是可迭代对象的话;否则转换为单元素元组
    window_shape = (tuple(window_shape)
                    if np.iterable(window_shape)
                    else (window_shape,))

    # 将输入数组转换为numpy数组,保留可能存在的子类
    x = np.array(x, copy=None, subok=subok)

    # 将窗口形状转换为numpy数组
    window_shape_array = np.array(window_shape)

    # 检查窗口形状数组中是否有负值,若有则引发ValueError异常
    if np.any(window_shape_array < 0):
        raise ValueError('`window_shape` cannot contain negative values')

    # 如果axis为None,则默认使用所有维度的轴
    if axis is None:
        axis = tuple(range(x.ndim))
        # 检查window_shape与x的维度数是否一致,若不一致则引发ValueError异常
        if len(window_shape) != len(axis):
            raise ValueError(f'Since axis is `None`, must provide '
                             f'window_shape for all dimensions of `x`; '
                             f'got {len(window_shape)} window_shape elements '
                             f'and `x.ndim` is {x.ndim}.')
    else:
        # 标准化axis,确保所有轴都在有效范围内
        axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True)
        # 检查window_shape与axis的长度是否一致,若不一致则引发ValueError异常
        if len(window_shape) != len(axis):
            raise ValueError(f'Must provide matching length window_shape and '
                             f'axis; got {len(window_shape)} window_shape '
                             f'elements and {len(axis)} axes elements.')

    # 计算输出数组的步幅
    out_strides = x.strides + tuple(x.strides[ax] for ax in axis)

    # 调整输入数组的形状,以确保每个轴上窗口的合法性
    x_shape_trimmed = list(x.shape)
    for ax, dim in zip(axis, window_shape):
        if x_shape_trimmed[ax] < dim:
            raise ValueError(
                'window shape cannot be larger than input array shape')
        x_shape_trimmed[ax] -= dim - 1
    out_shape = tuple(x_shape_trimmed) + window_shape

    # 返回按需切片的数组,以形成窗口视图
    return as_strided(x, strides=out_strides, shape=out_shape,
                      subok=subok, writeable=writeable)
# 将形状参数转换为元组,如果形状是可迭代的,则转换为元组,否则创建只包含一个元素的元组
shape = tuple(shape) if np.iterable(shape) else (shape,)

# 使用给定的参数创建一个新的 NumPy 数组,将 array 转换为数组,不复制数据,允许子类化
array = np.array(array, copy=None, subok=subok)

# 如果形状为空且 array 的形状不为空,则抛出值错误异常,说明无法将非标量广播到标量数组
if not shape and array.shape:
    raise ValueError('cannot broadcast a non-scalar to a scalar array')

# 如果形状中有任何负数元素,则抛出值错误异常,说明广播形状的所有元素必须是非负的
if any(size < 0 for size in shape):
    raise ValueError('all elements of broadcast shape must be non-negative')

# 定义额外参数列表为空列表
extras = []

# 使用 np.nditer 迭代器创建一个迭代器对象 it,以便按照形状 shape 广播 array
it = np.nditer(
    (array,), flags=['multi_index', 'refs_ok', 'zerosize_ok'] + extras,
    op_flags=['readonly'], itershape=shape, order='C')

# 进入迭代器上下文
with it:
    # 从迭代器获取广播后的视图,即 itviews 列表的第一个元素
    broadcast = it.itviews[0]

# 调用 _maybe_view_as_subclass 函数,返回 array 或 broadcast 的可能子类视图
result = _maybe_view_as_subclass(array, broadcast)

# 如果 readonly 为 False 且 array 具有 _writeable_no_warn 标志,则设置 result 的写标志和写警告标志
# 这部分代码将来会被移除
if not readonly and array.flags._writeable_no_warn:
    result.flags.writeable = True
    result.flags._warn_on_write = True

# 返回广播后的结果数组 result
return result
    # 从索引 32 开始,每隔 31 个元素取一个位置进行迭代
    for pos in range(32, len(args), 31):
        # 使用广播(broadcasting)来避免分配完整的数组
        # 具讽刺意味的是,np.broadcast 不能正确处理 np.broadcast 对象(它将它们视为标量)
        b = broadcast_to(0, b.shape)
        # 将广播应用于参数数组的子集(从 pos 到 pos+31),包括 b 本身
        b = np.broadcast(b, *args[pos:(pos + 31)])
    # 返回广播后的数组的形状
    return b.shape
# 定义一个空的 NumPy 数据类型作为默认值
_size0_dtype = np.dtype([])


@set_module('numpy')
# 将输入的形状广播成单个形状。
def broadcast_shapes(*args):
    """
    Broadcast the input shapes into a single shape.

    :ref:`Learn more about broadcasting here <basics.broadcasting>`.

    .. versionadded:: 1.20.0

    Parameters
    ----------
    *args : tuples of ints, or ints
        The shapes to be broadcast against each other.

    Returns
    -------
    tuple
        Broadcasted shape.

    Raises
    ------
    ValueError
        If the shapes are not compatible and cannot be broadcast according
        to NumPy's broadcasting rules.

    See Also
    --------
    broadcast
    broadcast_arrays
    broadcast_to

    Examples
    --------
    >>> np.broadcast_shapes((1, 2), (3, 1), (3, 2))
    (3, 2)

    >>> np.broadcast_shapes((6, 7), (5, 6, 1), (7,), (5, 1, 7))
    (5, 6, 7)
    """
    # 创建一个包含指定形状的空数组列表,使用默认的空数据类型 _size0_dtype
    arrays = [np.empty(x, dtype=_size0_dtype) for x in args]
    # 调用内部函数 _broadcast_shape 对数组进行广播操作,并返回结果
    return _broadcast_shape(*arrays)


# 定义 _broadcast_arrays_dispatcher 函数,用于分发 broadcast_arrays 函数的参数
def _broadcast_arrays_dispatcher(*args, subok=None):
    return args


@array_function_dispatch(_broadcast_arrays_dispatcher, module='numpy')
# 广播任意数量的数组。
def broadcast_arrays(*args, subok=False):
    """
    Broadcast any number of arrays against each other.

    Parameters
    ----------
    *args : array_likes
        The arrays to broadcast.

    subok : bool, optional
        If True, then sub-classes will be passed-through, otherwise
        the returned arrays will be forced to be a base-class array (default).

    Returns
    -------
    broadcasted : tuple of arrays
        These arrays are views on the original arrays.  They are typically
        not contiguous.  Furthermore, more than one element of a
        broadcasted array may refer to a single memory location. If you need
        to write to the arrays, make copies first. While you can set the
        ``writable`` flag True, writing to a single output value may end up
        changing more than one location in the output array.

        .. deprecated:: 1.17
            The output is currently marked so that if written to, a deprecation
            warning will be emitted. A future version will set the
            ``writable`` flag False so writing to it will raise an error.

    See Also
    --------
    broadcast
    broadcast_to
    broadcast_shapes

    Examples
    --------
    >>> x = np.array([[1,2,3]])
    >>> y = np.array([[4],[5]])
    >>> np.broadcast_arrays(x, y)
    (array([[1, 2, 3],
            [1, 2, 3]]),
     array([[4, 4, 4],
            [5, 5, 5]]))

    Here is a useful idiom for getting contiguous copies instead of
    non-contiguous views.

    >>> [np.array(a) for a in np.broadcast_arrays(x, y)]
    [array([[1, 2, 3],
            [1, 2, 3]]),
     array([[4, 4, 4],
            [5, 5, 5]])]

    """
    # nditer is not used here to avoid the limit of 32 arrays.
    # Otherwise, something like the following one-liner would suffice:
    # return np.nditer(args, flags=['multi_index', 'zerosize_ok'],
    #                  order='C').itviews
    # 列表推导式,对传入的每个参数进行处理,将其转换为 NumPy 数组
    args = [np.array(_m, copy=None, subok=subok) for _m in args]

    # 计算广播后的数组形状,_broadcast_shape 是一个自定义函数用于计算广播形状
    shape = _broadcast_shape(*args)

    # 列表推导式,对每个数组进行检查和处理:
    # 如果数组形状与广播后的形状相同,则保持不变
    # 否则,使用 _broadcast_to 函数将数组广播到指定形状
    result = [array if array.shape == shape
              else _broadcast_to(array, shape, subok=subok, readonly=False)
                              for array in args]
    # 返回结果元组,其中包含广播后的所有数组
    return tuple(result)

.\numpy\numpy\lib\_stride_tricks_impl.pyi

# 导入必要的模块和类型
from collections.abc import Iterable  # 导入 Iterable 抽象基类
from typing import Any, TypeVar, overload, SupportsIndex  # 导入类型注解相关模块

from numpy import generic  # 导入 numpy 的 generic 类型
from numpy._typing import (  # 导入 numpy 的类型注解
    NDArray,
    ArrayLike,
    _ShapeLike,
    _Shape,
    _ArrayLike
)

_SCT = TypeVar("_SCT", bound=generic)  # 定义一个泛型类型 _SCT,限定为 generic 的子类

__all__: list[str]  # 定义 __all__ 列表,用于模块导入时的限定符

class DummyArray:
    __array_interface__: dict[str, Any]  # 定义一个成员变量 __array_interface__,类型为字典[str, Any]
    base: None | NDArray[Any]  # 定义成员变量 base,可以是 None 或者 NDArray[Any] 类型

    def __init__(
        self,
        interface: dict[str, Any],
        base: None | NDArray[Any] = ...,
    ) -> None:
        ...  # DummyArray 类的初始化方法,接受一个字典和一个可选的 NDArray[Any] 参数

@overload
def as_strided(
    x: _ArrayLike[_SCT],
    shape: None | Iterable[int] = ...,
    strides: None | Iterable[int] = ...,
    subok: bool = ...,
    writeable: bool = ...,
) -> NDArray[_SCT]: ...
@overload
def as_strided(
    x: ArrayLike,
    shape: None | Iterable[int] = ...,
    strides: None | Iterable[int] = ...,
    subok: bool = ...,
    writeable: bool = ...,
) -> NDArray[Any]: ...
# 函数重载定义:as_strided 函数可以接受不同类型的参数,返回相应的 NDArray

@overload
def sliding_window_view(
    x: _ArrayLike[_SCT],
    window_shape: int | Iterable[int],
    axis: None | SupportsIndex = ...,
    *,
    subok: bool = ...,
    writeable: bool = ...,
) -> NDArray[_SCT]: ...
@overload
def sliding_window_view(
    x: ArrayLike,
    window_shape: int | Iterable[int],
    axis: None | SupportsIndex = ...,
    *,
    subok: bool = ...,
    writeable: bool = ...,
) -> NDArray[Any]: ...
# 函数重载定义:sliding_window_view 函数可以接受不同类型的参数,返回相应的 NDArray

@overload
def broadcast_to(
    array: _ArrayLike[_SCT],
    shape: int | Iterable[int],
    subok: bool = ...,
) -> NDArray[_SCT]: ...
@overload
def broadcast_to(
    array: ArrayLike,
    shape: int | Iterable[int],
    subok: bool = ...,
) -> NDArray[Any]: ...
# 函数重载定义:broadcast_to 函数可以接受不同类型的参数,返回相应的 NDArray

def broadcast_shapes(*args: _ShapeLike) -> _Shape:
    ...  # broadcast_shapes 函数接受多个参数 _ShapeLike 类型,返回 _Shape 类型

def broadcast_arrays(
    *args: ArrayLike,
    subok: bool = ...,
) -> tuple[NDArray[Any], ...]:
    ...  # broadcast_arrays 函数接受多个 ArrayLike 类型的参数,返回一个元组,其中包含 NDArray[Any] 类型的数据

.\numpy\numpy\lib\_twodim_base_impl.py

""" Basic functions for manipulating 2d arrays

"""
# 导入 functools 模块,用于创建偏函数
import functools
# 导入 operator 模块,用于操作符函数
import operator

# 导入以下 numpy 内部模块和函数
from numpy._core._multiarray_umath import _array_converter
from numpy._core.numeric import (
    asanyarray, arange, zeros, greater_equal, multiply, ones,
    asarray, where, int8, int16, int32, int64, intp, empty, promote_types,
    diagonal, nonzero, indices
    )
# 导入 numpy 的 overrides 模块和函数
from numpy._core.overrides import set_array_function_like_doc, set_module
from numpy._core import overrides
# 导入 numpy 的 iinfo 模块
from numpy._core import iinfo
# 导入 numpy 的 _stride_tricks_impl 模块中的 broadcast_to 函数
from numpy.lib._stride_tricks_impl import broadcast_to


# 定义公开的函数和类列表
__all__ = [
    'diag', 'diagflat', 'eye', 'fliplr', 'flipud', 'tri', 'triu',
    'tril', 'vander', 'histogram2d', 'mask_indices', 'tril_indices',
    'tril_indices_from', 'triu_indices', 'triu_indices_from', ]


# 创建 functools.partial 对象,用于将 overrides.array_function_dispatch 函数与特定模块名 'numpy' 绑定
array_function_dispatch = functools.partial(
    overrides.array_function_dispatch, module='numpy')


# 获取 int8、int16 和 int32 类型的信息并存储在 i1、i2 和 i4 变量中
i1 = iinfo(int8)
i2 = iinfo(int16)
i4 = iinfo(int32)


def _min_int(low, high):
    """ get small int that fits the range """
    # 根据给定的范围返回适合的最小整数类型
    if high <= i1.max and low >= i1.min:
        return int8
    if high <= i2.max and low >= i2.min:
        return int16
    if high <= i4.max and low >= i4.min:
        return int32
    return int64


# 定义用于 fliplr 函数的分发器
def _flip_dispatcher(m):
    return (m,)


@array_function_dispatch(_flip_dispatcher)
def fliplr(m):
    """
    Reverse the order of elements along axis 1 (left/right).

    For a 2-D array, this flips the entries in each row in the left/right
    direction. Columns are preserved, but appear in a different order than
    before.

    Parameters
    ----------
    m : array_like
        Input array, must be at least 2-D.

    Returns
    -------
    f : ndarray
        A view of `m` with the columns reversed.  Since a view
        is returned, this operation is :math:`\\mathcal O(1)`.

    See Also
    --------
    flipud : Flip array in the up/down direction.
    flip : Flip array in one or more dimensions.
    rot90 : Rotate array counterclockwise.

    Notes
    -----
    Equivalent to ``m[:,::-1]`` or ``np.flip(m, axis=1)``.
    Requires the array to be at least 2-D.

    Examples
    --------
    >>> A = np.diag([1.,2.,3.])
    >>> A
    array([[1.,  0.,  0.],
           [0.,  2.,  0.],
           [0.,  0.,  3.]])
    >>> np.fliplr(A)
    array([[0.,  0.,  1.],
           [0.,  2.,  0.],
           [3.,  0.,  0.]])

    >>> rng = np.random.default_rng()
    >>> A = rng.normal(size=(2,3,5))
    >>> np.all(np.fliplr(A) == A[:,::-1,...])
    True

    """
    # 将输入 m 转换为 ndarray 类型
    m = asanyarray(m)
    # 如果 m 的维度小于 2,则引发 ValueError 异常
    if m.ndim < 2:
        raise ValueError("Input must be >= 2-d.")
    # 返回列反转后的 m 视图
    return m[:, ::-1]


@array_function_dispatch(_flip_dispatcher)
def flipud(m):
    """
    Reverse the order of elements along axis 0 (up/down).

    For a 2-D array, this flips the entries in each column in the up/down
    direction. Rows are preserved, but appear in a different order than before.

    Parameters
    ----------
    m : array_like
        Input array.

    Returns
    -------
    # 将输入的数组 m 转换为 numpy 数组,确保能够进行后续操作
    m = asanyarray(m)
    # 如果输入数组的维度小于 1,则抛出值错误异常
    if m.ndim < 1:
        raise ValueError("Input must be >= 1-d.")
    # 返回翻转行的视图数组,相当于 m[::-1, ...] 的操作
    return m[::-1, ...]
# 用于设置函数的数组功能文档样式
@set_array_function_like_doc
# 用于设置函数的模块为 'numpy'
@set_module('numpy')
# 定义一个名为 eye 的函数,生成一个二维数组,对角线为 1,其他位置为 0
def eye(N, M=None, k=0, dtype=float, order='C', *, device=None, like=None):
    """
    Return a 2-D array with ones on the diagonal and zeros elsewhere.

    Parameters
    ----------
    N : int
      Number of rows in the output.
    M : int, optional
      Number of columns in the output. If None, defaults to `N`.
    k : int, optional
      Index of the diagonal: 0 (the default) refers to the main diagonal,
      a positive value refers to an upper diagonal, and a negative value
      to a lower diagonal.
    dtype : data-type, optional
      Data-type of the returned array.
    order : {'C', 'F'}, optional
        Whether the output should be stored in row-major (C-style) or
        column-major (Fortran-style) order in memory.

        .. versionadded:: 1.14.0
    device : str, optional
        The device on which to place the created array. Default: None.
        For Array-API interoperability only, so must be ``"cpu"`` if passed.

        .. versionadded:: 2.0.0
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    I : ndarray of shape (N,M)
      An array where all elements are equal to zero, except for the `k`-th
      diagonal, whose values are equal to one.

    See Also
    --------
    identity : (almost) equivalent function
    diag : diagonal 2-D array from a 1-D array specified by the user.

    Examples
    --------
    >>> np.eye(2, dtype=int)
    array([[1, 0],
           [0, 1]])
    >>> np.eye(3, k=1)
    array([[0.,  1.,  0.],
           [0.,  0.,  1.],
           [0.,  0.,  0.]])

    """
    # 如果 like 参数不为 None,则调用 _eye_with_like 函数处理
    if like is not None:
        return _eye_with_like(
            like, N, M=M, k=k, dtype=dtype, order=order, device=device
        )
    # 如果 M 为 None,则将 M 设为 N
    if M is None:
        M = N
    # 创建一个形状为 (N, M) 的零数组 m,数据类型为 dtype,存储顺序为 order,设备为 device
    m = zeros((N, M), dtype=dtype, order=order, device=device)
    # 如果 k 大于等于 M,则直接返回 m
    if k >= M:
        return m
    # 确保 M 和 k 是整数,以避免意外的类型转换结果
    M = operator.index(M)
    k = operator.index(k)
    # 如果 k 大于等于 0,则将 i 设为 k;否则将 i 设为 (-k) * M
    if k >= 0:
        i = k
    else:
        i = (-k) * M
    # 在 m 的前 M-k 行中,每隔 M+1 个元素设置为 1,从索引 i 开始
    m[:M-k].flat[i::M+1] = 1
    # 返回生成的二维数组 m
    return m


# 通过数组函数分发装饰器将 _eye_with_like 函数与 eye 函数关联起来
_eye_with_like = array_function_dispatch()(eye)


# 定义一个 _diag_dispatcher 函数,用于 diag 函数的分派
def _diag_dispatcher(v, k=None):
    return (v,)


# 通过数组函数分发装饰器将 _diag_dispatcher 函数与 diag 函数关联起来
@array_function_dispatch(_diag_dispatcher)
# 定义 diag 函数,用于提取对角线或构造对角线数组
def diag(v, k=0):
    """
    Extract a diagonal or construct a diagonal array.

    See the more detailed documentation for ``numpy.diagonal`` if you use this
    function to extract a diagonal and wish to write to the resulting array;
    whether it returns a copy or a view depends on what version of numpy you
    are using.

    Parameters
    ----------
    v : array_like
        If `v` is a 2-D array, return a copy of its `k`-th diagonal.
        If `v` is a 1-D array, return a 2-D array with `v` on the `k`-th
        diagonal.

    """
    v = asanyarray(v)
    s = v.shape
    # 将输入转换为任意数组,确保可以处理不同类型的输入
    if len(s) == 1:
        # 如果输入是一维数组
        n = s[0]+abs(k)
        # 计算输出数组的大小,包括需要的额外对角线长度
        res = zeros((n, n), v.dtype)
        # 创建一个全零数组作为输出,与输入数组类型相同
        if k >= 0:
            i = k
        else:
            i = (-k) * n
        # 计算对角线的起始索引
        res[:n-k].flat[i::n+1] = v
        # 将输入数组的值填充到输出数组的对角线上
        return res
    elif len(s) == 2:
        # 如果输入是二维数组
        return diagonal(v, k)
        # 调用 diagonal 函数返回指定位置的对角线数组
    else:
        # 处理不支持的输入维度
        raise ValueError("Input must be 1- or 2-d.")
        # 抛出值错误,要求输入必须是一维或二维数组
@array_function_dispatch(_diag_dispatcher)
# 使用装饰器将 _diag_dispatcher 函数与 diagflat 函数关联,用于数组函数分发
def diagflat(v, k=0):
    """
    Create a two-dimensional array with the flattened input as a diagonal.

    Parameters
    ----------
    v : array_like
        Input data, which is flattened and set as the `k`-th
        diagonal of the output.
    k : int, optional
        Diagonal to set; 0, the default, corresponds to the "main" diagonal,
        a positive (negative) `k` giving the number of the diagonal above
        (below) the main.

    Returns
    -------
    out : ndarray
        The 2-D output array.

    See Also
    --------
    diag : MATLAB work-alike for 1-D and 2-D arrays.
    diagonal : Return specified diagonals.
    trace : Sum along diagonals.

    Examples
    --------
    >>> np.diagflat([[1,2], [3,4]])
    array([[1, 0, 0, 0],
           [0, 2, 0, 0],
           [0, 0, 3, 0],
           [0, 0, 0, 4]])

    >>> np.diagflat([1,2], 1)
    array([[0, 1, 0],
           [0, 0, 2],
           [0, 0, 0]])

    """
    # 转换输入数据 v 并展平
    conv = _array_converter(v)
    v, = conv.as_arrays(subok=False)
    v = v.ravel()
    s = len(v)
    n = s + abs(k)
    # 创建一个形状为 (n, n) 的零数组,指定数据类型为 v 的数据类型
    res = zeros((n, n), v.dtype)
    if (k >= 0):
        # 对于 k >= 0 的情况,设置正对角线及其上的对角线
        i = arange(0, n-k, dtype=intp)
        fi = i+k+i*n
    else:
        # 对于 k < 0 的情况,设置负对角线及其下的对角线
        i = arange(0, n+k, dtype=intp)
        fi = i+(i-k)*n
    # 将展平的 v 数组数据设置到 res 的指定位置
    res.flat[fi] = v

    return conv.wrap(res)


@set_array_function_like_doc
@set_module('numpy')
# 使用装饰器设置 tri 函数的数组函数行为及所属模块为 numpy
def tri(N, M=None, k=0, dtype=float, *, like=None):
    """
    An array with ones at and below the given diagonal and zeros elsewhere.

    Parameters
    ----------
    N : int
        Number of rows in the array.
    M : int, optional
        Number of columns in the array.
        By default, `M` is taken equal to `N`.
    k : int, optional
        The sub-diagonal at and below which the array is filled.
        `k` = 0 is the main diagonal, while `k` < 0 is below it,
        and `k` > 0 is above.  The default is 0.
    dtype : dtype, optional
        Data type of the returned array.  The default is float.
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    tri : ndarray of shape (N, M)
        Array with its lower triangle filled with ones and zero elsewhere;
        in other words ``T[i,j] == 1`` for ``j <= i + k``, 0 otherwise.

    Examples
    --------
    >>> np.tri(3, 5, 2, dtype=int)
    array([[1, 1, 1, 0, 0],
           [1, 1, 1, 1, 0],
           [1, 1, 1, 1, 1]])

    >>> np.tri(3, 5, -1)
    array([[0.,  0.,  0.,  0.,  0.],
           [1.,  0.,  0.,  0.,  0.],
           [1.,  1.,  0.,  0.,  0.]])

    """
    if like is not None:
        # 如果指定了 like 参数,返回与 like 相同类型的三角矩阵
        return _tri_with_like(like, N, M=M, k=k, dtype=dtype)

    if M is None:
        M = N

    # 创建一个布尔类型的 N x M 形状的矩阵,其中下三角(包括对角线)为 1,其余为 0
    m = greater_equal.outer(arange(N, dtype=_min_int(0, N)),
                            arange(-k, M-k, dtype=_min_int(-k, M - k)))

    # 避免在已经是布尔类型时复制矩阵
    m = m.astype(dtype, copy=False)

    return m


# 将 array_function_dispatch 装饰器应用到 tri 函数
_tri_with_like = array_function_dispatch()(tri)
# 根据输入参数生成一个 Vandermonde 矩阵
def vander(x, N=None, increasing=False):
    # 如果 N 为 None,则设置 N 为 x 的长度
    if N is None:
        N = len(x)
    # 根据 increasing 参数决定是否递增排序
    if increasing:
        # 生成递增排序的 Vandermonde 矩阵
        return array([x**(N-1-i) for i in range(N)]).T
    else:
        # 生成递减排序的 Vandermonde 矩阵
        return array([x**i for i in range(N)]).T
    """
    The columns of the output matrix are powers of the input vector. The
    order of the powers is determined by the `increasing` boolean argument.
    Specifically, when `increasing` is False, the `i`-th output column is
    the input vector raised element-wise to the power of ``N - i - 1``. Such
    a matrix with a geometric progression in each row is named for Alexandre-
    Theophile Vandermonde.
    
    Parameters
    ----------
    x : array_like
        1-D input array.
    N : int, optional
        Number of columns in the output.  If `N` is not specified, a square
        array is returned (``N = len(x)``).
    increasing : bool, optional
        Order of the powers of the columns.  If True, the powers increase
        from left to right, if False (the default) they are reversed.
    
        .. versionadded:: 1.9.0
    
    Returns
    -------
    out : ndarray
        Vandermonde matrix.  If `increasing` is False, the first column is
        ``x^(N-1)``, the second ``x^(N-2)`` and so forth. If `increasing` is
        True, the columns are ``x^0, x^1, ..., x^(N-1)``.
    
    See Also
    --------
    polynomial.polynomial.polyvander
    
    Examples
    --------
    >>> x = np.array([1, 2, 3, 5])
    >>> N = 3
    >>> np.vander(x, N)
    array([[ 1,  1,  1],
           [ 4,  2,  1],
           [ 9,  3,  1],
           [25,  5,  1]])
    
    >>> np.column_stack([x**(N-1-i) for i in range(N)])
    array([[ 1,  1,  1],
           [ 4,  2,  1],
           [ 9,  3,  1],
           [25,  5,  1]])
    
    >>> x = np.array([1, 2, 3, 5])
    >>> np.vander(x)
    array([[  1,   1,   1,   1],
           [  8,   4,   2,   1],
           [ 27,   9,   3,   1],
           [125,  25,   5,   1]])
    >>> np.vander(x, increasing=True)
    array([[  1,   1,   1,   1],
           [  1,   2,   4,   8],
           [  1,   3,   9,  27],
           [  1,   5,  25, 125]])
    
    The determinant of a square Vandermonde matrix is the product
    of the differences between the values of the input vector:
    
    >>> np.linalg.det(np.vander(x))
    48.000000000000043 # may vary
    >>> (5-3)*(5-2)*(5-1)*(3-2)*(3-1)*(2-1)
    48
    """
    
    # 将输入数组 x 转换为 ndarray 类型
    x = asarray(x)
    
    # 如果 x 不是一维数组,则抛出异常
    if x.ndim != 1:
        raise ValueError("x must be a one-dimensional array or sequence.")
    
    # 如果未指定 N,则将 N 设置为 x 的长度
    if N is None:
        N = len(x)
    
    # 创建一个空的数组 v,形状为 (len(x), N),数据类型为 x 的数据类型和整数类型的广播类型
    v = empty((len(x), N), dtype=promote_types(x.dtype, int))
    
    # 根据 increasing 参数选择操作数组 tmp
    tmp = v[:, ::-1] if not increasing else v
    
    # 如果 N > 0,则将 tmp 的第一列设置为 1
    if N > 0:
        tmp[:, 0] = 1
    
    # 如果 N > 1,则将 tmp 的第二列到最后一列设置为 x 的列向量的累积乘积
    if N > 1:
        tmp[:, 1:] = x[:, None]
        multiply.accumulate(tmp[:, 1:], out=tmp[:, 1:], axis=1)
    
    # 返回生成的 Vandermonde 矩阵 v
    return v
def _histogram2d_dispatcher(x, y, bins=None, range=None, density=None,
                            weights=None):
    # 生成器函数,用于分派参数 x, y, bins, range, density, weights
    yield x  # 生成器返回 x
    yield y  # 生成器返回 y

    # 以下逻辑从 histogram2d 中的检查逻辑进行了糟糕的适应
    try:
        N = len(bins)  # 尝试获取 bins 的长度
    except TypeError:
        N = 1  # 如果无法获取长度,则默认 N 为 1
    if N == 2:
        yield from bins  # 如果 N 等于 2,则返回 bins 中的元素 [x, y]
    else:
        yield bins  # 否则返回 bins

    yield weights  # 返回 weights


@array_function_dispatch(_histogram2d_dispatcher)
def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
    """
    Compute the bi-dimensional histogram of two data samples.

    Parameters
    ----------
    x : array_like, shape (N,)
        An array containing the x coordinates of the points to be
        histogrammed.
    y : array_like, shape (N,)
        An array containing the y coordinates of the points to be
        histogrammed.
    bins : int or array_like or [int, int] or [array, array], optional
        The bin specification:

        * If int, the number of bins for the two dimensions (nx=ny=bins).
        * If array_like, the bin edges for the two dimensions
          (x_edges=y_edges=bins).
        * If [int, int], the number of bins in each dimension
          (nx, ny = bins).
        * If [array, array], the bin edges in each dimension
          (x_edges, y_edges = bins).
        * A combination [int, array] or [array, int], where int
          is the number of bins and array is the bin edges.

    range : array_like, shape(2,2), optional
        The leftmost and rightmost edges of the bins along each dimension
        (if not specified explicitly in the `bins` parameters):
        ``[[xmin, xmax], [ymin, ymax]]``. All values outside of this range
        will be considered outliers and not tallied in the histogram.
    density : bool, optional
        If False, the default, returns the number of samples in each bin.
        If True, returns the probability *density* function at the bin,
        ``bin_count / sample_count / bin_area``.
    weights : array_like, shape(N,), optional
        An array of values ``w_i`` weighing each sample ``(x_i, y_i)``.
        Weights are normalized to 1 if `density` is True. If `density` is
        False, the values of the returned histogram are equal to the sum of
        the weights belonging to the samples falling into each bin.

    Returns
    -------
    H : ndarray, shape(nx, ny)
        The bi-dimensional histogram of samples `x` and `y`. Values in `x`
        are histogrammed along the first dimension and values in `y` are
        histogrammed along the second dimension.
    xedges : ndarray, shape(nx+1,)
        The bin edges along the first dimension.
    yedges : ndarray, shape(ny+1,)
        The bin edges along the second dimension.

    See Also
    --------
    histogram : 1D histogram
    histogramdd : Multidimensional histogram

    Notes
    -----
    When `density` is True, then the returned histogram is the sample
    density, defined such that the sum over bins of the product
    """
    pass  # 空函数体,因为函数文档字符串已经提供了函数功能的说明
    # `bin_value * bin_area` is 1.
    # 上述表达式中 `bin_value * bin_area` 的结果为1。

    # Please note that the histogram does not follow the Cartesian convention
    # where `x` values are on the abscissa and `y` values on the ordinate
    # axis.  Rather, `x` is histogrammed along the first dimension of the
    # array (vertical), and `y` along the second dimension of the array
    # (horizontal).  This ensures compatibility with `histogramdd`.
    # 请注意,直方图不遵循笛卡尔坐标系的传统规定,其中 `x` 值位于横坐标轴上,
    # `y` 值位于纵坐标轴上。相反,`x` 被直方图化沿着数组的第一个维度(垂直方向),
    # `y` 被直方图化沿着数组的第二个维度(水平方向)。这样做确保与 `histogramdd` 兼容。

    # Examples
    # --------
    # 例子

    # Import necessary modules
    # 导入必要的模块
    >>> from matplotlib.image import NonUniformImage
    >>> import matplotlib.pyplot as plt

    # Construct a 2-D histogram with variable bin width. First define the bin
    # edges:
    # 构建一个具有可变箱宽的二维直方图。首先定义箱子的边缘:

    >>> xedges = [0, 1, 3, 5]
    >>> yedges = [0, 2, 3, 4, 6]

    # Next we create a histogram H with random bin content:
    # 接下来,我们用随机箱内容创建直方图 H:

    >>> x = np.random.normal(2, 1, 100)
    >>> y = np.random.normal(1, 1, 100)
    >>> H, xedges, yedges = np.histogram2d(x, y, bins=(xedges, yedges))

    # Histogram does not follow Cartesian convention (see Notes),
    # therefore transpose H for visualization purposes.
    # 直方图不遵循笛卡尔坐标系的传统规定(见注释),因此为了可视化目的转置 H。
    >>> H = H.T

    # :func:`imshow <matplotlib.pyplot.imshow>` can only display square bins:
    # :func:`imshow <matplotlib.pyplot.imshow>` 只能显示正方形的箱子:

    >>> fig = plt.figure(figsize=(7, 3))
    >>> ax = fig.add_subplot(131, title='imshow: square bins')
    >>> plt.imshow(H, interpolation='nearest', origin='lower',
    ...         extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])

    # :func:`pcolormesh <matplotlib.pyplot.pcolormesh>` can display actual edges:
    # :func:`pcolormesh <matplotlib.pyplot.pcolormesh>` 可以显示实际的边缘:

    >>> ax = fig.add_subplot(132, title='pcolormesh: actual edges',
    ...         aspect='equal')
    >>> X, Y = np.meshgrid(xedges, yedges)
    >>> ax.pcolormesh(X, Y, H)

    # :class:`NonUniformImage <matplotlib.image.NonUniformImage>` can be used to
    # display actual bin edges with interpolation:
    # :class:`NonUniformImage <matplotlib.image.NonUniformImage>` 可以用来显示带插值的实际箱边缘:

    >>> ax = fig.add_subplot(133, title='NonUniformImage: interpolated',
    ...         aspect='equal', xlim=xedges[[0, -1]], ylim=yedges[[0, -1]])
    >>> im = NonUniformImage(ax, interpolation='bilinear')
    >>> xcenters = (xedges[:-1] + xedges[1:]) / 2
    >>> ycenters = (yedges[:-1] + yedges[1:]) / 2
    >>> im.set_data(xcenters, ycenters, H)
    >>> ax.add_image(im)

    # Show the plot
    # 显示图形
    >>> plt.show()

    # It is also possible to construct a 2-D histogram without specifying bin
    # edges:
    # 也可以构建一个没有指定箱边界的二维直方图:

    >>> # Generate non-symmetric test data
    >>> n = 10000
    >>> x = np.linspace(1, 100, n)
    >>> y = 2*np.log(x) + np.random.rand(n) - 0.5
    >>> # Compute 2d histogram. Note the order of x/y and xedges/yedges
    >>> H, yedges, xedges = np.histogram2d(y, x, bins=20)

    # Now we can plot the histogram using
    # :func:`pcolormesh <matplotlib.pyplot.pcolormesh>`, and a
    # :func:`hexbin <matplotlib.pyplot.hexbin>` for comparison.
    # 现在我们可以使用 :func:`pcolormesh <matplotlib.pyplot.pcolormesh>` 绘制直方图,
    # 并使用 :func:`hexbin <matplotlib.pyplot.hexbin>` 进行比较。

    >>> # Plot histogram using pcolormesh
    >>> fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)
    >>> ax1.pcolormesh(xedges, yedges, H, cmap='rainbow')
    >>> ax1.plot(x, 2*np.log(x), 'k-')
    >>> ax1.set_xlim(x.min(), x.max())
    >>> ax1.set_ylim(y.min(), y.max())
    >>> ax1.set_xlabel('x')
    >>> ax1.set_ylabel('y')
    >>> ax1.set_title('histogram2d')
    >>> ax1.grid()

    >>> # 在 ax1 上创建二维直方图
    >>> # 设置 y 轴的范围为 y 的最小值到最大值
    >>> ax1.set_ylim(y.min(), y.max())
    >>> # 设置 x 轴标签为 'x'
    >>> ax1.set_xlabel('x')
    >>> # 设置 y 轴标签为 'y'
    >>> ax1.set_ylabel('y')
    >>> # 设置图表标题为 'histogram2d'
    >>> ax1.set_title('histogram2d')
    >>> # 在 ax1 上显示网格线
    >>> ax1.grid()

    >>> # 在 ax2 上创建 hexbin 图进行比较
    >>> ax2.hexbin(x, y, gridsize=20, cmap='rainbow')
    >>> # 绘制直线图,x 为自变量,2*np.log(x) 为因变量,线条为黑色实线
    >>> ax2.plot(x, 2*np.log(x), 'k-')
    >>> # 设置 ax2 的标题为 'hexbin'
    >>> ax2.set_title('hexbin')
    >>> # 设置 x 轴的范围为 x 的最小值到最大值
    >>> ax2.set_xlim(x.min(), x.max())
    >>> # 设置 x 轴标签为 'x'
    >>> ax2.set_xlabel('x')
    >>> # 在 ax2 上显示网格线
    >>> ax2.grid()

    >>> # 显示整个图形
    >>> plt.show()
    """
    from numpy import histogramdd

    # 检查 x 和 y 的长度是否相等,如果不相等则抛出 ValueError 异常
    if len(x) != len(y):
        raise ValueError('x and y must have the same length.')

    # 尝试获取 bins 的长度 N,如果 bins 不是一个数组则 N 为 1
    try:
        N = len(bins)
    except TypeError:
        N = 1

    # 如果 N 不是 1 也不是 2,则将 bins 转换为数组,并分别设置 xedges 和 yedges
    if N != 1 and N != 2:
        xedges = yedges = asarray(bins)
        bins = [xedges, yedges]
    
    # 计算二维直方图 hist 和对应的边界 edges
    hist, edges = histogramdd([x, y], bins, range, density, weights)
    # 返回直方图 hist,以及 x 和 y 的边界 edges[0] 和 edges[1]
    return hist, edges[0], edges[1]
# 设置模块为 'numpy',这是一个装饰器,用于指定模块名称
@set_module('numpy')
# 定义函数 mask_indices,返回用于访问 (n, n) 数组的索引,基于给定的遮罩函数
def mask_indices(n, mask_func, k=0):
    """
    Return the indices to access (n, n) arrays, given a masking function.

    Assume `mask_func` is a function that, for a square array a of size
    ``(n, n)`` with a possible offset argument `k`, when called as
    ``mask_func(a, k)`` returns a new array with zeros in certain locations
    (functions like `triu` or `tril` do precisely this). Then this function
    returns the indices where the non-zero values would be located.

    Parameters
    ----------
    n : int
        The returned indices will be valid to access arrays of shape (n, n).
    mask_func : callable
        A function whose call signature is similar to that of `triu`, `tril`.
        That is, ``mask_func(x, k)`` returns a boolean array, shaped like `x`.
        `k` is an optional argument to the function.
    k : scalar
        An optional argument which is passed through to `mask_func`. Functions
        like `triu`, `tril` take a second argument that is interpreted as an
        offset.

    Returns
    -------
    indices : tuple of arrays.
        The `n` arrays of indices corresponding to the locations where
        ``mask_func(np.ones((n, n)), k)`` is True.

    See Also
    --------
    triu, tril, triu_indices, tril_indices

    Notes
    -----
    .. versionadded:: 1.4.0

    Examples
    --------
    These are the indices that would allow you to access the upper triangular
    part of any 3x3 array:

    >>> iu = np.mask_indices(3, np.triu)

    For example, if `a` is a 3x3 array:

    >>> a = np.arange(9).reshape(3, 3)
    >>> a
    array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])
    >>> a[iu]
    array([0, 1, 2, 4, 5, 8])

    An offset can be passed also to the masking function.  This gets us the
    indices starting on the first diagonal right of the main one:

    >>> iu1 = np.mask_indices(3, np.triu, 1)

    with which we now extract only three elements:

    >>> a[iu1]
    array([1, 2, 5])

    """
    # 创建一个大小为 (n, n) 的整数数组 m,所有元素为 1
    m = ones((n, n), int)
    # 调用 mask_func 函数,传入 m 和 k,返回一个布尔数组 a
    a = mask_func(m, k)
    # 返回 a 中非零元素的索引
    return nonzero(a != 0)


# 设置模块为 'numpy',这是一个装饰器,用于指定模块名称
@set_module('numpy')
# 定义函数 tril_indices,返回一个 (n, m) 数组的下三角形部分的索引
def tril_indices(n, k=0, m=None):
    """
    Return the indices for the lower-triangle of an (n, m) array.

    Parameters
    ----------
    n : int
        The row dimension of the arrays for which the returned
        indices will be valid.
    k : int, optional
        Diagonal offset (see `tril` for details).
    m : int, optional
        .. versionadded:: 1.9.0

        The column dimension of the arrays for which the returned
        arrays will be valid.
        By default `m` is taken equal to `n`.

    Returns
    -------
    inds : tuple of arrays
        The indices for the triangle. The returned tuple contains two arrays,
        each with the indices along one dimension of the array.

    See also
    --------
    triu_indices : similar function, for upper-triangular.
    mask_indices : generic function accepting an arbitrary mask function.
    tril, triu

    Notes

    """
    # 根据文档,该函数是在 NumPy 1.4.0 版本中添加的新功能
    .. versionadded:: 1.4.0
    
    # 示例部分,展示如何计算两种不同的索引集合,用于访问4x4数组:
    # 一种是从主对角线开始的下三角部分,另一种是从右侧两个对角线开始。
    
    # 使用 np.tril_indices 函数计算出4x4数组的下三角部分的索引集合
    il1 = np.tril_indices(4)
    
    # 使用 np.tril_indices 函数计算出4x4数组中右侧两个对角线开始的索引集合
    il2 = np.tril_indices(4, 2)
    
    # 下面展示了如何将这些索引集合应用到示例数组 a 上:
    
    # 示例数组 a,形状为4x4
    a = np.arange(16).reshape(4, 4)
    >>> a
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15]])
    
    # 使用 il1 索引集合进行索引:
    >>> a[il1]
    array([ 0,  4,  5,  8,  9, 10, 12, 13, 14, 15])
    
    # 使用 il1 索引集合进行赋值:
    >>> a[il1] = -1
    >>> a
    array([[-1,  1,  2,  3],
           [-1, -1,  6,  7],
           [-1, -1, -1, 11],
           [-1, -1, -1, -1]])
    
    # 使用 il2 索引集合进行赋值,涵盖几乎整个数组(从主对角线右侧两个对角线开始):
    >>> a[il2] = -10
    >>> a
    array([[-10, -10, -10,   3],
           [-10, -10, -10, -10],
           [-10, -10, -10, -10],
           [-10, -10, -10, -10]])
    
    """
    tri_ = tri(n, m, k=k, dtype=bool)
    
    # 返回一个元组,其中每个元素是根据布尔数组 tri_ 的形状广播后的 inds 的值
    return tuple(broadcast_to(inds, tri_.shape)[tri_]
                 for inds in indices(tri_.shape, sparse=True))
# 定义一个函数分派器,返回输入参数的元组
def _trilu_indices_form_dispatcher(arr, k=None):
    return (arr,)


# 使用装饰器将下面的函数注册到数组函数分派机制中
@array_function_dispatch(_trilu_indices_form_dispatcher)
# 定义函数 tril_indices_from,返回给定数组的下三角部分的索引
def tril_indices_from(arr, k=0):
    """
    返回数组的下三角部分的索引。

    查看 `tril_indices` 获取详细信息。

    Parameters
    ----------
    arr : array_like
        索引适用于维度与 arr 相同的方形数组。
    k : int, optional
        对角线偏移量(详见 `tril` 的说明)。

    Examples
    --------

    创建一个 4x4 的数组。

    >>> a = np.arange(16).reshape(4, 4)
    >>> a
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15]])

    将数组传递给函数以获取下三角元素的索引。

    >>> trili = np.tril_indices_from(a)
    >>> trili
    (array([0, 1, 1, 2, 2, 2, 3, 3, 3, 3]), array([0, 0, 1, 0, 1, 2, 0, 1, 2, 3]))

    >>> a[trili]
    array([ 0,  4,  5,  8,  9, 10, 12, 13, 14, 15])

    这是 `tril_indices()` 的语法糖。

    >>> np.tril_indices(a.shape[0])
    (array([0, 1, 1, 2, 2, 2, 3, 3, 3, 3]), array([0, 0, 1, 0, 1, 2, 0, 1, 2, 3]))

    使用 `k` 参数来返回到第 k 条对角线的下三角数组的索引。

    >>> trili1 = np.tril_indices_from(a, k=1)
    >>> a[trili1]
    array([ 0,  1,  4,  5,  6,  8,  9, 10, 11, 12, 13, 14, 15])

    See Also
    --------
    tril_indices, tril, triu_indices_from

    Notes
    -----
    .. versionadded:: 1.4.0

    """
    # 如果输入数组不是二维的,抛出 ValueError 异常
    if arr.ndim != 2:
        raise ValueError("input array must be 2-d")
    # 返回调用 tril_indices 函数得到的结果,指定数组的行数和列数以及对角线偏移量
    return tril_indices(arr.shape[-2], k=k, m=arr.shape[-1])


# 将下面的函数设置为 numpy 模块的一部分
@set_module('numpy')
# 定义 triu_indices 函数,返回一个 (n, m) 数组的上三角部分的索引
def triu_indices(n, k=0, m=None):
    """
    返回一个 (n, m) 数组的上三角部分的索引。

    Parameters
    ----------
    n : int
        返回的索引适用于数组的大小。
    k : int, optional
        对角线偏移量(详见 `triu` 的说明)。
    m : int, optional
        .. versionadded:: 1.9.0

        返回的数组的列维度。
        默认情况下,`m` 等于 `n`。

    Returns
    -------
    inds : tuple, shape(2) of ndarrays, shape(`n`)
        三角形的索引。返回的元组包含两个数组,每个数组沿数组的一个维度包含索引。可用于切片形状为 (`n`, `n`) 的 ndarray。

    See also
    --------
    tril_indices : 类似的函数,用于下三角。
    mask_indices : 接受任意掩码函数的通用函数。
    triu, tril

    Notes
    -----
    .. versionadded:: 1.4.0

    Examples
    --------
    计算两组不同的索引以访问 4x4 数组,一组从主对角线开始为上三角部分,另一组从右边开始两个对角线更远的地方:

    >>> iu1 = np.triu_indices(4)
    >>> iu2 = np.triu_indices(4, 2)

    """
    # 此处省略函数主体,因为它只包含了文档字符串和一些函数签名,没有实际的代码实现
    # 创建一个布尔类型的三角形掩码,表示矩阵中不同的三角形区域
    tri_ = ~tri(n, m, k=k - 1, dtype=bool)

    # 返回一个元组,包含通过广播和掩码选择的索引的稀疏矩阵中的元素
    return tuple(broadcast_to(inds, tri_.shape)[tri_]
                 for inds in indices(tri_.shape, sparse=True))
# 使用装饰器来分派函数,根据数组的形式调度
@array_function_dispatch(_trilu_indices_form_dispatcher)
# 定义一个函数,返回给定数组的上三角部分的索引
def triu_indices_from(arr, k=0):
    """
    Return the indices for the upper-triangle of arr.

    See `triu_indices` for full details.

    Parameters
    ----------
    arr : ndarray, shape(N, N)
        The indices will be valid for square arrays.
        输入数组,应为方形数组,返回的索引对其有效。
    k : int, optional
        Diagonal offset (see `triu` for details).
        对角线的偏移量(参见 `triu` 以了解详情)。

    Returns
    -------
    triu_indices_from : tuple, shape(2) of ndarray, shape(N)
        Indices for the upper-triangle of `arr`.
        返回数组 `arr` 上三角部分的索引。

    Examples
    --------

    Create a 4 by 4 array.

    >>> a = np.arange(16).reshape(4, 4)
    >>> a
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15]])

    Pass the array to get the indices of the upper triangular elements.

    >>> triui = np.triu_indices_from(a)
    >>> triui
    (array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3]), array([0, 1, 2, 3, 1, 2, 3, 2, 3, 3]))

    >>> a[triui]
    array([ 0,  1,  2,  3,  5,  6,  7, 10, 11, 15])

    This is syntactic sugar for triu_indices().

    >>> np.triu_indices(a.shape[0])
    (array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3]), array([0, 1, 2, 3, 1, 2, 3, 2, 3, 3]))

    Use the `k` parameter to return the indices for the upper triangular array
    from the k-th diagonal.

    >>> triuim1 = np.triu_indices_from(a, k=1)
    >>> a[triuim1]
    array([ 1,  2,  3,  6,  7, 11])


    See Also
    --------
    triu_indices, triu, tril_indices_from

    Notes
    -----
    .. versionadded:: 1.4.0

    """
    # 如果输入数组的维度不是2,抛出值错误
    if arr.ndim != 2:
        raise ValueError("input array must be 2-d")
    # 返回调用 triu_indices 函数得到的结果,传递给它数组的形状及 k 参数
    return triu_indices(arr.shape[-2], k=k, m=arr.shape[-1])

.\numpy\numpy\lib\_twodim_base_impl.pyi

# 导入内建模块和函数
import builtins
# 导入抽象基类中的可调用对象和序列
from collections.abc import Callable, Sequence
# 导入类型提示
from typing import (
    Any,
    overload,
    TypeVar,
    Literal as L,
)

# 导入 NumPy 库,并导入一系列特定的数据类型和函数
import numpy as np
from numpy import (
    generic,
    number,
    timedelta64,
    datetime64,
    int_,
    intp,
    float64,
    signedinteger,
    floating,
    complexfloating,
    object_,
    _OrderCF,
)

# 导入 NumPy 内部的类型定义
from numpy._typing import (
    DTypeLike,
    _DTypeLike,
    ArrayLike,
    _ArrayLike,
    NDArray,
    _SupportsArrayFunc,
    _ArrayLikeInt_co,
    _ArrayLikeFloat_co,
    _ArrayLikeComplex_co,
    _ArrayLikeObject_co,
)

# 定义类型变量 _T 和 _SCT
_T = TypeVar("_T")
_SCT = TypeVar("_SCT", bound=generic)

# 定义回调函数类型 _MaskFunc,接受一个整数类型的 NumPy 数组和一个泛型参数,返回一个与 np.equal 兼容的数据类型数组
_MaskFunc = Callable[
    [NDArray[int_], _T],
    NDArray[number[Any] | np.bool | timedelta64 | datetime64 | object_],
]

# 定义模块的导出列表
__all__: list[str]

# 函数装饰器 @overload,用于指定函数的重载形式

# 函数 fliplr 的第一个重载形式,接受 _ArrayLike 类型参数 m,返回 _SCT 类型的 NumPy 数组
@overload
def fliplr(m: _ArrayLike[_SCT]) -> NDArray[_SCT]: ...

# 函数 fliplr 的第二个重载形式,接受 ArrayLike 类型参数 m,返回任意类型的 NumPy 数组
@overload
def fliplr(m: ArrayLike) -> NDArray[Any]: ...

# 函数 flipud 的第一个重载形式,接受 _ArrayLike 类型参数 m,返回 _SCT 类型的 NumPy 数组
@overload
def flipud(m: _ArrayLike[_SCT]) -> NDArray[_SCT]: ...

# 函数 flipud 的第二个重载形式,接受 ArrayLike 类型参数 m,返回任意类型的 NumPy 数组
@overload
def flipud(m: ArrayLike) -> NDArray[Any]: ...

# 函数 eye 的第一个重载形式,返回 float64 类型的 NumPy 数组
@overload
def eye(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: None = ...,
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: None | _SupportsArrayFunc = ...,
) -> NDArray[float64]: ...

# 函数 eye 的第二个重载形式,返回 _SCT 类型的 NumPy 数组
@overload
def eye(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: _DTypeLike[_SCT] = ...,
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: None | _SupportsArrayFunc = ...,
) -> NDArray[_SCT]: ...

# 函数 eye 的第三个重载形式,返回任意类型的 NumPy 数组
@overload
def eye(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: DTypeLike = ...,
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: None | _SupportsArrayFunc = ...,
) -> NDArray[Any]: ...

# 函数 diag 的第一个重载形式,接受 _ArrayLike 类型参数 v,返回 _SCT 类型的 NumPy 数组
@overload
def diag(v: _ArrayLike[_SCT], k: int = ...) -> NDArray[_SCT]: ...

# 函数 diag 的第二个重载形式,接受 ArrayLike 类型参数 v,返回任意类型的 NumPy 数组
@overload
def diag(v: ArrayLike, k: int = ...) -> NDArray[Any]: ...

# 函数 diagflat 的第一个重载形式,接受 _ArrayLike 类型参数 v,返回 _SCT 类型的 NumPy 数组
@overload
def diagflat(v: _ArrayLike[_SCT], k: int = ...) -> NDArray[_SCT]: ...

# 函数 diagflat 的第二个重载形式,接受 ArrayLike 类型参数 v,返回任意类型的 NumPy 数组
@overload
def diagflat(v: ArrayLike, k: int = ...) -> NDArray[Any]: ...

# 函数 tri 的第一个重载形式,返回 float64 类型的 NumPy 数组
@overload
def tri(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: None = ...,
    *,
    like: None | _SupportsArrayFunc = ...
) -> NDArray[float64]: ...

# 函数 tri 的第二个重载形式,返回 _SCT 类型的 NumPy 数组
@overload
def tri(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: _DTypeLike[_SCT] = ...,
    *,
    like: None | _SupportsArrayFunc = ...
) -> NDArray[_SCT]: ...

# 函数 tri 的第三个重载形式,返回任意类型的 NumPy 数组
@overload
def tri(
    N: int,
    M: None | int = ...,
    k: int = ...,
    dtype: DTypeLike = ...,
    *,
    like: None | _SupportsArrayFunc = ...
) -> NDArray[Any]: ...

# 函数 tril 的第一个重载形式,接受 _ArrayLike 类型参数 v,返回 _SCT 类型的 NumPy 数组
@overload
def tril(v: _ArrayLike[_SCT], k: int = ...) -> NDArray[_SCT]: ...

# 函数 tril 的第二个重载形式,接受 ArrayLike 类型参数 v,返回任意类型的 NumPy 数组
@overload
def tril(v: ArrayLike, k: int = ...) -> NDArray[Any]: ...

# 函数 triu 的第一个重载形式,接受 _ArrayLike 类型参数 v,返回 _SCT 类型的 NumPy 数组
@overload
def triu(v: _ArrayLike[_SCT], k: int = ...) -> NDArray[_SCT]: ...

# 函数 triu 的第二个重载形式,接受 ArrayLike 类型参数 v,返回任意类型的 NumPy 数组
@overload
def triu(v: ArrayLike, k: int = ...) -> NDArray[Any]: ...

# 函数 vander 的声明,类型检查被忽略(type: ignore[misc]),接受 _ArrayLikeInt_co 类型参数 x
# 返回类型未指定,应根据具体实现确定
def vander(
    x: _ArrayLikeInt_co,
    N: None | int = ...,
    increasing: bool = ...,



# 定义两个变量 N 和 increasing,分别类型为可空的整数或 None,和布尔值
N: None | int = ...,
increasing: bool = ...,


这段代码定义了两个变量 `N` 和 `increasing`。在类型注释中,`N` 的类型是可空的整数或者 `None`,而 `increasing` 是布尔类型。这些变量的具体值在这里用 `...` 表示,实际应用中应该有具体的赋值。
@overload
def vander(
    x: _ArrayLikeFloat_co,
    N: None | int = ...,
    increasing: bool = ...,
) -> NDArray[floating[Any]]: ...
@overload
def vander(
    x: _ArrayLikeComplex_co,
    N: None | int = ...,
    increasing: bool = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def vander(
    x: _ArrayLikeObject_co,
    N: None | int = ...,
    increasing: bool = ...,
) -> NDArray[object_]: ...


# 生成范德蒙矩阵(Vandermonde matrix)。
# 根据不同的输入类型和参数生成不同的 V 阵(Vandermonde matrix)。
# - x: 输入数组或类数组(_ArrayLike),可以是浮点数、复数或对象类型。
# - N: V 阵的列数,如果为 None 则取 x 的长度。
# - increasing: 控制 V 阵的列的递增或递减排列。
# 返回生成的 V 阵作为浮点数、复数或对象数组。

@overload
def histogram2d(
    x: _ArrayLikeFloat_co,
    y: _ArrayLikeFloat_co,
    bins: int | Sequence[int] = ...,
    range: None | _ArrayLikeFloat_co = ...,
    density: None | bool = ...,
    weights: None | _ArrayLikeFloat_co = ...,
) -> tuple[
    NDArray[float64],
    NDArray[floating[Any]],
    NDArray[floating[Any]],
]: ...
@overload
def histogram2d(
    x: _ArrayLikeComplex_co,
    y: _ArrayLikeComplex_co,
    bins: int | Sequence[int] = ...,
    range: None | _ArrayLikeFloat_co = ...,
    density: None | bool = ...,
    weights: None | _ArrayLikeFloat_co = ...,
) -> tuple[
    NDArray[float64],
    NDArray[complexfloating[Any, Any]],
    NDArray[complexfloating[Any, Any]],
]: ...
@overload  # TODO: Sort out `bins`
def histogram2d(
    x: _ArrayLikeComplex_co,
    y: _ArrayLikeComplex_co,
    bins: Sequence[_ArrayLikeInt_co],
    range: None | _ArrayLikeFloat_co = ...,
    density: None | bool = ...,
    weights: None | _ArrayLikeFloat_co = ...,
) -> tuple[
    NDArray[float64],
    NDArray[Any],
    NDArray[Any],
]: ...


# 生成二维直方图。
# 根据输入的数组 x 和 y,以及可选的 bins、range、density 和 weights 参数生成二维直方图。
# - x: 输入数组或类数组,可以是浮点数或复数。
# - y: 输入数组或类数组,可以是浮点数或复数,与 x 的形状必须一致。
# - bins: 定义直方图箱子的数量或边界。
# - range: 定义 x 和 y 的范围。
# - density: 如果为 True,则返回的直方图是归一化的概率密度。
# - weights: 可选的权重数组,用于每个点的加权统计。
# 返回一个包含三个数组的元组,分别是直方图统计值、x 方向上的直方图箱子边界、y 方向上的直方图箱子边界。

@overload
def mask_indices(
    n: int,
    mask_func: _MaskFunc[int],
    k: int = ...,
) -> tuple[NDArray[intp], NDArray[intp]]: ...
@overload
def mask_indices(
    n: int,
    mask_func: _MaskFunc[_T],
    k: _T,
) -> tuple[NDArray[intp], NDArray[intp]]: ...


# 根据掩码函数生成索引数组的元组。
# 根据给定的参数生成用于掩码的索引数组。
# - n: 生成的索引数组的维度。
# - mask_func: 一个函数,根据索引位置返回一个布尔值数组。
# - k: 控制生成的索引与对角线的关系。
# 返回一个元组,包含两个整数数组,分别是行索引和列索引。

def tril_indices(
    n: int,
    k: int = ...,
    m: None | int = ...,
) -> tuple[NDArray[int_], NDArray[int_]]: ...


# 返回一个下三角矩阵的索引元组。
# 返回一个下三角矩阵的所有行列索引。
# - n: 矩阵的行数和列数。
# - k: 控制生成的索引与主对角线的关系。
# - m: 可选参数,控制生成的索引的上限。

def tril_indices_from(
    arr: NDArray[Any],
    k: int = ...,
) -> tuple[NDArray[int_], NDArray[int_]]: ...


# 返回给定数组的下三角矩阵的索引元组。
# 返回给定数组的下三角矩阵的所有行列索引。
# - arr: 输入的数组,返回其下三角矩阵的索引。
# - k: 控制生成的索引与主对角线的关系。

def triu_indices(
    n: int,
    k: int = ...,
    m: None | int = ...,
) -> tuple[NDArray[int_], NDArray[int_]]: ...


# 返回一个上三角矩阵的索引元组。
# 返回一个上三角矩阵的所有行列索引。
# - n: 矩阵的行数和列数。
# - k: 控制生成的索引与主对角线的关系。
# - m: 可选参数,控制生成的索引的上限。

def triu_indices_from(
    arr: NDArray[Any],
    k: int = ...,
) -> tuple[NDArray[int_], NDArray[int_]]: ...


# 返回给定数组的上三角矩阵的索引元组。
# 返回给定数组的上三角矩阵的所有行列索引。
# - arr: 输入的数组,返回其上三角矩阵的索引。
# - k: 控制生成的索引与主对角线的关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值