NumPy-源码解析-四十-

199 阅读1小时+

NumPy 源码解析(四十)

.\numpy\numpy\random\_generator.pyx

# 导入必要的模块和函数
#!python
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, binding=True
import operator  # 导入operator模块,用于操作符函数
import warnings  # 导入warnings模块,用于警告处理
from collections.abc import Sequence  # 从collections.abc模块导入Sequence抽象基类

# 导入Cython模块和函数
from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer
from cpython cimport (Py_INCREF, PyFloat_AsDouble)
from cpython.mem cimport PyMem_Malloc, PyMem_Free

cimport cython  # 导入Cython编译器指令
import numpy as np  # 导入NumPy库
cimport numpy as np  # 在Cython中导入NumPy库,用于高效访问NumPy数组的C语言API
from numpy.lib.array_utils import normalize_axis_index  # 从NumPy库导入数组工具模块中的函数

# 导入自定义Cython扩展模块
from .c_distributions cimport *
from libc cimport string  # 从C标准库libc中导入string模块,用于字符串处理
from libc.math cimport sqrt  # 从C标准库libc中导入math模块中的sqrt函数,用于计算平方根
from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t,
                          int32_t, int64_t, INT64_MAX, SIZE_MAX)  # 从C标准库libc中导入整数类型和常量

# 导入自定义Cython扩展模块中的函数和类
from ._bounded_integers cimport (_rand_bool, _rand_int32, _rand_int64,
         _rand_int16, _rand_int8, _rand_uint64, _rand_uint32, _rand_uint16,
         _rand_uint8, _gen_mask)  # 导入各种整数生成函数和掩码生成函数
from ._pcg64 import PCG64  # 导入PCG64伪随机数生成器类
from numpy.random cimport bitgen_t  # 在Cython中导入NumPy库中定义的位生成器类型
from ._common cimport (POISSON_LAM_MAX, CONS_POSITIVE, CONS_NONE,
            CONS_NON_NEGATIVE, CONS_BOUNDED_0_1, CONS_BOUNDED_GT_0_1,
            CONS_BOUNDED_LT_0_1, CONS_GT_1, CONS_POSITIVE_NOT_NAN, CONS_POISSON,
            double_fill, cont, kahan_sum, cont_broadcast_3, float_fill, cont_f,
            check_array_constraint, check_constraint, disc, discrete_broadcast_iii,
            validate_output_shape
        )  # 导入共享的常量和函数,用于约束检查和数值处理

# 定义与NumPy数组对象相关的C语言API接口
cdef extern from "numpy/arrayobject.h":
    int PyArray_ResolveWritebackIfCopy(np.ndarray)  # 解析数组对象的写回行为(若存在)
    int PyArray_FailUnlessWriteable(np.PyArrayObject *obj,
                                    const char *name) except -1  # 检查数组对象是否可写
    object PyArray_FromArray(np.PyArrayObject *, np.PyArray_Descr *, int)  # 根据现有数组对象创建新的NumPy数组对象

    enum:
        NPY_ARRAY_WRITEBACKIFCOPY  # NumPy数组写回标志

np.import_array()  # 导入NumPy的数组接口

# 定义一个Cython函数,安全地对非负整数数组求和
cdef int64_t _safe_sum_nonneg_int64(size_t num_colors, int64_t *colors):
    """
    Sum the values in the array `colors`.

    Return -1 if an overflow occurs.
    The values in *colors are assumed to be nonnegative.
    """
    cdef size_t i
    cdef int64_t sum

    sum = 0  # 初始化总和为0
    for i in range(num_colors):
        if colors[i] > INT64_MAX - sum:
            return -1  # 若加法溢出则返回-1
        sum += colors[i]  # 累加数组中的值
    return sum  # 返回总和结果

# 定义一个内联函数,用于封装对原始数据的重新排序操作
cdef inline void _shuffle_raw_wrap(bitgen_t *bitgen, np.npy_intp n,
                                   np.npy_intp first, np.npy_intp itemsize,
                                   np.npy_intp stride,
                                   char* data, char* buf) noexcept nogil:
    # 通过调用_cythonized的_shuffle_raw函数实现具体的原始数据重排操作
    # 这里通过优化特定情况(itemsize等于sizeof(np.npy_intp))提高性能约33%
    if itemsize == sizeof(np.npy_intp):
        _shuffle_raw(bitgen, n, first, sizeof(np.npy_intp), stride, data, buf)
    else:
        _shuffle_raw(bitgen, n, first, itemsize, stride, data, buf)
cdef inline void _shuffle_raw(bitgen_t *bitgen, np.npy_intp n,
                              np.npy_intp first, np.npy_intp itemsize,
                              np.npy_intp stride,
                              char* data, char* buf) noexcept nogil:
    """
    Parameters
    ----------
    bitgen
        指向 bitgen_t 实例的指针。
    n
        data 中的元素数量。
    first
        首个要进行洗牌的观察结果。洗牌 n-1, n-2, ..., first,当 first=1 时整个数组被洗牌。
    itemsize
        每个项的字节大小。
    stride
        数组的步长。
    data
        数据的位置。
    buf
        缓冲区的位置 (itemsize)。
    """
    cdef np.npy_intp i, j

    for i in reversed(range(first, n)):
        j = random_interval(bitgen, i)
        string.memcpy(buf, data + j * stride, itemsize)
        string.memcpy(data + j * stride, data + i * stride, itemsize)
        string.memcpy(data + i * stride, buf, itemsize)


cdef inline void _shuffle_int(bitgen_t *bitgen, np.npy_intp n,
                              np.npy_intp first, int64_t* data) noexcept nogil:
    """
    Parameters
    ----------
    bitgen
        指向 bitgen_t 实例的指针。
    n
        data 中的元素数量。
    first
        首个要进行洗牌的观察结果。洗牌 n-1, n-2, ..., first,当 first=1 时整个数组被洗牌。
    data
        数据的位置。
    """
    cdef np.npy_intp i, j
    cdef int64_t temp
    for i in reversed(range(first, n)):
        j = random_bounded_uint64(bitgen, 0, i, 0, 0)
        temp = data[j]
        data[j] = data[i]
        data[i] = temp


cdef bint _check_bit_generator(object bitgen):
    """检查对象是否符合 BitGenerator 接口。"""
    if not hasattr(bitgen, "capsule"):
        return False
    cdef const char *name = "BitGenerator"
    return PyCapsule_IsValid(bitgen.capsule, name)


cdef class Generator:
    """
    Generator(bit_generator)

    `Generator` 是 BitGenerators 的容器。

    `Generator` 提供了从各种概率分布生成随机数的多种方法。除了特定于分布的参数外,每个方法还接受一个关键字参数 `size`,默认为 `None`。如果 `size` 是 `None`,则生成并返回单个值。如果 `size` 是整数,则返回填充有生成值的一维数组。如果 `size` 是元组,则返回填充有相应形状的数组。

    函数 :func:`numpy.random.default_rng` 将使用 numpy 默认的 `BitGenerator` 实例化一个 `Generator`。

    **不保证兼容性**

    `Generator` 不提供版本兼容性的保证。特别是随着更好的算法的发展,位流可能会发生变化。

    Parameters
    ----------
    bit_generator : BitGenerator
        作为核心生成器使用的 BitGenerator 实例。

    Notes
    -----
    """
    """
    The Python stdlib module `random` contains pseudo-random number generator
    with a number of methods that are similar to the ones available in
    `Generator`. It uses Mersenne Twister, and this bit generator can
    be accessed using `MT19937`. `Generator`, besides being
    NumPy-aware, has the advantage that it provides a much larger number
    of probability distributions to choose from.

    Examples
    --------
    >>> from numpy.random import Generator, PCG64
    >>> rng = Generator(PCG64())
    >>> rng.standard_normal()
    -0.203  # random

    See Also
    --------
    default_rng : Recommended constructor for `Generator`.
    """
    
    # 定义Cython公共属性_bit_generator,用于存储位生成器对象
    cdef public object _bit_generator
    
    # 定义Cython变量_bitgen,用于存储位生成器结构体
    cdef bitgen_t _bitgen
    
    # 定义Cython变量_binomial,用于存储二项式分布结构体
    cdef binomial_t _binomial
    
    # 定义Cython属性lock,用于存储锁对象
    cdef object lock
    
    # 初始化类,接受一个bit_generator参数作为输入
    _poisson_lam_max = POISSON_LAM_MAX
    
    def __init__(self, bit_generator):
        # 将输入的bit_generator存储到实例的_bit_generator属性中
        self._bit_generator = bit_generator
        
        # 获取bit_generator的capsule
        capsule = bit_generator.capsule
        
        # 定义Cython变量name为"BitGenerator"
        cdef const char *name = "BitGenerator"
        
        # 如果capsule无效,则抛出值错误异常
        if not PyCapsule_IsValid(capsule, name):
            raise ValueError("Invalid bit generator. The bit generator must "
                             "be instantiated.")
        
        # 将capsule中的指针解析为bitgen_t类型,并存储到_bitgen中
        self._bitgen = (<bitgen_t *> PyCapsule_GetPointer(capsule, name))[0]
        
        # 将bit_generator的锁对象存储到实例的lock属性中
        self.lock = bit_generator.lock

    def __repr__(self):
        # 返回实例的字符串表示形式,包含内存地址信息
        return self.__str__() + ' at 0x{:X}'.format(id(self))

    def __str__(self):
        # 返回实例的字符串表示形式,包含类名和位生成器的类名
        _str = self.__class__.__name__
        _str += '(' + self.bit_generator.__class__.__name__ + ')'
        return _str

    # Pickling support:
    def __getstate__(self):
        # 返回None,表示此类不能被序列化
        return None

    def __setstate__(self, bit_gen):
        # 如果bit_gen是字典类型,则为兼容旧版本路径
        if isinstance(bit_gen, dict):
            # 以旧版本方式设置bit_generator的状态
            # 在2.0.x之前,仅保留底层位生成器的状态,任何种子序列信息将丢失
            self.bit_generator.state = bit_gen

    def __reduce__(self):
        # 导入内部函数__generator_ctor
        from ._pickle import __generator_ctor
        
        # 返回元组(__generator_ctor, (self._bit_generator, ), None),用于序列化实例
        # __generator_ctor要求参数为(bit_generator, )
        return __generator_ctor, (self._bit_generator, ), None

    @property
    def bit_generator(self):
        """
        Gets the bit generator instance used by the generator

        Returns
        -------
        bit_generator : BitGenerator
            The bit generator instance used by the generator
        """
        # 返回实例的_bit_generator属性,即位生成器对象
        return self._bit_generator
    def spawn(self, int n_children):
        """
        spawn(n_children)

        Create new independent child generators.

        See :ref:`seedsequence-spawn` for additional notes on spawning
        children.

        .. versionadded:: 1.25.0

        Parameters
        ----------
        n_children : int
            Number of child generators to create.

        Returns
        -------
        child_generators : list of Generators
            List containing newly spawned child generator objects.

        Raises
        ------
        TypeError
            Raised when the underlying SeedSequence does not support spawning.

        See Also
        --------
        random.BitGenerator.spawn, random.SeedSequence.spawn :
            Equivalent method on the bit generator and seed sequence.
        bit_generator :
            The bit generator instance used by the generator.

        Examples
        --------
        Starting from a seeded default generator:

        >>> # High quality entropy created with: f"0x{secrets.randbits(128):x}"
        >>> entropy = 0x3034c61a9ae04ff8cb62ab8ec2c4b501
        >>> rng = np.random.default_rng(entropy)

        Create two new generators for example for parallel execution:

        >>> child_rng1, child_rng2 = rng.spawn(2)

        Drawn numbers from each are independent but derived from the initial
        seeding entropy:

        >>> rng.uniform(), child_rng1.uniform(), child_rng2.uniform()
        (0.19029263503854454, 0.9475673279178444, 0.4702687338396767)

        It is safe to spawn additional children from the original ``rng`` or
        the children:

        >>> more_child_rngs = rng.spawn(20)
        >>> nested_spawn = child_rng1.spawn(20)

        """
        # 返回一个列表,其中包含从当前生成器的位生成器上生成的n_children个子生成器实例
        return [type(self)(g) for g in self._bit_generator.spawn(n_children)]
    def random(self, size=None, dtype=np.float64, out=None):
        """
        random(size=None, dtype=np.float64, out=None)

        Return random floats in the half-open interval [0.0, 1.0).

        Results are from the "continuous uniform" distribution over the
        stated interval.  To sample :math:`Unif[a, b), b > a` use `uniform`
        or multiply the output of `random` by ``(b - a)`` and add ``a``::

            (b - a) * random() + a

        Parameters
        ----------
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  Default is None, in which case a
            single value is returned.
        dtype : dtype, optional
            Desired dtype of the result, only `float64` and `float32` are supported.
            Byteorder must be native. The default value is np.float64.
        out : ndarray, optional
            Alternative output array in which to place the result. If size is not None,
            it must have the same shape as the provided size and must match the type of
            the output values.

        Returns
        -------
        out : float or ndarray of floats
            Array of random floats of shape `size` (unless ``size=None``, in which
            case a single float is returned).

        See Also
        --------
        uniform : Draw samples from the parameterized uniform distribution.

        Examples
        --------
        >>> rng = np.random.default_rng()
        >>> rng.random()
        0.47108547995356098 # random
        >>> type(rng.random())
        <class 'float'>
        >>> rng.random((5,))
        array([ 0.30220482,  0.86820401,  0.1654503 ,  0.11659149,  0.54323428]) # random

        Three-by-two array of random numbers from [-5, 0):

        >>> 5 * rng.random((3, 2)) - 5
        array([[-3.99149989, -0.52338984], # random
               [-2.99091858, -0.79479508],
               [-1.23204345, -1.75224494]])

        """
        # 定义临时变量 temp
        cdef double temp
        # 将 dtype 转换为 numpy 的 dtype 对象
        _dtype = np.dtype(dtype)
        # 根据 dtype 类型选择不同的填充函数,并返回结果
        if _dtype == np.float64:
            # 使用双精度填充函数处理随机数生成
            return double_fill(&random_standard_uniform_fill, &self._bitgen, size, self.lock, out)
        elif _dtype == np.float32:
            # 使用单精度填充函数处理随机数生成
            return float_fill(&random_standard_uniform_fill_f, &self._bitgen, size, self.lock, out)
        else:
            # 抛出类型错误,如果不支持指定的 dtype
            raise TypeError('Unsupported dtype %r for random' % _dtype)
    # 定义一个方法用于生成标准指数分布的随机数,可以指定输出的数据类型和方法
    def standard_exponential(self, size=None, dtype=np.float64, method='zig', out=None):
        """
        standard_exponential(size=None, dtype=np.float64, method='zig', out=None)

        Draw samples from the standard exponential distribution.

        `standard_exponential` is identical to the exponential distribution
        with a scale parameter of 1.

        Parameters
        ----------
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  Default is None, in which case a
            single value is returned.
        dtype : dtype, optional
            Desired dtype of the result, only `float64` and `float32` are supported.
            Byteorder must be native. The default value is np.float64.
        method : str, optional
            Either 'inv' or 'zig'. 'inv' uses the default inverse CDF method.
            'zig' uses the much faster Ziggurat method of Marsaglia and Tsang.
        out : ndarray, optional
            Alternative output array in which to place the result. If size is not None,
            it must have the same shape as the provided size and must match the type of
            the output values.

        Returns
        -------
        out : float or ndarray
            Drawn samples.

        Examples
        --------
        Output a 3x8000 array:

        >>> rng = np.random.default_rng()
        >>> n = rng.standard_exponential((3, 8000))

        """
        # 获取指定dtype的dtype对象
        _dtype = np.dtype(dtype)
        # 根据dtype选择不同的生成方法
        if _dtype == np.float64:
            if method == 'zig':
                # 使用double_fill函数生成标准指数分布的双精度浮点数样本
                return double_fill(&random_standard_exponential_fill, &self._bitgen, size, self.lock, out)
            else:
                # 使用double_fill函数生成标准指数分布的双精度浮点数样本(使用逆CDF方法)
                return double_fill(&random_standard_exponential_inv_fill, &self._bitgen, size, self.lock, out)
        elif _dtype == np.float32:
            if method == 'zig':
                # 使用float_fill函数生成标准指数分布的单精度浮点数样本
                return float_fill(&random_standard_exponential_fill_f, &self._bitgen, size, self.lock, out)
            else:
                # 使用float_fill函数生成标准指数分布的单精度浮点数样本(使用逆CDF方法)
                return float_fill(&random_standard_exponential_inv_fill_f, &self._bitgen, size, self.lock, out)
        else:
            # 抛出错误,不支持的dtype类型
            raise TypeError('Unsupported dtype %r for standard_exponential'
                            % _dtype)
    def bytes(self, np.npy_intp length):
        """
        bytes(length)

        Return random bytes.

        Parameters
        ----------
        length : int
            Number of random bytes.

        Returns
        -------
        out : bytes
            String of length `length`.

        Notes
        -----
        This function generates random bytes from a discrete uniform 
        distribution. The generated bytes are independent from the CPU's 
        native endianness.
        
        Examples
        --------
        >>> rng = np.random.default_rng()
        >>> rng.bytes(10)
        b'\\xfeC\\x9b\\x86\\x17\\xf2\\xa1\\xafcp'  # random

        """
        # Calculate the number of 32-bit unsigned integers needed to cover 'length' bytes
        cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1)
        
        # Generate random integers from 0 to 4294967295 (2^32 - 1), size adjusted for 'length'
        # Convert these integers to little-endian byte order, then convert to bytes and truncate to 'length'
        return self.integers(0, 4294967296, size=n_uint32,
                             dtype=np.uint32).astype('<u4').tobytes()[:length]

    @cython.wraparound(True)
    # Enable wraparound indexing for Cython (handle negative indices as Python does):
    def standard_normal(self, size=None, dtype=np.float64, out=None):
        """
        standard_normal(size=None, dtype=np.float64, out=None)

        Draw samples from a standard Normal distribution (mean=0, stdev=1).

        Parameters
        ----------
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  Default is None, in which case a
            single value is returned.
        dtype : dtype, optional
            Desired dtype of the result, only `float64` and `float32` are supported.
            Byteorder must be native. The default value is np.float64.
        out : ndarray, optional
            Alternative output array in which to place the result. If size is not None,
            it must have the same shape as the provided size and must match the type of
            the output values.

        Returns
        -------
        out : float or ndarray
            A floating-point array of shape ``size`` of drawn samples, or a
            single sample if ``size`` was not specified.

        See Also
        --------
        normal :
            Equivalent function with additional ``loc`` and ``scale`` arguments
            for setting the mean and standard deviation.

        Notes
        -----
        For random samples from the normal distribution with mean ``mu`` and
        standard deviation ``sigma``, use one of::

            mu + sigma * rng.standard_normal(size=...)
            rng.normal(mu, sigma, size=...)

        Examples
        --------
        >>> rng = np.random.default_rng()
        >>> rng.standard_normal()
        2.1923875335537315 # random

        >>> s = rng.standard_normal(8000)
        >>> s
        array([ 0.6888893 ,  0.78096262, -0.89086505, ...,  0.49876311,  # random
               -0.38672696, -0.4685006 ])                                # random
        >>> s.shape
        (8000,)
        >>> s = rng.standard_normal(size=(3, 4, 2))
        >>> s.shape
        (3, 4, 2)

        Two-by-four array of samples from the normal distribution with
        mean 3 and standard deviation 2.5:

        >>> 3 + 2.5 * rng.standard_normal(size=(2, 4))
        array([[-4.49401501,  4.00950034, -1.81814867,  7.29718677],   # random
               [ 0.39924804,  4.68456316,  4.99394529,  4.84057254]])  # random

        """
        # 获取指定的数据类型
        _dtype = np.dtype(dtype)
        # 检查数据类型是否为 np.float64
        if _dtype == np.float64:
            # 如果是 np.float64,则调用 double_fill 函数生成标准正态分布的样本
            return double_fill(&random_standard_normal_fill, &self._bitgen, size, self.lock, out)
        # 检查数据类型是否为 np.float32
        elif _dtype == np.float32:
            # 如果是 np.float32,则调用 float_fill 函数生成标准正态分布的样本
            return float_fill(&random_standard_normal_fill_f, &self._bitgen, size, self.lock, out)
        else:
            # 抛出错误,不支持的数据类型
            raise TypeError('Unsupported dtype %r for standard_normal' % _dtype)
    def chisquare(self, df, size=None):
        """
        chisquare(df, size=None)

        Draw samples from a chi-square distribution.

        When `df` independent random variables, each with standard normal
        distributions (mean 0, variance 1), are squared and summed, the
        resulting distribution is chi-square (see Notes).  This distribution
        is often used in hypothesis testing.

        Parameters
        ----------
        df : float or array_like of floats
             Number of degrees of freedom, must be > 0.
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  If size is ``None`` (default),
            a single value is returned if ``df`` is a scalar.  Otherwise,
            ``np.array(df).size`` samples are drawn.

        Returns
        -------
        out : ndarray or scalar
            Drawn samples from the parameterized chi-square distribution.

        Raises
        ------
        ValueError
            When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``)
            is given.

        Notes
        -----
        The variable obtained by summing the squares of `df` independent,
        standard normally distributed random variables:

        .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i

        is chi-square distributed, denoted

        .. math:: Q \\sim \\chi^2_k.

        The probability density function of the chi-squared distribution is

        .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)}
                         x^{k/2 - 1} e^{-x/2},

        where :math:`\\Gamma` is the gamma function,

        .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt.

        References
        ----------
        .. [1] NIST "Engineering Statistics Handbook"
               https://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm

        Examples
        --------
        >>> rng = np.random.default_rng()
        >>> rng.chisquare(2,4)
        array([ 1.89920014,  9.00867716,  3.13710533,  5.62318272]) # random

        The distribution of a chi-square random variable
        with 20 degrees of freedom looks as follows:
        
        >>> import matplotlib.pyplot as plt
        >>> import scipy.stats as stats
        >>> s = rng.chisquare(20, 10000)
        >>> count, bins, _ = plt.hist(s, 30, density=True)
        >>> x = np.linspace(0, 60, 1000)
        >>> plt.plot(x, stats.chi2.pdf(x, df=20))
        >>> plt.xlim([0, 60])
        >>> plt.show()

        """
        # 调用底层函数以生成卡方分布的随机样本
        return cont(&random_chisquare, &self._bitgen, size, self.lock, 1,
                    df, 'df', CONS_POSITIVE,
                    0.0, '', CONS_NONE,
                    0.0, '', CONS_NONE, None)
    # 定义一个方法用于生成标准 Cauchy 分布的样本数据
    def standard_cauchy(self, size=None):
        """
        standard_cauchy(size=None)

        Draw samples from a standard Cauchy distribution with mode = 0.

        Also known as the Lorentz distribution.

        Parameters
        ----------
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  Default is None, in which case a
            single value is returned.

        Returns
        -------
        samples : ndarray or scalar
            The drawn samples.

        Notes
        -----
        The probability density function for the full Cauchy distribution is

        .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+
                  (\\frac{x-x_0}{\\gamma})^2 \\bigr] }

        and the Standard Cauchy distribution just sets :math:`x_0=0` and
        :math:`\\gamma=1`

        The Cauchy distribution arises in the solution to the driven harmonic
        oscillator problem, and also describes spectral line broadening. It
        also describes the distribution of values at which a line tilted at
        a random angle will cut the x axis.

        When studying hypothesis tests that assume normality, seeing how the
        tests perform on data from a Cauchy distribution is a good indicator of
        their sensitivity to a heavy-tailed distribution, since the Cauchy looks
        very much like a Gaussian distribution, but with heavier tails.

        References
        ----------
        .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy
              Distribution",
              https://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm
        .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A
              Wolfram Web Resource.
              https://mathworld.wolfram.com/CauchyDistribution.html
        .. [3] Wikipedia, "Cauchy distribution"
              https://en.wikipedia.org/wiki/Cauchy_distribution

        Examples
        --------
        Draw samples and plot the distribution:

        >>> import matplotlib.pyplot as plt
        >>> rng = np.random.default_rng()
        >>> s = rng.standard_cauchy(1000000)
        >>> s = s[(s>-25) & (s<25)]  # truncate distribution so it plots well
        >>> plt.hist(s, bins=100)
        >>> plt.show()

        """
        # 调用 C 库函数以生成标准 Cauchy 分布的样本数据
        return cont(&random_standard_cauchy, &self._bitgen, size, self.lock, 0,
                    0.0, '', CONS_NONE, 0.0, '', CONS_NONE, 0.0, '', CONS_NONE, None)
    def pareto(self, a, size=None):
        """
        pareto(a, size=None)

        Draw samples from a Pareto II (AKA Lomax) distribution with
        specified shape.

        Parameters
        ----------
        a : float or array_like of floats
            Shape of the distribution. Must be positive.
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  If size is ``None`` (default),
            a single value is returned if ``a`` is a scalar.  Otherwise,
            ``np.array(a).size`` samples are drawn.

        Returns
        -------
        out : ndarray or scalar
            Drawn samples from the Pareto II distribution.

        See Also
        --------
        scipy.stats.pareto : Pareto I distribution
        scipy.stats.lomax : Lomax (Pareto II) distribution
        scipy.stats.genpareto : Generalized Pareto distribution

        Notes
        -----
        The probability density for the Pareto II distribution is

        .. math:: p(x) = \\frac{a}{{x+1}^{a+1}} , x \ge 0

        where :math:`a > 0` is the shape.

        The Pareto II distribution is a shifted and scaled version of the
        Pareto I distribution, which can be found in `scipy.stats.pareto`.

        References
        ----------
        .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of
               Sourceforge projects.
        .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne.
        .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme
               Values, Birkhauser Verlag, Basel, pp 23-30.
        .. [4] Wikipedia, "Pareto distribution",
               https://en.wikipedia.org/wiki/Pareto_distribution

        Examples
        --------
        Draw samples from the distribution:

        >>> a = 3.
        >>> rng = np.random.default_rng()
        >>> s = rng.pareto(a, 10000)

        Display the histogram of the samples, along with the probability
        density function:

        >>> import matplotlib.pyplot as plt
        >>> x = np.linspace(0, 3, 50)
        >>> pdf = a / (x+1)**(a+1)
        >>> plt.hist(s, bins=x, density=True, label='histogram')
        >>> plt.plot(x, pdf, linewidth=2, color='r', label='pdf')
        >>> plt.xlim(x.min(), x.max())
        >>> plt.legend()
        >>> plt.show()

        """
        # 调用 C 函数生成 Pareto II 分布的随机样本
        return cont(&random_pareto, &self._bitgen, size, self.lock, 1,
                    # 参数 a:分布的形状参数
                    a, 'a', CONS_POSITIVE,
                    # 默认值 0.0
                    0.0, '', CONS_NONE,
                    # 默认值 0.0
                    0.0, '', CONS_NONE, None)
    def rayleigh(self, scale=1.0, size=None):
        """
        rayleigh(scale=1.0, size=None)

        从 Rayleigh 分布中抽取样本。

        :math:`\\chi` 和 Weibull 分布是 Rayleigh 分布的推广。

        Parameters
        ----------
        scale : float or array_like of floats, optional
            尺度参数,也等于众数。必须为非负数。默认为 1。
        size : int or tuple of ints, optional
            输出的形状。如果给定形状为 ``(m, n, k)``,则抽取 ``m * n * k`` 个样本。
            如果 `size` 为 `None`(默认),且 `scale` 为标量,则返回单个值。
            否则,抽取 `np.array(scale).size` 个样本。

        Returns
        -------
        out : ndarray or scalar
            从参数化的 Rayleigh 分布中抽取的样本。

        Notes
        -----
        Rayleigh 分布的概率密度函数为:

        .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}}

        例如,如果风速的东向分量和北向分量都服从相同的均值为零的高斯分布,
        那么风速将服从 Rayleigh 分布。

        References
        ----------
        .. [1] Brighton Webs Ltd., "Rayleigh Distribution,"
               https://web.archive.org/web/20090514091424/http://brighton-webs.co.uk:80/distributions/rayleigh.asp
        .. [2] Wikipedia, "Rayleigh distribution"
               https://en.wikipedia.org/wiki/Rayleigh_distribution

        Examples
        --------
        从分布中抽取值并绘制直方图:

        >>> from matplotlib.pyplot import hist
        >>> rng = np.random.default_rng()
        >>> values = hist(rng.rayleigh(3, 100000), bins=200, density=True)

        浪高往往遵循 Rayleigh 分布。如果平均浪高为 1 米,有多少浪的高度可能大于 3 米?

        >>> meanvalue = 1
        >>> modevalue = np.sqrt(2 / np.pi) * meanvalue
        >>> s = rng.rayleigh(modevalue, 1000000)

        高于 3 米的浪的百分比为:

        >>> 100.*sum(s>3)/1000000.
        0.087300000000000003 # 随机

        """
        # 调用 `random_rayleigh` 函数以从 Rayleigh 分布中抽取随机样本
        return cont(&random_rayleigh, &self._bitgen, size, self.lock, 1,
                    scale, 'scale', CONS_NON_NEGATIVE,
                    0.0, '', CONS_NONE,
                    0.0, '', CONS_NONE, None)
    # 定义 Wald 分布的抽样方法,返回符合参数化 Wald 分布的样本
    def wald(self, mean, scale, size=None):
        """
        wald(mean, scale, size=None)

        Draw samples from a Wald, or inverse Gaussian, distribution.

        As the scale approaches infinity, the distribution becomes more like a
        Gaussian. Some references claim that the Wald is an inverse Gaussian
        with mean equal to 1, but this is by no means universal.

        The inverse Gaussian distribution was first studied in relationship to
        Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian
        because there is an inverse relationship between the time to cover a
        unit distance and distance covered in unit time.

        Parameters
        ----------
        mean : float or array_like of floats
            Distribution mean, must be > 0.
        scale : float or array_like of floats
            Scale parameter, must be > 0.
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  If size is ``None`` (default),
            a single value is returned if ``mean`` and ``scale`` are both scalars.
            Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn.

        Returns
        -------
        out : ndarray or scalar
            Drawn samples from the parameterized Wald distribution.

        Notes
        -----
        The probability density function for the Wald distribution is

        .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^
                                    \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x}

        As noted above the inverse Gaussian distribution first arise
        from attempts to model Brownian motion. It is also a
        competitor to the Weibull for use in reliability modeling and
        modeling stock returns and interest rate processes.

        References
        ----------
        .. [1] Brighton Webs Ltd., Wald Distribution,
               https://web.archive.org/web/20090423014010/http://www.brighton-webs.co.uk:80/distributions/wald.asp
        .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian
               Distribution: Theory : Methodology, and Applications", CRC Press,
               1988.
        .. [3] Wikipedia, "Inverse Gaussian distribution"
               https://en.wikipedia.org/wiki/Inverse_Gaussian_distribution

        Examples
        --------
        Draw values from the distribution and plot the histogram:

        >>> import matplotlib.pyplot as plt
        >>> rng = np.random.default_rng()
        >>> h = plt.hist(rng.wald(3, 2, 100000), bins=200, density=True)
        >>> plt.show()

        """
        # 调用底层 C 函数 cont,实现复杂的 Wald 分布抽样
        return cont(&random_wald, &self._bitgen, size, self.lock, 2,
                    mean, 'mean', CONS_POSITIVE,
                    scale, 'scale', CONS_POSITIVE,
                    0.0, '', CONS_NONE, None)

    # 复杂的离散分布:
    def poisson(self, lam=1.0, size=None):
        """
        poisson(lam=1.0, size=None)

        Draw samples from a Poisson distribution.

        The Poisson distribution is the limit of the binomial distribution
        for large N.

        Parameters
        ----------
        lam : float or array_like of floats
            Expected number of events occurring in a fixed-time interval,
            must be >= 0. A sequence must be broadcastable over the requested
            size.
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  If size is ``None`` (default),
            a single value is returned if ``lam`` is a scalar. Otherwise,
            ``np.array(lam).size`` samples are drawn.

        Returns
        -------
        out : ndarray or scalar
            Drawn samples from the parameterized Poisson distribution.

        Notes
        -----
        The Poisson distribution

        .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!}

        For events with an expected separation :math:`\\lambda` the Poisson
        distribution :math:`f(k; \\lambda)` describes the probability of
        :math:`k` events occurring within the observed
        interval :math:`\\lambda`.

        Because the output is limited to the range of the C int64 type, a
        ValueError is raised when `lam` is within 10 sigma of the maximum
        representable value.

        References
        ----------
        .. [1] Weisstein, Eric W. "Poisson Distribution."
               From MathWorld--A Wolfram Web Resource.
               https://mathworld.wolfram.com/PoissonDistribution.html
        .. [2] Wikipedia, "Poisson distribution",
               https://en.wikipedia.org/wiki/Poisson_distribution

        Examples
        --------
        Draw samples from the distribution:

        >>> rng = np.random.default_rng()
        >>> lam, size = 5, 10000
        >>> s = rng.poisson(lam=lam, size=size)

        Verify the mean and variance, which should be approximately ``lam``:
        
        >>> s.mean(), s.var()
        (4.9917 5.1088311)  # may vary

        Display the histogram and probability mass function:

        >>> import matplotlib.pyplot as plt
        >>> from scipy import stats
        >>> x = np.arange(0, 21)
        >>> pmf = stats.poisson.pmf(x, mu=lam)
        >>> plt.hist(s, bins=x, density=True, width=0.5)
        >>> plt.stem(x, pmf, 'C1-')
        >>> plt.show()

        Draw each 100 values for lambda 100 and 500:

        >>> s = rng.poisson(lam=(100., 500.), size=(100, 2))

        """
        使用指定的参数调用底层的随机泊松函数,返回随机数样本
        return disc(&random_poisson, &self._bitgen, size, self.lock, 1, 0,
                    lam, 'lam', CONS_POISSON,
                    0.0, '', CONS_NONE,
                    0.0, '', CONS_NONE)
    # 定义 geometric 方法,用于从几何分布中抽取样本
    def geometric(self, p, size=None):
        """
        geometric(p, size=None)

        Draw samples from the geometric distribution.

        Bernoulli trials are experiments with one of two outcomes:
        success or failure (an example of such an experiment is flipping
        a coin).  The geometric distribution models the number of trials
        that must be run in order to achieve success.  It is therefore
        supported on the positive integers, ``k = 1, 2, ...``.

        The probability mass function of the geometric distribution is

        .. math:: f(k) = (1 - p)^{k - 1} p

        where `p` is the probability of success of an individual trial.

        Parameters
        ----------
        p : float or array_like of floats
            The probability of success of an individual trial.
        size : int or tuple of ints, optional
            Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
            ``m * n * k`` samples are drawn.  If size is ``None`` (default),
            a single value is returned if ``p`` is a scalar.  Otherwise,
            ``np.array(p).size`` samples are drawn.

        Returns
        -------
        out : ndarray or scalar
            Drawn samples from the parameterized geometric distribution.

        References
        ----------

        .. [1] Wikipedia, "Geometric distribution",
               https://en.wikipedia.org/wiki/Geometric_distribution

        Examples
        --------
        Draw 10,000 values from the geometric distribution, with the 
        probability of an individual success equal to ``p = 0.35``:

        >>> p, size = 0.35, 10000
        >>> rng = np.random.default_rng()
        >>> sample = rng.geometric(p=p, size=size)

        What proportion of trials succeeded after a single run?

        >>> (sample == 1).sum()/size
        0.34889999999999999  # may vary

        The geometric distribution with ``p=0.35`` looks as follows:

        >>> import matplotlib.pyplot as plt
        >>> count, bins, _ = plt.hist(sample, bins=30, density=True)
        >>> plt.plot(bins, (1-p)**(bins-1)*p)
        >>> plt.xlim([0, 25])
        >>> plt.show()
        
        """
        # 调用底层的离散分布函数 disc,抽取几何分布的样本
        return disc(&random_geometric, &self._bitgen, size, self.lock, 1, 0,
                    p, 'p', CONS_BOUNDED_GT_0_1,
                    0.0, '', CONS_NONE,
                    0.0, '', CONS_NONE)

    # Multivariate distributions:
    def permutation(self, object x, axis=0):
        """
        permutation(x, axis=0)

        Randomly permute a sequence, or return a permuted range.

        Parameters
        ----------
        x : int or array_like
            If `x` is an integer, randomly permute ``np.arange(x)``.
            If `x` is an array, make a copy and shuffle the elements
            randomly.
        axis : int, optional
            The axis which `x` is shuffled along. Default is 0.

        Returns
        -------
        out : ndarray
            Permuted sequence or array range.

        Examples
        --------
        >>> rng = np.random.default_rng()
        >>> rng.permutation(10)
        array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) # random

        >>> rng.permutation([1, 4, 9, 12, 15])
        array([15,  1,  9,  4, 12]) # random

        >>> arr = np.arange(9).reshape((3, 3))
        >>> rng.permutation(arr)
        array([[6, 7, 8], # random
               [0, 1, 2],
               [3, 4, 5]])

        >>> rng.permutation("abc")
        Traceback (most recent call last):
            ...
        numpy.exceptions.AxisError: axis 0 is out of bounds for array of dimension 0

        >>> arr = np.arange(9).reshape((3, 3))
        >>> rng.permutation(arr, axis=1)
        array([[0, 2, 1], # random
               [3, 5, 4],
               [6, 8, 7]])

        """
        # 如果 `x` 是整数,则创建一个包含 0 到 x-1 的整数数组,并进行随机排列
        if isinstance(x, (int, np.integer)):
            arr = np.arange(x)
            self.shuffle(arr)
            return arr

        # 将 `x` 转换为 NumPy 数组
        arr = np.asarray(x)

        # 根据轴的索引规范化轴的索引值
        axis = normalize_axis_index(axis, arr.ndim)

        # 如果数组是一维的,进行快速的 shuffle 操作
        if arr.ndim == 1:
            # 如果 `arr` 和 `x` 使用相同的内存,返回一个复制的数组
            if np.may_share_memory(arr, x):
                arr = np.array(arr)
            self.shuffle(arr)
            return arr

        # 对索引数组进行 shuffle,使用 intp 类型以确保快速路径
        idx = np.arange(arr.shape[axis], dtype=np.intp)
        self.shuffle(idx)

        # 构造切片对象以进行索引数组的应用
        slices = [slice(None)] * arr.ndim
        slices[axis] = idx
        return arr[tuple(slices)]
# 在 Cython 中嵌入函数签名,并设置为 True
@cython.embedsignature(True)
# 定义一个函数 default_rng,用于构造一个新的 Generator,使用默认的 BitGenerator (PCG64)
def default_rng(seed=None):
    """Construct a new Generator with the default BitGenerator (PCG64).

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
        A seed to initialize the `BitGenerator`. If None, then fresh,
        unpredictable entropy will be pulled from the OS. If an ``int`` or
        ``array_like[ints]`` is passed, then all values must be non-negative and will be
        passed to `SeedSequence` to derive the initial `BitGenerator` state. One may also
        pass in a `SeedSequence` instance.
        Additionally, when passed a `BitGenerator`, it will be wrapped by
        `Generator`. If passed a `Generator`, it will be returned unaltered.

    Returns
    -------
    Generator
        The initialized generator object.

    Notes
    -----
    If ``seed`` is not a `BitGenerator` or a `Generator`, a new `BitGenerator`
    is instantiated. This function does not manage a default global instance.

    See :ref:`seeding_and_entropy` for more information about seeding.
    
    Examples
    --------
    `default_rng` is the recommended constructor for the random number class
    `Generator`. Here are several ways we can construct a random 
    number generator using `default_rng` and the `Generator` class. 
    
    Here we use `default_rng` to generate a random float:
 
    >>> import numpy as np
    >>> rng = np.random.default_rng(12345)
    >>> print(rng)
    Generator(PCG64)
    >>> rfloat = rng.random()
    >>> rfloat
    0.22733602246716966
    >>> type(rfloat)
    <class 'float'>
     
    Here we use `default_rng` to generate 3 random integers between 0 
    (inclusive) and 10 (exclusive):
        
    >>> import numpy as np
    >>> rng = np.random.default_rng(12345)
    >>> rints = rng.integers(low=0, high=10, size=3)
    >>> rints
    array([6, 2, 7])
    >>> type(rints[0])
    <class 'numpy.int64'>
    
    Here we specify a seed so that we have reproducible results:
    
    >>> import numpy as np
    >>> rng = np.random.default_rng(seed=42)
    >>> print(rng)
    Generator(PCG64)
    >>> arr1 = rng.random((3, 3))
    >>> arr1
    array([[0.77395605, 0.43887844, 0.85859792],
           [0.69736803, 0.09417735, 0.97562235],
           [0.7611397 , 0.78606431, 0.12811363]])

    If we exit and restart our Python interpreter, we'll see that we
    generate the same random numbers again:

    >>> import numpy as np
    >>> rng = np.random.default_rng(seed=42)
    >>> arr2 = rng.random((3, 3))
    >>> arr2
    array([[0.77395605, 0.43887844, 0.85859792],
           [0.69736803, 0.09417735, 0.97562235],
           [0.7611397 , 0.78606431, 0.12811363]])

    """
    # 检查传入的 seed 是否是一个 BitGenerator
    if _check_bit_generator(seed):
        # 如果是 BitGenerator,则直接将其包装为 Generator 并返回
        return Generator(seed)
    # 如果传入的 seed 是 Generator 的实例,则直接返回该实例
    elif isinstance(seed, Generator):
        return seed
   `
    # 否则,我们需要像正常一样实例化一个新的 BitGenerator 和 Generator。
    return Generator(PCG64(seed))

.\numpy\numpy\random\_mt19937.pyi

# 导入必要的类型定义
from typing import TypedDict

# 导入必要的数据类型和函数
from numpy import uint32
from numpy.typing import NDArray
from numpy.random.bit_generator import BitGenerator, SeedSequence
from numpy._typing import _ArrayLikeInt_co

# 定义用于存储 MT19937 内部状态的 TypedDict
class _MT19937Internal(TypedDict):
    key: NDArray[uint32]  # MT19937 算法的内部状态向量
    pos: int  # 当前状态向量的位置

# 定义用于存储 MT19937 完整状态的 TypedDict
class _MT19937State(TypedDict):
    bit_generator: str  # 使用的位生成器名称
    state: _MT19937Internal  # MT19937 的内部状态

# MT19937 类,继承自 BitGenerator
class MT19937(BitGenerator):
    def __init__(self, seed: None | _ArrayLikeInt_co | SeedSequence = ...) -> None:
        ...

    def _legacy_seeding(self, seed: _ArrayLikeInt_co) -> None:
        ...

    def jumped(self, jumps: int = ...) -> MT19937:
        ...

    @property
    def state(self) -> _MT19937State:
        ...

    @state.setter
    def state(self, value: _MT19937State) -> None:
        ...

.\numpy\numpy\random\_mt19937.pyx

#cython: binding=True
# 引入operator模块,用于操作符函数的标准操作
import operator

# 引入numpy库,并且使用Cython语法进行导入
import numpy as np
cimport numpy as np

# 从C标准库libc中导入stdint头文件中的uint32_t和uint64_t类型
from libc.stdint cimport uint32_t, uint64_t
# 从numpy.random中导入BitGenerator和SeedSequence类
from numpy.random cimport BitGenerator, SeedSequence

# 定义模块的公开接口,仅包含MT19937
__all__ = ['MT19937']

# 调用numpy的C API导入数组对象
np.import_array()

# 从"src/mt19937/mt19937.h"头文件中导入以下内容
cdef extern from "src/mt19937/mt19937.h":

    # 定义C结构体s_mt19937_state,包含uint32_t类型的key数组和int类型的pos变量
    struct s_mt19937_state:
        uint32_t key[624]
        int pos

    # 将s_mt19937_state重命名为mt19937_state
    ctypedef s_mt19937_state mt19937_state

    # 定义以下C函数原型,使用nogil标记以避免GIL的影响
    uint64_t mt19937_next64(mt19937_state *state)  nogil
    uint32_t mt19937_next32(mt19937_state *state)  nogil
    double mt19937_next_double(mt19937_state *state)  nogil
    void mt19937_init_by_array(mt19937_state *state, uint32_t *init_key, int key_length)
    void mt19937_seed(mt19937_state *state, uint32_t seed)
    void mt19937_jump(mt19937_state *state)

    # 定义常量RK_STATE_LEN
    enum:
        RK_STATE_LEN

# 定义C函数mt19937_uint64,返回mt19937_next64的结果,避免C++异常处理
cdef uint64_t mt19937_uint64(void *st) noexcept nogil:
    return mt19937_next64(<mt19937_state *> st)

# 定义C函数mt19937_uint32,返回mt19937_next32的结果,避免C++异常处理
cdef uint32_t mt19937_uint32(void *st) noexcept nogil:
    return mt19937_next32(<mt19937_state *> st)

# 定义C函数mt19937_double,返回mt19937_next_double的结果,避免C++异常处理
cdef double mt19937_double(void *st) noexcept nogil:
    return mt19937_next_double(<mt19937_state *> st)

# 定义C函数mt19937_raw,返回mt19937_next32的结果作为uint64_t,避免C++异常处理
cdef uint64_t mt19937_raw(void *st) noexcept nogil:
    return <uint64_t>mt19937_next32(<mt19937_state *> st)

# 定义MT19937类,作为BitGenerator的子类
cdef class MT19937(BitGenerator):
    """
    MT19937(seed=None)

    Mersenne Twister伪随机数生成器的容器类。

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence}, optional
        初始化BitGenerator的种子。如果为None,则从操作系统获取新的不可预测熵。
        如果传递一个int或array_like[ints],则将传递给SeedSequence以派生初始BitGenerator状态。
        也可以传递SeedSequence实例。

    Attributes
    ----------
    lock: threading.Lock
        共享的锁实例,以便在多个生成器中使用相同的位生成器而不会损坏状态。
        从位生成器生成值的代码应持有位生成器的锁。

    Notes
    -----
    MT19937提供一个包含函数指针的胶囊,用于生成双精度数,以及无符号32位和64位整数。
    这些在Python中不能直接消耗,必须由Generator或类似对象消耗,支持低级访问。

    Python标准库模块"random"也包含一个Mersenne Twister伪随机数生成器。

    **状态和种子**

    MT19937状态向量包括一个624元素的32位无符号整数数组,以及一个介于0和624之间的单个整数值,
    用于索引主数组中的当前位置。

    输入种子由SeedSequence处理以填充整个状态。第一个元素被重置,只设置其最高位。

    **并行特性**

    在并行应用程序中使用BitGenerator的首选方法是使用

    """
    """
    cdef mt19937_state rng_state
    """

    # 定义 MT19937 状态结构体变量 rng_state

    def __init__(self, seed=None):
        # 调用父类 BitGenerator 的初始化方法,传入种子值
        BitGenerator.__init__(self, seed)
        # 使用种子序列生成状态值,长度为 RK_STATE_LEN,数据类型为 np.uint32
        val = self._seed_seq.generate_state(RK_STATE_LEN, np.uint32)
        # 将状态数组的第一个元素设为 0x80000000UL,确保非零初始数组
        self.rng_state.key[0] = 0x80000000UL
        # 遍历生成的状态值,将其赋给 rng_state 的 key 数组
        for i in range(1, RK_STATE_LEN):
            self.rng_state.key[i] = val[i]
        # 设置 rng_state 的 pos 属性为 i
        self.rng_state.pos = i

        # 将 _bitgen 的 state 指向 rng_state 的地址
        self._bitgen.state = &self.rng_state
        # 将 _bitgen 的各种生成函数指向相应的 MT19937 版本的函数
        self._bitgen.next_uint64 = &mt19937_uint64
        self._bitgen.next_uint32 = &mt19937_uint32
        self._bitgen.next_double = &mt19937_double
        self._bitgen.next_raw = &mt19937_raw
    # 使用_legacy_seeding方法来对随机数生成器进行向后兼容的种子设置
    def _legacy_seeding(self, seed):
        """
        _legacy_seeding(seed)

        Seed the generator in a backward compatible way. For modern
        applications, creating a new instance is preferable. Calling this
        overrides self._seed_seq

        Parameters
        ----------
        seed : {None, int, array_like}
            Random seed initializing the pseudo-random number generator.
            Can be an integer in [0, 2**32-1], array of integers in
            [0, 2**32-1], a `SeedSequence, or ``None``. If `seed`
            is ``None``, then fresh, unpredictable entropy will be pulled from
            the OS.

        Raises
        ------
        ValueError
            If seed values are out of range for the PRNG.
        """
        # 定义一个NumPy数组对象
        cdef np.ndarray obj
        # 使用self.lock进行线程安全操作
        with self.lock:
            try:
                # 如果seed为None,则使用SeedSequence生成种子
                if seed is None:
                    seed = SeedSequence()
                    # 生成长度为RK_STATE_LEN的状态值
                    val = seed.generate_state(RK_STATE_LEN)
                    # 最高位设置为1,确保初始数组非零
                    self.rng_state.key[0] = 0x80000000UL
                    # 将生成的状态值填充到rng_state.key数组中
                    for i in range(1, RK_STATE_LEN):
                        self.rng_state.key[i] = val[i]
                else:
                    # 如果seed具有squeeze属性,则调用squeeze方法
                    if hasattr(seed, 'squeeze'):
                        seed = seed.squeeze()
                    # 将seed转换为整数索引
                    idx = operator.index(seed)
                    # 如果索引超出范围[0, 2**32 - 1],则抛出ValueError异常
                    if idx > int(2**32 - 1) or idx < 0:
                        raise ValueError("Seed must be between 0 and 2**32 - 1")
                    # 使用mt19937_seed函数对rng_state进行种子初始化
                    mt19937_seed(&self.rng_state, seed)
            # 捕获TypeError异常
            except TypeError:
                # 将seed转换为NumPy数组对象
                obj = np.asarray(seed)
                # 如果数组大小为0,则抛出ValueError异常
                if obj.size == 0:
                    raise ValueError("Seed must be non-empty")
                # 将数组转换为64位整数类型,安全类型转换
                obj = obj.astype(np.int64, casting='safe')
                # 如果数组不是一维的,则抛出ValueError异常
                if obj.ndim != 1:
                    raise ValueError("Seed array must be 1-d")
                # 如果数组中的值超出范围[0, 2**32 - 1],则抛出ValueError异常
                if ((obj > int(2**32 - 1)) | (obj < 0)).any():
                    raise ValueError("Seed must be between 0 and 2**32 - 1")
                # 将数组转换为32位无符号整数类型,不安全类型转换,按C顺序存储
                obj = obj.astype(np.uint32, casting='unsafe', order='C')
                # 使用mt19937_init_by_array函数对rng_state进行数组初始化
                mt19937_init_by_array(&self.rng_state, <uint32_t*> obj.data, np.PyArray_DIM(obj, 0))
        # 将_seed_seq设置为None
        self._seed_seq = None

    # 使用jump_inplace方法来就地跳转状态
    cdef jump_inplace(self, iter):
        """
        Jump state in-place

        Not part of public API

        Parameters
        ----------
        iter : integer, positive
            Number of times to jump the state of the rng.
        """
        # 定义一个NumPy数组索引对象
        cdef np.npy_intp i
        # 循环iter次,调用mt19937_jump函数跳转rng_state的状态
        for i in range(iter):
            mt19937_jump(&self.rng_state)
    def jumped(self, np.npy_intp jumps=1):
        """
        jumped(jumps=1)

        Returns a new bit generator with the state jumped

        The state of the returned bit generator is jumped as-if
        2**(128 * jumps) random numbers have been generated.

        Parameters
        ----------
        jumps : integer, positive
            Number of times to jump the state of the bit generator returned

        Returns
        -------
        bit_generator : MT19937
            New instance of generator jumped iter times

        Notes
        -----
        The jump step is computed using a modified version of Matsumoto's
        implementation of Horner's method. The step polynomial is precomputed
        to perform 2**128 steps. The jumped state has been verified to match
        the state produced using Matsumoto's original code.

        References
        ----------
        .. [1] Matsumoto, M, Generating multiple disjoint streams of
           pseudorandom number sequences.  Accessed on: May 6, 2020.
           http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/JUMP/
        .. [2] Hiroshi Haramoto, Makoto Matsumoto, Takuji Nishimura, François
           Panneton, Pierre L\'Ecuyer, "Efficient Jump Ahead for F2-Linear
           Random Number Generators", INFORMS JOURNAL ON COMPUTING, Vol. 20,
           No. 3, Summer 2008, pp. 385-390.
        """
        cdef MT19937 bit_generator

        # 创建一个新的 MT19937 实例
        bit_generator = self.__class__()
        # 将当前对象的状态复制到新实例
        bit_generator.state = self.state
        # 调用 jump_inplace 方法,跳转状态 jumps 次
        bit_generator.jump_inplace(jumps)

        return bit_generator

    @property
    def state(self):
        """
        Get or set the PRNG state

        Returns
        -------
        state : dict
            Dictionary containing the information required to describe the
            state of the PRNG
        """
        # 创建一个包含当前 PRNG 状态信息的字典
        key = np.zeros(624, dtype=np.uint32)
        for i in range(624):
            key[i] = self.rng_state.key[i]

        return {'bit_generator': self.__class__.__name__,
                'state': {'key': key, 'pos': self.rng_state.pos}}

    @state.setter
    def state(self, value):
        # 如果传入的状态是元组类型,则转换为字典
        if isinstance(value, tuple):
            if value[0] != 'MT19937' or len(value) not in (3, 5):
                raise ValueError('state is not a legacy MT19937 state')
            value ={'bit_generator': 'MT19937',
                    'state': {'key': value[1], 'pos': value[2]}}

        # 如果状态不是字典类型,则抛出类型错误
        if not isinstance(value, dict):
            raise TypeError('state must be a dict')
        # 获取状态字典中的 bit_generator 键,验证是否匹配当前类名
        bitgen = value.get('bit_generator', '')
        if bitgen != self.__class__.__name__:
            raise ValueError('state must be for a {0} '
                             'PRNG'.format(self.__class__.__name__))
        # 将状态字典中的 key 和 pos 值分别复制到当前对象的 rng_state 中
        key = value['state']['key']
        for i in range(624):
            self.rng_state.key[i] = key[i]
        self.rng_state.pos = value['state']['pos']

.\numpy\numpy\random\_pcg64.pyi

# 导入必要的类型引用
from typing import TypedDict

# 导入需要的类和函数
from numpy.random.bit_generator import BitGenerator, SeedSequence
from numpy._typing import _ArrayLikeInt_co

# 定义 PCG64 内部状态的类型字典
class _PCG64Internal(TypedDict):
    state: int  # PCG64 内部状态值
    inc: int    # PCG64 内部增量值

# 定义 PCG64 完整状态的类型字典
class _PCG64State(TypedDict):
    bit_generator: str      # 字符串类型的位生成器名称
    state: _PCG64Internal   # PCG64 内部状态字典
    has_uint32: int         # 是否有无符号整数类型标记
    uinteger: int           # 无符号整数值

# PCG64 类,继承自 BitGenerator 类
class PCG64(BitGenerator):
    def __init__(self, seed: None | _ArrayLikeInt_co | SeedSequence = ...) -> None: ...
    def jumped(self, jumps: int = ...) -> PCG64: ...
    
    @property
    def state(
        self,
    ) -> _PCG64State: ...
    
    @state.setter
    def state(
        self,
        value: _PCG64State,
    ) -> None: ...
    
    def advance(self, delta: int) -> PCG64: ...
    
# PCG64DXSM 类,继承自 BitGenerator 类
class PCG64DXSM(BitGenerator):
    def __init__(self, seed: None | _ArrayLikeInt_co | SeedSequence = ...) -> None: ...
    def jumped(self, jumps: int = ...) -> PCG64DXSM: ...
    
    @property
    def state(
        self,
    ) -> _PCG64State: ...
    
    @state.setter
    def state(
        self,
        value: _PCG64State,
    ) -> None: ...
    
    def advance(self, delta: int) -> PCG64DXSM: ...

.\numpy\numpy\random\_pcg64.pyx

#cython: binding=True
# 导入必要的库和模块
import numpy as np
# 导入 C 扩展中需要的 numpy 模块
cimport numpy as np

# 从 C 标准库中导入指定类型
from libc.stdint cimport uint32_t, uint64_t
# 从 _common 模块中导入特定函数和类型
from ._common cimport uint64_to_double, wrap_int
# 从 numpy.random 中导入 BitGenerator 类
from numpy.random cimport BitGenerator

# 定义公开的类和函数列表
__all__ = ['PCG64']

# 从 C 头文件 pcg64.h 中声明 extern 函数和类型
cdef extern from "src/pcg64/pcg64.h":
    # 使用 int 作为通用类型,具体类型从 pcg64.h 中读取,与平台相关
    ctypedef int pcg64_random_t

    # 定义结构体 s_pcg64_state,包含 PCG 状态、是否有未使用的 uint32 和 uint32 值
    struct s_pcg64_state:
        pcg64_random_t *pcg_state
        int has_uint32
        uint32_t uinteger

    ctypedef s_pcg64_state pcg64_state

    # 定义 PCG64 的各种操作函数原型
    uint64_t pcg64_next64(pcg64_state *state)  nogil
    uint32_t pcg64_next32(pcg64_state *state)  nogil
    void pcg64_jump(pcg64_state *state)
    void pcg64_advance(pcg64_state *state, uint64_t *step)
    void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc)
    void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, int *has_uint32, uint32_t *uinteger)
    void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, int has_uint32, uint32_t uinteger)

    uint64_t pcg64_cm_next64(pcg64_state *state)  noexcept nogil
    uint32_t pcg64_cm_next32(pcg64_state *state)  noexcept nogil
    void pcg64_cm_advance(pcg64_state *state, uint64_t *step)

# 定义 C 函数用于返回 PCG64 生成的 uint64 随机数,输入为指向 PCG64 状态的指针
cdef uint64_t pcg64_uint64(void* st) noexcept nogil:
    return pcg64_next64(<pcg64_state *>st)

# 定义 C 函数用于返回 PCG64 生成的 uint32 随机数,输入为指向 PCG64 状态的指针
cdef uint32_t pcg64_uint32(void *st) noexcept nogil:
    return pcg64_next32(<pcg64_state *> st)

# 定义 C 函数用于返回 PCG64 生成的 double 类型随机数,输入为指向 PCG64 状态的指针
cdef double pcg64_double(void* st) noexcept nogil:
    return uint64_to_double(pcg64_next64(<pcg64_state *>st))

# 定义 C 函数用于返回 PCG64 生成的 uint64 随机数(另一种变体),输入为指向 PCG64 状态的指针
cdef uint64_t pcg64_cm_uint64(void* st) noexcept nogil:
    return pcg64_cm_next64(<pcg64_state *>st)

# 定义 C 函数用于返回 PCG64 生成的 uint32 随机数(另一种变体),输入为指向 PCG64 状态的指针
cdef uint32_t pcg64_cm_uint32(void *st) noexcept nogil:
    return pcg64_cm_next32(<pcg64_state *> st)

# 定义 C 函数用于返回 PCG64 生成的 double 类型随机数(另一种变体),输入为指向 PCG64 状态的指针
cdef double pcg64_cm_double(void* st) noexcept nogil:
    return uint64_to_double(pcg64_cm_next64(<pcg64_state *>st))

# 定义 PCG64 类,继承自 BitGenerator 类
cdef class PCG64(BitGenerator):
    """
    PCG64(seed=None)

    BitGenerator for the PCG-64 pseudo-random number generator.

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence}, optional
        A seed to initialize the `BitGenerator`. If None, then fresh,
        unpredictable entropy will be pulled from the OS. If an ``int`` or
        ``array_like[ints]`` is passed, then it will be passed to
        `SeedSequence` to derive the initial `BitGenerator` state. One may also
        pass in a `SeedSequence` instance.

    Notes
    -----
    PCG-64 is a 128-bit implementation of O'Neill's permutation congruential
    generator ([1]_, [2]_). PCG-64 has a period of :math:`2^{128}` and supports
    advancing an arbitrary number of steps as well as :math:`2^{127}` streams.
    The specific member of the PCG family that we use is PCG XSL RR 128/64
    as described in the paper ([2]_).

    `PCG64` provides a capsule containing function pointers that produce
    doubles, and unsigned 32 and 64- bit integers. These are not
    directly consumable in Python and must be consumed by a `Generator`
    """
    # 定义 C 语言扩展中使用的 PCG64 RNG 的状态结构
    cdef pcg64_state rng_state
    # 定义 PCG64 随机数生成器对象的结构
    cdef pcg64_random_t pcg64_random_state

    # 初始化方法,可选参数 seed 用于设置随机数种子
    def __init__(self, seed=None):
        # 调用 BitGenerator 的初始化方法,并传递种子参数
        BitGenerator.__init__(self, seed)
        # 将 RNG 状态中的 pcg_state 成员设置为 pcg64_random_state 的地址
        self.rng_state.pcg_state = &self.pcg64_random_state

        # 设置 _bitgen 对象的状态指针为 rng_state 的地址
        self._bitgen.state = <void *>&self.rng_state
        # 设置 _bitgen 对象使用的下一个 uint64 随机数生成函数
        self._bitgen.next_uint64 = &pcg64_uint64
        # 设置 _bitgen 对象使用的下一个 uint32 随机数生成函数
        self._bitgen.next_uint32 = &pcg64_uint32
        # 设置 _bitgen 对象使用的下一个 double 随机数生成函数
        self._bitgen.next_double = &pcg64_double
        # 设置 _bitgen 对象使用的下一个 raw 随机数生成函数
        self._bitgen.next_raw = &pcg64_uint64
        # 使用种子生成状态,并设置给 _bitgen
        val = self._seed_seq.generate_state(4, np.uint64)
        # 调用 C 函数 pcg64_set_seed 来设置 RNG 的种子
        pcg64_set_seed(&self.rng_state,
                       <uint64_t *>np.PyArray_DATA(val),
                       (<uint64_t *>np.PyArray_DATA(val) + 2))
        # 重置状态变量
        self._reset_state_variables()

    # 重置 RNG 的状态变量
    cdef _reset_state_variables(self):
        # 将 RNG 的 has_uint32 状态变量设置为 0
        self.rng_state.has_uint32 = 0
        # 将 RNG 的 uinteger 状态变量设置为 0

    # 在原地进行 RNG 状态的跳跃
    # 注意:不是公共 API 的一部分
    cdef jump_inplace(self, jumps):
        """
        在原地跳跃 RNG 的状态

        参数
        ----------
        jumps : 整数,正数
            要跳跃 RNG 状态的次数。

        注意
        -----
        当乘以 2**128 时,步长为黄金分割率 phi-1。
        """
        # 使用常量步长进行 RNG 的 advance 操作
        step = 0x9e3779b97f4a7c15f39cc0605cedc835
        self.advance(step * int(jumps))
    def jumped(self, jumps=1):
        """
        jumped(jumps=1)

        Returns a new bit generator with the state jumped.

        Jumps the state as-if jumps * 210306068529402873165736369884012333109
        random numbers have been generated.

        Parameters
        ----------
        jumps : integer, positive
            Number of times to jump the state of the bit generator returned

        Returns
        -------
        bit_generator : PCG64
            New instance of generator jumped iter times

        Notes
        -----
        The step size is phi-1 when multiplied by 2**128 where phi is the
        golden ratio.
        """
        # 创建一个新的 PCG64 位生成器对象
        cdef PCG64 bit_generator
        bit_generator = self.__class__()

        # 将当前对象的状态赋给新生成的 bit_generator
        bit_generator.state = self.state

        # 调用 jump_inplace 方法来跳跃状态 jumps 次
        bit_generator.jump_inplace(jumps)

        # 返回新的 bit_generator 对象
        return bit_generator

    @property
    def state(self):
        """
        Get or set the PRNG state

        Returns
        -------
        state : dict
            Dictionary containing the information required to describe the
            state of the PRNG
        """
        # 定义相关变量和数据类型
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger

        # 创建一个长度为 4 的空 np.uint64 类型的数组 state_vec
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)

        # 调用底层函数 pcg64_get_state 获取 PRNG 的状态信息
        pcg64_get_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        &has_uint32, &uinteger)

        # 从 state_vec 数组中提取状态值和增量值
        state = int(state_vec[0]) * 2**64 + int(state_vec[1])
        inc = int(state_vec[2]) * 2**64 + int(state_vec[3])

        # 返回包含 PRNG 状态信息的字典
        return {'bit_generator': self.__class__.__name__,
                'state': {'state': state, 'inc': inc},
                'has_uint32': has_uint32,
                'uinteger': uinteger}

    @state.setter
    def state(self, value):
        # 定义相关变量和数据类型
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger

        # 检查输入的状态是否为字典类型
        if not isinstance(value, dict):
            raise TypeError('state must be a dict')

        # 检查状态字典中的生成器类型是否与当前类匹配
        bitgen = value.get('bit_generator', '')
        if bitgen != self.__class__.__name__:
            raise ValueError('state must be for a {0} '
                             'RNG'.format(self.__class__.__name__))

        # 创建一个长度为 4 的空 np.uint64 类型的数组 state_vec
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)

        # 将状态字典中的状态和增量值分别存入 state_vec 数组的不同位置
        state_vec[0] = value['state']['state'] // 2 ** 64
        state_vec[1] = value['state']['state'] % 2 ** 64
        state_vec[2] = value['state']['inc'] // 2 ** 64
        state_vec[3] = value['state']['inc'] % 2 ** 64

        # 获取状态字典中的 has_uint32 和 uinteger 值
        has_uint32 = value['has_uint32']
        uinteger = value['uinteger']

        # 调用底层函数 pcg64_set_state 设置 PRNG 的状态信息
        pcg64_set_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        has_uint32, uinteger)
    def advance(self, delta):
        """
        advance(delta)

        Advance the underlying RNG as-if delta draws have occurred.

        Parameters
        ----------
        delta : integer, positive
            Number of draws to advance the RNG. Must be less than the
            size state variable in the underlying RNG.

        Returns
        -------
        self : PCG64
            RNG advanced delta steps

        Notes
        -----
        Advancing a RNG updates the underlying RNG state as-if a given
        number of calls to the underlying RNG have been made. In general
        there is not a one-to-one relationship between the number output
        random values from a particular distribution and the number of
        draws from the core RNG.  This occurs for two reasons:

        * The random values are simulated using a rejection-based method
          and so, on average, more than one value from the underlying
          RNG is required to generate an single draw.
        * The number of bits required to generate a simulated value
          differs from the number of bits generated by the underlying
          RNG.  For example, two 16-bit integer values can be simulated
          from a single draw of a 32-bit RNG.

        Advancing the RNG state resets any pre-computed random numbers.
        This is required to ensure exact reproducibility.
        """
        # Ensure delta is wrapped to fit within 128-bit integer size
        delta = wrap_int(delta, 128)

        # Create a numpy array d to hold two 64-bit unsigned integers
        cdef np.ndarray d = np.empty(2, dtype=np.uint64)
        # Split delta into two parts: high and low 64-bit integers
        d[0] = delta // 2**64
        d[1] = delta % 2**64
        # Call C function pcg64_advance with address of rng_state and data in d
        pcg64_advance(&self.rng_state, <uint64_t *>np.PyArray_DATA(d))
        # Reset internal state variables after advancing RNG state
        self._reset_state_variables()
        # Return self to allow method chaining and indicate RNG advanced
        return self
# 定义一个 Cython 类 `PCG64DXSM`,继承自 `BitGenerator` 类
cdef class PCG64DXSM(BitGenerator):
    """
    PCG64DXSM(seed=None)

    BitGenerator for the PCG-64 DXSM pseudo-random number generator.

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence}, optional
        A seed to initialize the `BitGenerator`. If None, then fresh,
        unpredictable entropy will be pulled from the OS. If an ``int`` or
        ``array_like[ints]`` is passed, then it will be passed to
        `SeedSequence` to derive the initial `BitGenerator` state. One may also
        pass in a `SeedSequence` instance.

    Notes
    -----
    PCG-64 DXSM is a 128-bit implementation of O'Neill's permutation congruential
    generator ([1]_, [2]_). PCG-64 DXSM has a period of :math:`2^{128}` and supports
    advancing an arbitrary number of steps as well as :math:`2^{127}` streams.
    The specific member of the PCG family that we use is PCG CM DXSM 128/64. It
    differs from `PCG64` in that it uses the stronger DXSM output function,
    a 64-bit "cheap multiplier" in the LCG, and outputs from the state before
    advancing it rather than advance-then-output.

    `PCG64DXSM` provides a capsule containing function pointers that produce
    doubles, and unsigned 32 and 64- bit integers. These are not
    directly consumable in Python and must be consumed by a `Generator`
    or similar object that supports low-level access.

    Supports the method :meth:`advance` to advance the RNG an arbitrary number of
    steps. The state of the PCG-64 DXSM RNG is represented by 2 128-bit unsigned
    integers.

    **State and Seeding**

    The `PCG64DXSM` state vector consists of 2 unsigned 128-bit values,
    which are represented externally as Python ints. One is the state of the
    PRNG, which is advanced by a linear congruential generator (LCG). The
    second is a fixed odd increment used in the LCG.

    The input seed is processed by `SeedSequence` to generate both values. The
    increment is not independently settable.

    **Parallel Features**

    The preferred way to use a BitGenerator in parallel applications is to use
    the `SeedSequence.spawn` method to obtain entropy values, and to use these
    to generate new BitGenerators:

    >>> from numpy.random import Generator, PCG64DXSM, SeedSequence
    >>> sg = SeedSequence(1234)
    >>> rg = [Generator(PCG64DXSM(s)) for s in sg.spawn(10)]

    **Compatibility Guarantee**

    `PCG64DXSM` makes a guarantee that a fixed seed will always produce
    the same random integer stream.

    References
    ----------
    .. [1] `"PCG, A Family of Better Random Number Generators"
           <http://www.pcg-random.org/>`_
    .. [2] O'Neill, Melissa E. `"PCG: A Family of Simple Fast Space-Efficient
           Statistically Good Algorithms for Random Number Generation"
           <https://www.cs.hmc.edu/tr/hmc-cs-2014-0905.pdf>`_
    """
    # 定义 Cython 结构体变量 rng_state 和 pcg64_random_state
    cdef pcg64_state rng_state
    cdef pcg64_random_t pcg64_random_state
    # 初始化方法,用于创建一个新的随机数生成器对象
    def __init__(self, seed=None):
        # 调用父类 BitGenerator 的初始化方法,传入种子值
        BitGenerator.__init__(self, seed)
        # 设置当前对象的 rng_state.pcg_state 指向 self.pcg64_random_state 的地址
        self.rng_state.pcg_state = &self.pcg64_random_state

        # 将 self._bitgen.state 设置为指向 self.rng_state 的空指针
        self._bitgen.state = <void *>&self.rng_state
        # 设置不同类型的随机数生成函数,如整数、双精度数等
        self._bitgen.next_uint64 = &pcg64_cm_uint64
        self._bitgen.next_uint32 = &pcg64_cm_uint32
        self._bitgen.next_double = &pcg64_cm_double
        self._bitgen.next_raw = &pcg64_cm_uint64
        
        # 使用种子序列生成状态,设置初始种子值
        # 生成一个包含 4 个 np.uint64 类型数据的数组
        val = self._seed_seq.generate_state(4, np.uint64)
        # 调用 pcg64_set_seed 函数,设置随机数生成器状态的种子
        pcg64_set_seed(&self.rng_state,
                       <uint64_t *>np.PyArray_DATA(val),
                       (<uint64_t *>np.PyArray_DATA(val) + 2))
        # 重置对象的状态变量
        self._reset_state_variables()

    # 重置状态变量的私有方法
    cdef _reset_state_variables(self):
        # 将 rng_state.has_uint32 置为 0
        self.rng_state.has_uint32 = 0
        # 将 rng_state.uinteger 置为 0
        self.rng_state.uinteger = 0

    # 跳转状态的私有方法,不是公共 API 的一部分
    cdef jump_inplace(self, jumps):
        """
        Jump state in-place
        Not part of public API

        Parameters
        ----------
        jumps : integer, positive
            Number of times to jump the state of the rng.

        Notes
        -----
        The step size is phi-1 when multiplied by 2**128 where phi is the
        golden ratio.
        """
        # 定义步长为固定的十六进制数
        step = 0x9e3779b97f4a7c15f39cc0605cedc835
        # 调用 advance 方法,以 step * jumps 的步长前进状态
        self.advance(step * int(jumps))

    # 返回经过跳转的新随机数生成器对象
    def jumped(self, jumps=1):
        """
        jumped(jumps=1)

        Returns a new bit generator with the state jumped.

        Jumps the state as-if jumps * 210306068529402873165736369884012333109
        random numbers have been generated.

        Parameters
        ----------
        jumps : integer, positive
            Number of times to jump the state of the bit generator returned

        Returns
        -------
        bit_generator : PCG64DXSM
            New instance of generator jumped iter times

        Notes
        -----
        The step size is phi-1 when multiplied by 2**128 where phi is the
        golden ratio.
        """
        # 声明一个新的 PCG64DXSM 类型的 bit_generator 对象
        cdef PCG64DXSM bit_generator

        # 使用当前类的构造函数创建一个新的 bit_generator 对象
        bit_generator = self.__class__()
        # 将新对象的状态设置为当前对象的状态
        bit_generator.state = self.state
        # 调用 jump_inplace 方法,跳转状态 jumps 次
        bit_generator.jump_inplace(jumps)

        # 返回跳转后的新 bit_generator 对象
        return bit_generator
    def state(self):
        """
        Get or set the PRNG state

        Returns
        -------
        state : dict
            Dictionary containing the information required to describe the
            state of the PRNG
        """
        # 定义 Cython 变量:状态向量和布尔值
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger

        # state_vec 包含 state.high, state.low, inc.high, inc.low 的状态信息
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
        
        # 调用 C 函数 pcg64_get_state 从 RNG 状态中获取信息并存入 state_vec
        pcg64_get_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        &has_uint32, &uinteger)
        
        # 将 state_vec 中的数据解析为整数形式的 state 和 inc
        state = int(state_vec[0]) * 2**64 + int(state_vec[1])
        inc = int(state_vec[2]) * 2**64 + int(state_vec[3])
        
        # 返回描述 PRNG 状态的字典
        return {'bit_generator': self.__class__.__name__,
                'state': {'state': state, 'inc': inc},
                'has_uint32': has_uint32,
                'uinteger': uinteger}

    @state.setter
    def state(self, value):
        # 定义 Cython 变量:状态向量和布尔值
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger
        
        # 检查输入的状态是否为字典类型
        if not isinstance(value, dict):
            raise TypeError('state must be a dict')
        
        # 检查状态字典中的 bit_generator 是否匹配当前 RNG 类型
        bitgen = value.get('bit_generator', '')
        if bitgen != self.__class__.__name__:
            raise ValueError('state must be for a {0} '
                             'RNG'.format(self.__class__.__name__))
        
        # 创建一个空的状态向量数组,用来存储状态信息
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
        
        # 将 state 和 inc 分别存入状态向量数组的前两个和后两个位置
        state_vec[0] = value['state']['state'] // 2 ** 64
        state_vec[1] = value['state']['state'] % 2 ** 64
        state_vec[2] = value['state']['inc'] // 2 ** 64
        state_vec[3] = value['state']['inc'] % 2 ** 64
        
        # 将 has_uint32 和 uinteger 从输入字典中获取并赋值
        has_uint32 = value['has_uint32']
        uinteger = value['uinteger']
        
        # 调用 C 函数 pcg64_set_state 来设置 RNG 的状态
        pcg64_set_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        has_uint32, uinteger)
    def advance(self, delta):
        """
        advance(delta)

        Advance the underlying RNG as-if delta draws have occurred.

        Parameters
        ----------
        delta : integer, positive
            Number of draws to advance the RNG. Must be less than the
            size state variable in the underlying RNG.

        Returns
        -------
        self : PCG64
            RNG advanced delta steps

        Notes
        -----
        Advancing a RNG updates the underlying RNG state as-if a given
        number of calls to the underlying RNG have been made. In general
        there is not a one-to-one relationship between the number output
        random values from a particular distribution and the number of
        draws from the core RNG.  This occurs for two reasons:

        * The random values are simulated using a rejection-based method
          and so, on average, more than one value from the underlying
          RNG is required to generate an single draw.
        * The number of bits required to generate a simulated value
          differs from the number of bits generated by the underlying
          RNG.  For example, two 16-bit integer values can be simulated
          from a single draw of a 32-bit RNG.

        Advancing the RNG state resets any pre-computed random numbers.
        This is required to ensure exact reproducibility.
        """
        # 对输入的 delta 进行处理,确保其在 128 位整数范围内
        delta = wrap_int(delta, 128)

        # 创建一个长度为 2 的无符号 64 位整数数组 d
        cdef np.ndarray d = np.empty(2, dtype=np.uint64)
        # 将 delta 拆分成两部分,存入数组 d 中
        d[0] = delta // 2**64
        d[1] = delta % 2**64
        # 调用 C 函数 pcg64_cm_advance,更新 RNG 状态,传入拆分后的数组 d
        pcg64_cm_advance(&self.rng_state, <uint64_t *>np.PyArray_DATA(d))
        # 重置内部状态变量,以确保精确可复现性
        self._reset_state_variables()
        # 返回当前对象 self,表示 RNG 已经前进了 delta 步
        return self

.\numpy\numpy\random\_philox.pyi

from typing import TypedDict  # 导入 TypedDict 类型提示

from numpy import uint64  # 从 numpy 库中导入 uint64 类型
from numpy.typing import NDArray  # 导入 NDArray 泛型类型
from numpy.random.bit_generator import BitGenerator, SeedSequence  # 从 numpy.random.bit_generator 导入 BitGenerator 和 SeedSequence 类型
from numpy._typing import _ArrayLikeInt_co  # 导入 _ArrayLikeInt_co 私有类型

class _PhiloxInternal(TypedDict):
    counter: NDArray[uint64]  # 定义 _PhiloxInternal 类型的 counter 属性为 uint64 类型的 NDArray
    key: NDArray[uint64]  # 定义 _PhiloxInternal 类型的 key 属性为 uint64 类型的 NDArray

class _PhiloxState(TypedDict):
    bit_generator: str  # 定义 _PhiloxState 类型的 bit_generator 属性为字符串类型
    state: _PhiloxInternal  # 定义 _PhiloxState 类型的 state 属性为 _PhiloxInternal 类型
    buffer: NDArray[uint64]  # 定义 _PhiloxState 类型的 buffer 属性为 uint64 类型的 NDArray
    buffer_pos: int  # 定义 _PhiloxState 类型的 buffer_pos 属性为整数类型
    has_uint32: int  # 定义 _PhiloxState 类型的 has_uint32 属性为整数类型
    uinteger: int  # 定义 _PhiloxState 类型的 uinteger 属性为整数类型

class Philox(BitGenerator):
    def __init__(
        self,
        seed: None | _ArrayLikeInt_co | SeedSequence = ...,  # 构造函数,初始化 seed 参数,可接受 None、_ArrayLikeInt_co 或 SeedSequence 类型,默认为 ...
        counter: None | _ArrayLikeInt_co = ...,  # 构造函数,初始化 counter 参数,可接受 None 或 _ArrayLikeInt_co 类型,默认为 ...
        key: None | _ArrayLikeInt_co = ...,  # 构造函数,初始化 key 参数,可接受 None 或 _ArrayLikeInt_co 类型,默认为 ...
    ) -> None: ...  # 构造函数返回 None,无具体实现

    @property
    def state(  # 定义状态属性 state 的 getter 方法
        self,
    ) -> _PhiloxState: ...  # 返回 _PhiloxState 类型的对象,无具体实现

    @state.setter
    def state(  # 定义状态属性 state 的 setter 方法
        self,
        value: _PhiloxState,  # 接受 _PhiloxState 类型的 value 参数
    ) -> None: ...  # setter 方法返回 None,无具体实现

    def jumped(self, jumps: int = ...) -> Philox: ...  # 定义 jumped 方法,接受整数类型的 jumps 参数,默认为 ...,返回 Philox 类型的对象,无具体实现

    def advance(self, delta: int) -> Philox: ...  # 定义 advance 方法,接受整数类型的 delta 参数,返回 Philox 类型的对象,无具体实现

.\numpy\numpy\random\_philox.pyx

#cython: binding=True
# 导入CPython的PyCapsule_New函数,用于创建Python对象的C扩展对象

from cpython.pycapsule cimport PyCapsule_New
# 导入NumPy库,并在Cython中声明其使用的接口

import numpy as np
cimport numpy as np

# 从C标准库中导入特定类型的整数
from libc.stdint cimport uint32_t, uint64_t

# 导入自定义Cython模块中的函数和类型声明
from ._common cimport uint64_to_double, int_to_array, wrap_int
from numpy.random cimport BitGenerator

# 将Philox类包含在__all__列表中,表示此类为公共接口的一部分
__all__ = ['Philox']

# 导入NumPy C API
np.import_array()

# 定义一个Cython的整数常量PHILOX_BUFFER_SIZE
cdef int PHILOX_BUFFER_SIZE=4

# 从头文件'src/philox/philox.h'中导入结构体和函数声明
cdef extern from 'src/philox/philox.h':
    struct s_r123array2x64:
        uint64_t v[2]

    struct s_r123array4x64:
        uint64_t v[4]

    ctypedef s_r123array4x64 philox4x64_ctr_t
    ctypedef s_r123array2x64 philox4x64_key_t

    struct s_philox_state:
        philox4x64_ctr_t *ctr
        philox4x64_key_t *key
        int buffer_pos
        uint64_t *buffer
        int has_uint32
        uint32_t uinteger

    ctypedef s_philox_state philox_state

    # 导入用于Philox算法的一些函数声明
    uint64_t philox_next64(philox_state *state)  noexcept nogil
    uint32_t philox_next32(philox_state *state)  noexcept nogil
    void philox_jump(philox_state *state)
    void philox_advance(uint64_t *step, philox_state *state)

# 定义C函数philox_uint64,返回64位无符号整数,接受void*类型的参数
cdef uint64_t philox_uint64(void* st) noexcept nogil:
    return philox_next64(<philox_state *> st)

# 定义C函数philox_uint32,返回32位无符号整数,接受void*类型的参数
cdef uint32_t philox_uint32(void *st) noexcept nogil:
    return philox_next32(<philox_state *> st)

# 定义C函数philox_double,返回双精度浮点数,接受void*类型的参数
cdef double philox_double(void* st) noexcept nogil:
    return uint64_to_double(philox_next64(<philox_state *> st))

# 定义Philox类,继承自BitGenerator类,用于实现Philox (4x64) PRNG
cdef class Philox(BitGenerator):
    """
    Philox(seed=None, counter=None, key=None)

    Container for the Philox (4x64) pseudo-random number generator.

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence}, optional
        A seed to initialize the `BitGenerator`. If None, then fresh,
        unpredictable entropy will be pulled from the OS. If an ``int`` or
        ``array_like[ints]`` is passed, then it will be passed to
        `SeedSequence` to derive the initial `BitGenerator` state. One may also
        pass in a `SeedSequence` instance.
    counter : {None, int, array_like}, optional
        Counter to use in the Philox state. Can be either
        a Python int (long in 2.x) in [0, 2**256) or a 4-element uint64 array.
        If not provided, the RNG is initialized at 0.
    key : {None, int, array_like}, optional
        Key to use in the Philox state.  Unlike ``seed``, the value in key is
        directly set. Can be either a Python int in [0, 2**128) or a 2-element
        uint64 array. `key` and ``seed`` cannot both be used.

    Attributes
    ----------
    lock: threading.Lock
        Lock instance that is shared so that the same bit git generator can
        be used in multiple Generators without corrupting the state. Code that
        generates values from a bit generator should hold the bit generator's
        lock.

    Notes
    -----
    Philox is a 64-bit PRNG that uses a counter-based design based on weaker
    (and faster) versions of cryptographic functions [1]_. Instances using
    """
    # 类文档字符串,描述Philox类及其初始化参数和特性
    pass
    # 导入必要的模块和类
    from numpy.random import BitGenerator
    
    # 定义 Philox 类,继承自 BitGenerator 类
    class Philox(BitGenerator):
        """
        Philox is a cryptographic random number generator.
        
        Philox can generate independent sequences by using different keys. It has a 
        period of 2^256 - 1 and supports arbitrary advancing and jumping by 2^128 increments.
    
        Philox provides function pointers for producing doubles, and unsigned 32-bit and 64-bit integers.
        These are not directly usable in Python and require a `Generator` or similar object for access.
    
        State and Seeding:
        - Philox state includes a 256-bit counter as a 4-element uint64 array and a 128-bit key 
          as a 2-element uint64 array.
        - The counter is incremented by 1 for every 4 64-bit randoms produced.
        - Different keys produce independent sequences.
    
        Usage:
        - Seed is processed by `SeedSequence` to generate the key. Counter is set to 0.
        - Alternatively, you can set the key and counter directly.
    
        Parallel Features:
        - Use `SeedSequence.spawn` for parallel applications to obtain entropy values and generate new BitGenerators.
        - `Philox.jumped()` advances state by 2^128 random numbers.
        - `Philox.advance(step)` advances counter by `step` (0 to 2^256-1).
        - Chaining `Philox` instances ensures segments are from the same sequence.
    
        Compatibility Guarantee:
        - Philox guarantees that the same seed will produce the same random stream.
    
        Examples:
        - Generate a random number using Philox:
          >>> from numpy.random import Generator, Philox
          >>> rg = Generator(Philox(1234))
          >>> rg.standard_normal()
    
        References:
        - [Link to references]
        """
        
        # 初始化方法,接受一个 seed 参数,默认为 None
        def __init__(self, seed=None):
            """
            Initialize Philox with a seed.
    
            Parameters
            ----------
            seed : {None, int, array_like}, optional
                Seed for generating random numbers. Default is None.
            """
            # 调用父类的初始化方法
            super().__init__()
            # 如果 seed 为 None,则初始化 key 和 counter 为空数组
            if seed is None:
                self.key = []
                self.counter = []
            else:
                # 否则使用 SeedSequence 处理 seed 生成 key 和设置 counter 为 0
                self.key = SeedSequence(seed).generate_state(2)
                self.counter = [0, 0]
    
        # 生成随机浮点数的方法
        def random(self):
            """Generate random floats."""
            # 返回随机浮点数
            return self._philox()
    
        # 生成随机 32 位无符号整数的方法
        def random_raw(self):
            """Generate random 32-bit unsigned integers."""
            # 返回随机 32 位无符号整数
            return self._philox()
    
        # 生成随机 64 位无符号整数的方法
        def random_raw_long(self):
            """Generate random 64-bit unsigned integers."""
            # 返回随机 64 位无符号整数
            return self._philox()
    
        # 用于调整状态的方法,接受一个步长参数
        def advance(self, step):
            """
            Advance the counter by a specified step.
    
            Parameters
            ----------
            step : int
                Step to advance the counter by.
            """
            # 将 counter[0] 增加 step
            self.counter[0] += step
    
        # 用于跳跃状态的方法
        def jumped(self):
            """Advance the state as if 2^128 random numbers have been generated."""
            # 调用 advance 方法,步长为 2^128
            self.advance(2 ** 128)
            # 返回当前实例
            return self
    
        # 内部方法,用于生成随机数
        def _philox(self):
            """Internal method for generating random numbers."""
            # 返回一个占位符,实际的实现细节未提供
            return NotImplemented
    """
        .. [1] John K. Salmon, Mark A. Moraes, Ron O. Dror, and David E. Shaw,
               "Parallel Random Numbers: As Easy as 1, 2, 3," Proceedings of
               the International Conference for High Performance Computing,
               Networking, Storage and Analysis (SC11), New York, NY: ACM, 2011.
        """
    
        # 定义 Cython 类型变量
        cdef philox_state rng_state
        cdef philox4x64_key_t philox_key
        cdef philox4x64_ctr_t philox_ctr
    
        # 初始化函数,接受种子、计数器和密钥参数
        def __init__(self, seed=None, counter=None, key=None):
            # 如果种子和密钥都不为空,则引发 ValueError 异常
            if seed is not None and key is not None:
                raise ValueError('seed and key cannot be both used')
    
            # 调用 BitGenerator 的初始化方法,传递种子参数
            BitGenerator.__init__(self, seed)
    
            # 将 rng_state 的 ctr 和 key 成员指向对应的 Philox 状态的成员
            self.rng_state.ctr = &self.philox_ctr
            self.rng_state.key = &self.philox_key
    
            # 如果提供了密钥,则将其转换为数组并设置为 rng_state 的 key 成员
            if key is not None:
                key = int_to_array(key, 'key', 128, 64)
                for i in range(2):
                    self.rng_state.key.v[i] = key[i]
                # 设置种子序列为无效状态
                self._seed_seq = None
            else:
                # 否则,使用 _seed_seq 生成长度为 2 的 64 位无符号整数密钥
                key = self._seed_seq.generate_state(2, np.uint64)
                for i in range(2):
                    self.rng_state.key.v[i] = key[i]
    
            # 如果未提供计数器,默认为 0;将其转换为数组并设置为 rng_state 的 ctr 成员
            counter = 0 if counter is None else counter
            counter = int_to_array(counter, 'counter', 256, 64)
            for i in range(4):
                self.rng_state.ctr.v[i] = counter[i]
    
            # 重置状态变量
            self._reset_state_variables()
    
            # 将 _bitgen 的 state 成员指向 rng_state,并设置其余的方法指针
            self._bitgen.state = <void *>&self.rng_state
            self._bitgen.next_uint64 = &philox_uint64
            self._bitgen.next_uint32 = &philox_uint32
            self._bitgen.next_double = &philox_double
            self._bitgen.next_raw = &philox_uint64
    
        # 重置状态变量的私有方法
        cdef _reset_state_variables(self):
            cdef philox_state *rng_state = &self.rng_state
             
            # 初始化 rng_state 的各个成员变量
            rng_state[0].has_uint32 = 0
            rng_state[0].uinteger = 0
            rng_state[0].buffer_pos = PHILOX_BUFFER_SIZE
            for i in range(PHILOX_BUFFER_SIZE):
                rng_state[0].buffer[i] = 0
    
        # 状态属性的 getter 方法,返回 PRNG 的状态信息
        @property
        def state(self):
            """
            Get or set the PRNG state
    
            Returns
            -------
            state : dict
                Dictionary containing the information required to describe the
                state of the PRNG
            """
            # 从 rng_state 中提取 ctr、key 和 buffer 的数据到 numpy 数组中
            ctr = np.empty(4, dtype=np.uint64)
            key = np.empty(2, dtype=np.uint64)
            buffer = np.empty(PHILOX_BUFFER_SIZE, dtype=np.uint64)
            for i in range(4):
                ctr[i] = self.rng_state.ctr.v[i]
                if i < 2:
                    key[i] = self.rng_state.key.v[i]
            for i in range(PHILOX_BUFFER_SIZE):
                buffer[i] = self.rng_state.buffer[i]
    
            # 构建并返回包含 PRNG 状态信息的字典
            state = {'counter': ctr, 'key': key}
            return {'bit_generator': self.__class__.__name__,
                    'state': state,
                    'buffer': buffer,
                    'buffer_pos': self.rng_state.buffer_pos,
                    'has_uint32': self.rng_state.has_uint32,
                    'uinteger': self.rng_state.uinteger}
    
        # 状态属性的 setter 方法
        @state.setter
    def state(self, value):
        # 检查输入值是否为字典类型,如果不是则抛出类型错误异常
        if not isinstance(value, dict):
            raise TypeError('state must be a dict')
        
        # 从输入字典中获取 'bit_generator' 键对应的值
        bitgen = value.get('bit_generator', '')
        
        # 检查获取的 'bit_generator' 值是否与当前类名相同,如果不同则抛出数值错误异常
        if bitgen != self.__class__.__name__:
            raise ValueError('state must be for a {0} PRNG'.format(self.__class__.__name__))
        
        # 将输入字典中的 'state' 字典中的 'counter' 和 'key' 分别复制到 rng_state 对象中
        for i in range(4):
            self.rng_state.ctr.v[i] = <uint64_t> value['state']['counter'][i]
            if i < 2:
                self.rng_state.key.v[i] = <uint64_t> value['state']['key'][i]
        
        # 将输入字典中的 'buffer' 列表复制到 rng_state 对象的 buffer 数组中
        for i in range(PHILOX_BUFFER_SIZE):
            self.rng_state.buffer[i] = <uint64_t> value['buffer'][i]
        
        # 将输入字典中的 'has_uint32', 'uinteger' 和 'buffer_pos' 三个键对应的值分别赋给 rng_state 对象的相应属性
        self.rng_state.has_uint32 = value['has_uint32']
        self.rng_state.uinteger = value['uinteger']
        self.rng_state.buffer_pos = value['buffer_pos']

    cdef jump_inplace(self, iter):
        """
        Jump state in-place

        Not part of public API

        Parameters
        ----------
        iter : integer, positive
            Number of times to jump the state of the rng.
        """
        # 以 (2 ** 128) * iter 的步长向前推进状态
        self.advance(iter * int(2 ** 128))

    def jumped(self, jumps=1):
        """
        jumped(jumps=1)

        Returns a new bit generator with the state jumped

        The state of the returned bit generator is jumped as-if
        (2**128) * jumps random numbers have been generated.

        Parameters
        ----------
        jumps : integer, positive
            Number of times to jump the state of the bit generator returned

        Returns
        -------
        bit_generator : Philox
            New instance of generator jumped iter times
        """
        # 创建一个新的 Philox 实例 bit_generator
        cdef Philox bit_generator
        bit_generator = self.__class__()
        
        # 将当前实例的状态复制到新实例的状态中
        bit_generator.state = self.state
        
        # 调用 jump_inplace 方法,跳跃指定次数的状态
        bit_generator.jump_inplace(jumps)

        # 返回跳跃后的新的 bit_generator 实例
        return bit_generator
    def advance(self, delta):
        """
        advance(delta)

        Advance the underlying RNG as-if delta draws have occurred.

        Parameters
        ----------
        delta : integer, positive
            Number of draws to advance the RNG. Must be less than the
            size state variable in the underlying RNG.

        Returns
        -------
        self : Philox
            RNG advanced delta steps

        Notes
        -----
        Advancing a RNG updates the underlying RNG state as-if a given
        number of calls to the underlying RNG have been made. In general
        there is not a one-to-one relationship between the number output
        random values from a particular distribution and the number of
        draws from the core RNG.  This occurs for two reasons:

        * The random values are simulated using a rejection-based method
          and so, on average, more than one value from the underlying
          RNG is required to generate an single draw.
        * The number of bits required to generate a simulated value
          differs from the number of bits generated by the underlying
          RNG.  For example, two 16-bit integer values can be simulated
          from a single draw of a 32-bit RNG.

        Advancing the RNG state resets any pre-computed random numbers.
        This is required to ensure exact reproducibility.
        """
        # 将 delta 包装为 256 范围内的整数
        delta = wrap_int(delta, 256)

        # 创建一个 numpy 数组 delta_a,将 delta 转换为 'step' 形式的 uint64 数组
        cdef np.ndarray delta_a
        delta_a = int_to_array(delta, 'step', 256, 64)

        # 调用底层函数 philox_advance,更新 RNG 状态
        philox_advance(<uint64_t *> delta_a.data, &self.rng_state)

        # 重置 Philox 对象的状态变量
        self._reset_state_variables()

        # 返回更新后的 Philox 对象自身
        return self

.\numpy\numpy\random\_pickle.py

# 从本地模块中导入不同的随机数生成器类和函数
from .bit_generator import BitGenerator
from .mtrand import RandomState
from ._philox import Philox
from ._pcg64 import PCG64, PCG64DXSM
from ._sfc64 import SFC64

# 定义一个字典,将随机数生成器的名称映射到相应的类
BitGenerators = {'MT19937': MT19937,
                 'PCG64': PCG64,
                 'PCG64DXSM': PCG64DXSM,
                 'Philox': Philox,
                 'SFC64': SFC64,
                 }

def __bit_generator_ctor(bit_generator: str | type[BitGenerator] = 'MT19937'):
    """
    用于反序列化的辅助函数,返回一个随机数生成器对象

    Parameters
    ----------
    bit_generator : type[BitGenerator] or str
        BitGenerator 类或包含 BitGenerator 名称的字符串

    Returns
    -------
    BitGenerator
        BitGenerator 的实例对象
    """
    # 如果 bit_generator 是类对象,则直接使用
    if isinstance(bit_generator, type):
        bit_gen_class = bit_generator
    # 如果 bit_generator 是字符串且存在于 BitGenerators 字典中,则使用对应的类
    elif bit_generator in BitGenerators:
        bit_gen_class = BitGenerators[bit_generator]
    # 否则,抛出 ValueError 异常
    else:
        raise ValueError(
            str(bit_generator) + ' is not a known BitGenerator module.'
        )

    return bit_gen_class()


def __generator_ctor(bit_generator_name="MT19937",
                     bit_generator_ctor=__bit_generator_ctor):
    """
    用于反序列化的辅助函数,返回一个 Generator 对象

    Parameters
    ----------
    bit_generator_name : str or BitGenerator
        包含核心 BitGenerator 名称的字符串或 BitGenerator 实例
    bit_generator_ctor : callable, optional
        接受 bit_generator_name 作为唯一参数并返回初始化的 bit generator 的可调用函数

    Returns
    -------
    rg : Generator
        使用指定核心 BitGenerator 的 Generator
    """
    # 如果 bit_generator_name 是 BitGenerator 的实例,则直接创建 Generator 对象
    if isinstance(bit_generator_name, BitGenerator):
        return Generator(bit_generator_name)
    
    # 使用遗留路径,使用 bit_generator_name 和 bit_generator_ctor 创建 Generator 对象
    return Generator(bit_generator_ctor(bit_generator_name))


def __randomstate_ctor(bit_generator_name="MT19937",
                       bit_generator_ctor=__bit_generator_ctor):
    """
    用于反序列化的辅助函数,返回一个类似于遗留 RandomState 的对象

    Parameters
    ----------
    bit_generator_name : str
        包含核心 BitGenerator 名称的字符串
    bit_generator_ctor : callable, optional
        接受 bit_generator_name 作为唯一参数并返回初始化的 bit generator 的可调用函数

    Returns
    -------
    rs : RandomState
        使用指定核心 BitGenerator 的遗留 RandomState
    """
    # 如果 bit_generator_name 是 BitGenerator 的实例,则直接创建 RandomState 对象
    if isinstance(bit_generator_name, BitGenerator):
        return RandomState(bit_generator_name)
    
    # 使用 bit_generator_name 和 bit_generator_ctor 创建 RandomState 对象
    return RandomState(bit_generator_ctor(bit_generator_name))

.\numpy\numpy\random\_sfc64.pyi

# 引入必要的类型定义
from typing import TypedDict

# 引入必要的数据类型和类
from numpy import uint64
from numpy.random.bit_generator import BitGenerator, SeedSequence
from numpy._typing import NDArray, _ArrayLikeInt_co

# 定义 SFC64 内部状态的字典类型
class _SFC64Internal(TypedDict):
    state: NDArray[uint64]

# 定义 SFC64 状态的字典类型
class _SFC64State(TypedDict):
    bit_generator: str  # 字符串类型的比特生成器名称
    state: _SFC64Internal  # SFC64 内部状态的字典
    has_uint32: int  # 整数,标志是否具有 uint32 数值
    uinteger: int  # 整数,保存 uinteger 值

# SFC64 类继承自 BitGenerator 类
class SFC64(BitGenerator):
    def __init__(self, seed: None | _ArrayLikeInt_co | SeedSequence = ...) -> None: ...
        # 初始化函数,接受种子参数,可以是 None、_ArrayLikeInt_co 类型或 SeedSequence 类型

    @property
    def state(
        self,
    ) -> _SFC64State: ...
        # state 属性的 getter 方法,返回 _SFC64State 类型的对象

    @state.setter
    def state(
        self,
        value: _SFC64State,
    ) -> None: ...
        # state 属性的 setter 方法,接受 _SFC64State 类型的对象作为参数,无返回值

.\numpy\numpy\random\_sfc64.pyx

#cython: binding=True
# 导入所需的库
import numpy as np
# 导入Cython特定的numpy功能
cimport numpy as np

# 从C标准库中导入数据类型定义
from libc.stdint cimport uint32_t, uint64_t
# 导入Cython模块中的函数
from ._common cimport uint64_to_double
# 从numpy中导入BitGenerator类
from numpy.random cimport BitGenerator

# 定义外部C语言头文件中的数据结构和函数接口
__all__ = ['SFC64']

cdef extern from "src/sfc64/sfc64.h":
    # 定义C语言中的结构体s_sfc64_state
    struct s_sfc64_state:
        uint64_t s[4]
        int has_uint32
        uint32_t uinteger

    # 使用Cython类型定义sfc64_state结构体
    ctypedef s_sfc64_state sfc64_state
    # 声明调用C语言函数的原型
    uint64_t sfc64_next64(sfc64_state *state)  nogil
    uint32_t sfc64_next32(sfc64_state *state)  nogil
    void sfc64_set_seed(sfc64_state *state, uint64_t *seed)
    void sfc64_get_state(sfc64_state *state, uint64_t *state_arr, int *has_uint32, uint32_t *uinteger)
    void sfc64_set_state(sfc64_state *state, uint64_t *state_arr, int has_uint32, uint32_t uinteger)

# 定义C语言函数的Cython包装器函数
cdef uint64_t sfc64_uint64(void* st) noexcept nogil:
    return sfc64_next64(<sfc64_state *>st)

cdef uint32_t sfc64_uint32(void *st) noexcept nogil:
    return sfc64_next32(<sfc64_state *> st)

cdef double sfc64_double(void* st) noexcept nogil:
    return uint64_to_double(sfc64_next64(<sfc64_state *>st))


# 定义SFC64类,继承自BitGenerator类
cdef class SFC64(BitGenerator):
    """
    SFC64(seed=None)

    BitGenerator for Chris Doty-Humphrey's Small Fast Chaotic PRNG.

    Parameters
    ----------
    seed : {None, int, array_like[ints], SeedSequence}, optional
        A seed to initialize the `BitGenerator`. If None, then fresh,
        unpredictable entropy will be pulled from the OS. If an ``int`` or
        ``array_like[ints]`` is passed, then it will be passed to
        `SeedSequence` to derive the initial `BitGenerator` state. One may also
        pass in a `SeedSequence` instance.

    Notes
    -----
    `SFC64` is a 256-bit implementation of Chris Doty-Humphrey's Small Fast
    Chaotic PRNG ([1]_). `SFC64` has a few different cycles that one might be
    on, depending on the seed; the expected period will be about
    :math:`2^{255}` ([2]_). `SFC64` incorporates a 64-bit counter which means
    that the absolute minimum cycle length is :math:`2^{64}` and that distinct
    seeds will not run into each other for at least :math:`2^{64}` iterations.

    `SFC64` provides a capsule containing function pointers that produce
    doubles, and unsigned 32 and 64- bit integers. These are not
    directly consumable in Python and must be consumed by a `Generator`
    or similar object that supports low-level access.

    **State and Seeding**

    The `SFC64` state vector consists of 4 unsigned 64-bit values. The last
    is a 64-bit counter that increments by 1 each iteration.

    The input seed is processed by `SeedSequence` to generate the first
    3 values, then the `SFC64` algorithm is iterated a small number of times
    to mix.

    **Compatibility Guarantee**

    `SFC64` makes a guarantee that a fixed seed will always produce the same
    random integer stream.

    References
    ----------
    .. [1] `"PractRand"
            <https://pracrand.sourceforge.net/RNG_engines.txt>`_

    """
    pass
    # 引用和描述
    .. [2] `"Random Invertible Mapping Statistics"
            <https://www.pcg-random.org/posts/random-invertible-mapping-statistics.html>`_
    """

    # 定义 C 扩展类型变量 rng_state,用于存储 SFC64 状态
    cdef sfc64_state rng_state

    # 初始化函数,用于创建 SFC64 PRNG 对象
    def __init__(self, seed=None):
        # 调用 BitGenerator 的初始化函数,传递种子参数
        BitGenerator.__init__(self, seed)
        # 将 RNG 状态绑定到 _bitgen
        self._bitgen.state = <void *>&self.rng_state
        # 设置 _bitgen 的下一个随机数生成函数为 SFC64 的具体实现函数
        self._bitgen.next_uint64 = &sfc64_uint64
        self._bitgen.next_uint32 = &sfc64_uint32
        self._bitgen.next_double = &sfc64_double
        self._bitgen.next_raw = &sfc64_uint64
        # 通过种子序列生成状态向量
        val = self._seed_seq.generate_state(3, np.uint64)
        # 使用生成的状态向量设置 SFC64 RNG 的初始状态
        sfc64_set_seed(&self.rng_state, <uint64_t*>np.PyArray_DATA(val))
        # 重置对象的状态变量
        self._reset_state_variables()

    # 重置对象状态变量的私有方法
    cdef _reset_state_variables(self):
        # 将状态变量标志为无效状态
        self.rng_state.has_uint32 = 0
        # 将整数缓存设置为 0
        self.rng_state.uinteger = 0

    # state 属性的 getter 方法,用于获取 PRNG 的状态
    @property
    def state(self):
        """
        获取或设置 PRNG 的状态

        Returns
        -------
        state : dict
            包含描述 PRNG 状态所需信息的字典
        """
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger

        # 创建一个包含四个 uint64 类型元素的数组作为状态向量
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
        # 获取当前 RNG 状态并存储在 state_vec 中
        sfc64_get_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        &has_uint32, &uinteger)
        # 返回包含 PRNG 状态信息的字典
        return {'bit_generator': self.__class__.__name__,
                'state': {'state': state_vec},
                'has_uint32': has_uint32,
                'uinteger': uinteger}

    # state 属性的 setter 方法,用于设置 PRNG 的状态
    @state.setter
    def state(self, value):
        cdef np.ndarray state_vec
        cdef int has_uint32
        cdef uint32_t uinteger
        # 如果 value 不是字典类型,则抛出类型错误
        if not isinstance(value, dict):
            raise TypeError('state must be a dict')
        # 获取字典中的 bit_generator 键值,检查是否与当前类名匹配
        bitgen = value.get('bit_generator', '')
        if bitgen != self.__class__.__name__:
            raise ValueError('state must be for a {0} '
                             'RNG'.format(self.__class__.__name__))
        # 创建一个包含四个 uint64 类型元素的数组 state_vec,并将状态向量值复制到其中
        state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
        state_vec[:] = value['state']['state']
        # 获取 has_uint32 和 uinteger 值
        has_uint32 = value['has_uint32']
        uinteger = value['uinteger']
        # 使用提供的状态设置 SFC64 RNG 的状态
        sfc64_set_state(&self.rng_state,
                        <uint64_t *>np.PyArray_DATA(state_vec),
                        has_uint32, uinteger)

.\numpy\numpy\random\__init__.pxd

# 导入必要的 Cython 模块和类型定义
cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t

# 从 numpy/random/bitgen.h 头文件中导入 bitgen 结构体定义
cdef extern from "numpy/random/bitgen.h":
    struct bitgen:
        void *state
        uint64_t (*next_uint64)(void *st) nogil
        uint32_t (*next_uint32)(void *st) nogil
        double (*next_double)(void *st) nogil
        uint64_t (*next_raw)(void *st) nogil

    # 定义 bitgen_t 类型作为 bitgen 结构体的别名
    ctypedef bitgen bitgen_t

# 从 numpy.random.bit_generator 模块中导入 BitGenerator 和 SeedSequence 类
from numpy.random.bit_generator cimport BitGenerator, SeedSequence

.\numpy\numpy\random\__init__.py

"""
========================
Random Number Generation
========================

Use ``default_rng()`` to create a `Generator` and call its methods.

=============== =========================================================
Generator
--------------- ---------------------------------------------------------
Generator       实现所有随机数分布的类
default_rng     ``Generator`` 的默认构造函数
=============== =========================================================

============================================= ===
BitGenerator Streams that work with Generator
--------------------------------------------- ---
MT19937
PCG64
PCG64DXSM
Philox
SFC64
============================================= ===

============================================= ===
Getting entropy to initialize a BitGenerator
--------------------------------------------- ---
SeedSequence
============================================= ===


Legacy
------

For backwards compatibility with previous versions of numpy before 1.17, the
various aliases to the global `RandomState` methods are left alone and do not
use the new `Generator` API.

==================== =========================================================
Utility functions
-------------------- ---------------------------------------------------------
random               ``[0, 1)`` 区间上均匀分布的浮点数
bytes                均匀分布的随机字节
permutation          随机排列序列 / 生成随机序列
shuffle              原地随机排列序列
choice               从一维数组中随机抽样
==================== =========================================================

==================== =========================================================
Compatibility
functions - removed
in the new API
-------------------- ---------------------------------------------------------
rand                 均匀分布的随机值
randn                正态分布的随机值
ranf                 均匀分布的浮点数
random_integers      给定范围内均匀分布的整数(已弃用,请使用 ``integers(..., closed=True)``)
random_sample        `random_sample` 的别名
randint              给定范围内均匀分布的整数
seed                 种子以初始化旧版本的随机数生成器
==================== =========================================================

==================== =========================================================
Univariate
distributions
-------------------- ---------------------------------------------------------
beta                 ``[0, 1]`` 区间上的 Beta 分布
binomial             二项分布
chisquare            :math:`\\chi^2` 分布
exponential          指数分布
f                    F 分布(Fisher-Snedecor 分布)
gamma                Gamma 分布
# geometric            几何分布。
# gumbel               甘贝尔分布。
# hypergeometric       超几何分布。
# laplace              拉普拉斯分布。
# logistic             逻辑斯蒂分布。
# lognormal            对数正态分布。
# logseries            对数级数分布。
# negative_binomial    负二项分布。
# noncentral_chisquare 非中心卡方分布。
# noncentral_f         非中心 F 分布。
# normal               正态分布。
# pareto               帕累托分布。
# poisson              泊松分布。
# power                幂分布。
# rayleigh             瑞利分布。
# triangular           三角分布。
# uniform              均匀分布。
# vonmises             冯·米塞斯分布(圆形分布)。
# wald                 瓦尔德分布(反高斯分布)。
# weibull              威布尔分布。
# zipf                 费希尔分布(用于排名数据的分布)。
==================== =========================================================

==================== ==========================================================
Multivariate
distributions
-------------------- ----------------------------------------------------------
# dirichlet            贝塔分布的多元化泛化。
# multinomial          二项分布的多元化泛化。
# multivariate_normal  正态分布的多元化泛化。
==================== ==========================================================

==================== =========================================================
Standard
distributions
-------------------- ---------------------------------------------------------
# standard_cauchy      标准柯西-洛伦兹分布。
# standard_exponential 标准指数分布。
# standard_gamma       标准伽马分布。
# standard_normal      标准正态分布。
# standard_t           标准学生 t 分布。
==================== =========================================================

==================== =========================================================
Internal functions
-------------------- ---------------------------------------------------------
# get_state            获取生成器内部状态的元组表示。
# set_state            设置生成器的状态。
==================== =========================================================
    'randn',                    # 从标准正态分布中抽取随机样本
    'random',                   # 生成一个0到1之间的随机浮点数
    'random_integers',          # 生成一个指定范围内的随机整数
    'random_sample',            # 生成一个指定范围内的随机浮点数
    'ranf',                     # 生成一个0到1之间的随机浮点数
    'rayleigh',                 # 从瑞利分布中抽取随机样本
    'sample',                   # 从指定的序列中随机抽取指定长度的样本
    'seed',                     # 初始化随机数生成器的种子
    'set_state',                # 设置随机数生成器的状态
    'shuffle',                  # 将序列中的元素随机排序
    'standard_cauchy',          # 从标准柯西分布中抽取随机样本
    'standard_exponential',     # 从标准指数分布中抽取随机样本
    'standard_gamma',           # 从标准伽马分布中抽取随机样本
    'standard_normal',          # 从标准正态分布中抽取随机样本
    'standard_t',               # 从标准学生 t 分布中抽取随机样本
    'triangular',               # 从三角分布中抽取随机样本
    'uniform',                  # 从均匀分布中抽取随机样本
    'vonmises',                 # 从冯·米塞斯分布中抽取随机样本
    'wald',                     # 从瓦尔德分布中抽取随机样本
    'weibull',                  # 从威布尔分布中抽取随机样本
    'zipf',                     # 从齐普夫分布中抽取随机样本
# 将以下模块导入用于模块冻结分析(例如 PyInstaller)
from . import _pickle
from . import _common
from . import _bounded_integers

# 导入 Generator 类和 default_rng 函数
from ._generator import Generator, default_rng
# 导入 SeedSequence 类和 BitGenerator 类
from .bit_generator import SeedSequence, BitGenerator
# 导入 MT19937 类
from ._mt19937 import MT19937
# 导入 PCG64 和 PCG64DXSM 类
from ._pcg64 import PCG64, PCG64DXSM
# 导入 Philox 类
from ._philox import Philox
# 导入 SFC64 类
from ._sfc64 import SFC64
# 导入 mtrand 中的所有内容
from .mtrand import *

# 将以下名称添加到 __all__ 列表中,以便在模块被 import * 时可以访问
__all__ += ['Generator', 'RandomState', 'SeedSequence', 'MT19937',
            'Philox', 'PCG64', 'PCG64DXSM', 'SFC64', 'default_rng',
            'BitGenerator']

def __RandomState_ctor():
    """Return a RandomState instance.

    This function exists solely to assist (un)pickling.

    Note that the state of the RandomState returned here is irrelevant, as this
    function's entire purpose is to return a newly allocated RandomState whose
    state pickle can set.  Consequently the RandomState returned by this function
    is a freshly allocated copy with a seed=0.

    See https://github.com/numpy/numpy/issues/4763 for a detailed discussion

    """
    # 返回一个具有种子为 0 的新分配 RandomState 实例
    return RandomState(seed=0)

# 导入 PytestTester 类并将其命名为 test,用于单元测试
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
# 删除 PytestTester,使其不再在模块中可用
del PytestTester

.\numpy\numpy\random\__init__.pyi

# 从 numpy._pytesttester 模块导入 PytestTester 类
from numpy._pytesttester import PytestTester

# 从 numpy.random._generator 模块导入 Generator 类作为 Generator
# 从 numpy.random._generator 模块导入 default_rng 函数作为 default_rng
from numpy.random._generator import Generator as Generator
from numpy.random._generator import default_rng as default_rng

# 从 numpy.random._mt19937 模块导入 MT19937 类作为 MT19937
from numpy.random._mt19937 import MT19937 as MT19937

# 从 numpy.random._pcg64 模块导入 PCG64 类作为 PCG64
# 从 numpy.random._pcg64 模块导入 PCG64DXSM 类作为 PCG64DXSM
from numpy.random._pcg64 import (
    PCG64 as PCG64,
    PCG64DXSM as PCG64DXSM,
)

# 从 numpy.random._philox 模块导入 Philox 类作为 Philox
from numpy.random._philox import Philox as Philox

# 从 numpy.random._sfc64 模块导入 SFC64 类作为 SFC64
from numpy.random._sfc64 import SFC64 as SFC64

# 从 numpy.random.bit_generator 模块导入 BitGenerator 类作为 BitGenerator
from numpy.random.bit_generator import BitGenerator as BitGenerator

# 从 numpy.random.bit_generator 模块导入 SeedSequence 类作为 SeedSequence
from numpy.random.bit_generator import SeedSequence as SeedSequence

# 从 numpy.random.mtrand 模块导入以下内容:
# RandomState 类作为 RandomState
# 各种随机分布函数(例如 beta, binomial, bytes 等)
# 其他的功能函数(例如 get_bit_generator, get_state, set_bit_generator 等)
from numpy.random.mtrand import (
    RandomState as RandomState,
    beta as beta,
    binomial as binomial,
    bytes as bytes,
    chisquare as chisquare,
    choice as choice,
    dirichlet as dirichlet,
    exponential as exponential,
    f as f,
    gamma as gamma,
    geometric as geometric,
    get_bit_generator as get_bit_generator,
    get_state as get_state,
    gumbel as gumbel,
    hypergeometric as hypergeometric,
    laplace as laplace,
    logistic as logistic,
    lognormal as lognormal,
    logseries as logseries,
    multinomial as multinomial,
    multivariate_normal as multivariate_normal,
    negative_binomial as negative_binomial,
    noncentral_chisquare as noncentral_chisquare,
    noncentral_f as noncentral_f,
    normal as normal,
    pareto as pareto,
    permutation as permutation,
    poisson as poisson,
    power as power,
    rand as rand,
    randint as randint,
    randn as randn,
    random as random,
    random_integers as random_integers,
    random_sample as random_sample,
    ranf as ranf,
    rayleigh as rayleigh,
    sample as sample,
    seed as seed,
    set_bit_generator as set_bit_generator,
    set_state as set_state,
    shuffle as shuffle,
    standard_cauchy as standard_cauchy,
    standard_exponential as standard_exponential,
    standard_gamma as standard_gamma,
    standard_normal as standard_normal,
    standard_t as standard_t,
    triangular as triangular,
    uniform as uniform,
    vonmises as vonmises,
    wald as wald,
    weibull as weibull,
    zipf as zipf,
)

# 定义 __all__ 列表,包含所有需要导出的符号名称字符串
__all__: list[str]

# 定义 test 变量,类型为 PytestTester 类的一个实例
test: PytestTester

.\numpy\numpy\rec\__init__.py

# 导入 numpy._core.records 模块中所有公开的变量和函数名
from numpy._core.records import __all__, __doc__
# 导入 numpy._core.records 模块中的所有内容,包括所有变量、函数和类
from numpy._core.records import *

.\numpy\numpy\rec\__init__.pyi

# 导入 numpy._core.records 模块中的特定组件
from numpy._core.records import (
    record as record,              # 导入 record 别名为 record
    recarray as recarray,          # 导入 recarray 别名为 recarray
    format_parser as format_parser,# 导入 format_parser 别名为 format_parser
    fromarrays as fromarrays,      # 导入 fromarrays 别名为 fromarrays
    fromrecords as fromrecords,    # 导入 fromrecords 别名为 fromrecords
    fromstring as fromstring,      # 导入 fromstring 别名为 fromstring
    fromfile as fromfile,          # 导入 fromfile 别名为 fromfile
    array as array                 # 导入 array 别名为 array
)

# 定义 __all__ 变量,指定在使用 from ... import * 时导入的符号列表
__all__: list[str]

# 定义 __path__ 变量,指定模块的搜索路径列表
__path__: list[str]

.\numpy\numpy\strings\__init__.py

# 导入 numpy._core.strings 模块中的 __all__ 和 __doc__ 变量
from numpy._core.strings import __all__, __doc__
# 导入 numpy._core.strings 模块中的所有函数和变量(不推荐通配符导入)
from numpy._core.strings import *

.\numpy\numpy\strings\__init__.pyi

# 导入 numpy._core.strings 模块中的字符串操作函数,并重命名为易于理解的名称
from numpy._core.strings import (
    equal as equal,                     # 导入字符串相等比较函数,并重命名为 equal
    not_equal as not_equal,             # 导入字符串不相等比较函数,并重命名为 not_equal
    greater_equal as greater_equal,     # 导入字符串大于等于比较函数,并重命名为 greater_equal
    less_equal as less_equal,           # 导入字符串小于等于比较函数,并重命名为 less_equal
    greater as greater,                 # 导入字符串大于比较函数,并重命名为 greater
    less as less,                       # 导入字符串小于比较函数,并重命名为 less
    add as add,                         # 导入字符串连接函数,并重命名为 add
    multiply as multiply,               # 导入字符串乘法函数,并重命名为 multiply
    mod as mod,                         # 导入字符串取模函数,并重命名为 mod
    isalpha as isalpha,                 # 导入判断字符串是否只包含字母函数,并重命名为 isalpha
    isalnum as isalnum,                 # 导入判断字符串是否只包含字母和数字函数,并重命名为 isalnum
    isdigit as isdigit,                 # 导入判断字符串是否只包含数字函数,并重命名为 isdigit
    isspace as isspace,                 # 导入判断字符串是否只包含空格函数,并重命名为 isspace
    isnumeric as isnumeric,             # 导入判断字符串是否只包含数字函数,并重命名为 isnumeric
    isdecimal as isdecimal,             # 导入判断字符串是否只包含十进制数字函数,并重命名为 isdecimal
    islower as islower,                 # 导入判断字符串是否全部小写函数,并重命名为 islower
    isupper as isupper,                 # 导入判断字符串是否全部大写函数,并重命名为 isupper
    istitle as istitle,                 # 导入判断字符串是否标题化(每个单词首字母大写)函数,并重命名为 istitle
    str_len as str_len,                 # 导入获取字符串长度函数,并重命名为 str_len
    find as find,                       # 导入在字符串中查找子字符串函数,并重命名为 find
    rfind as rfind,                     # 导入从右侧开始在字符串中查找子字符串函数,并重命名为 rfind
    index as index,                     # 导入返回子字符串第一次出现的索引函数,并重命名为 index
    rindex as rindex,                   # 导入返回子字符串最后一次出现的索引函数,并重命名为 rindex
    count as count,                     # 导入计算子字符串出现次数函数,并重命名为 count
    startswith as startswith,           # 导入判断字符串是否以指定子字符串开头函数,并重命名为 startswith
    endswith as endswith,               # 导入判断字符串是否以指定子字符串结尾函数,并重命名为 endswith
    decode as decode,                   # 导入解码字符串函数,并重命名为 decode
    encode as encode,                   # 导入编码字符串函数,并重命名为 encode
    expandtabs as expandtabs,           # 导入将字符串中的制表符扩展为空格函数,并重命名为 expandtabs
    center as center,                   # 导入使字符串居中对齐函数,并重命名为 center
    ljust as ljust,                     # 导入使字符串左对齐函数,并重命名为 ljust
    rjust as rjust,                     # 导入使字符串右对齐函数,并重命名为 rjust
    lstrip as lstrip,                   # 导入去除字符串左侧空白字符函数,并重命名为 lstrip
    rstrip as rstrip,                   # 导入去除字符串右侧空白字符函数,并重命名为 rstrip
    strip as strip,                     # 导入去除字符串两侧空白字符函数,并重命名为 strip
    zfill as zfill,                     # 导入字符串右侧补零函数,并重命名为 zfill
    upper as upper,                     # 导入将字符串转换为大写函数,并重命名为 upper
    lower as lower,                     # 导入将字符串转换为小写函数,并重命名为 lower
    swapcase as swapcase,               # 导入交换字符串大小写函数,并重命名为 swapcase
    capitalize as capitalize,           # 导入将字符串首字母大写函数,并重命名为 capitalize
    title as title,                     # 导入将字符串标题化函数,并重命名为 title
    replace as replace,                 # 导入替换字符串中子字符串函数,并重命名为 replace
    join as join,                       # 导入连接可迭代对象中的字符串函数,并重命名为 join
    split as split,                     # 导入按指定分隔符拆分字符串函数,并重命名为 split
    rsplit as rsplit,                   # 导入从右侧开始按指定分隔符拆分字符串函数,并重命名为 rsplit
    splitlines as splitlines,           # 导入按行拆分字符串函数,并重命名为 splitlines
    partition as partition,             # 导入将字符串分割为三部分函数,并重命名为 partition
    rpartition as rpartition,           # 导入将字符串从右侧开始分割为三部分函数,并重命名为 rpartition
    translate as translate              # 导入根据指定映射替换字符串中的字符函数,并重命名为 translate
)

__all__: list[str]                      # 定义 __all__ 变量,指定在使用 from module import * 时导入的符号列表为 str 类型

.\numpy\numpy\testing\overrides.py

# 导入测试 `__array_function__` 和 ufunc 重写实现的工具

from numpy._core.overrides import ARRAY_FUNCTIONS as _array_functions
# 导入 numpy 库中的 ufunc 别名 `_ufunc`
from numpy import ufunc as _ufunc
# 导入 numpy 库中的 umath 模块别名 `_umath`
import numpy._core.umath as _umath

def get_overridable_numpy_ufuncs():
    """列出所有可以通过 `__array_ufunc__` 被重写的 numpy ufunc 函数

    Parameters
    ----------
    None

    Returns
    -------
    set
        包含所有可以在公共 numpy API 中通过 `__array_ufunc__` 被重写的 ufunc 集合。
    """
    # 从 `_umath.__dict__.values()` 中选择所有的 ufunc 对象,并存入集合 `ufuncs`
    ufuncs = {obj for obj in _umath.__dict__.values()
              if isinstance(obj, _ufunc)}
    return ufuncs

def allows_array_ufunc_override(func):
    """确定一个函数是否可以通过 `__array_ufunc__` 被重写

    Parameters
    ----------
    func : callable
        可能可以通过 `__array_ufunc__` 被重写的函数

    Returns
    -------
    bool
        如果 `func` 可以通过 `__array_ufunc__` 被重写则返回 `True`,否则返回 `False`。

    Notes
    -----
    该函数等价于 ``isinstance(func, np.ufunc)`` 并且对于在 Numpy 之外定义的 ufuncs 也能正确工作。
    """
    return isinstance(func, np.ufunc)

def get_overridable_numpy_array_functions():
    """列出所有可以通过 `__array_function__` 被重写的 numpy 函数

    Parameters
    ----------
    None

    Returns
    -------
    set
        包含所有可以在公共 numpy API 中通过 `__array_function__` 被重写的函数集合。

    """
    # 'import numpy' 并没有导入 `recfunctions`,因此确保它被导入,这样定义在那里的 ufunc 才会出现在 ufunc 列表中
    from numpy.lib import recfunctions
    return _array_functions.copy()

def allows_array_function_override(func):
    """确定一个 Numpy 函数是否可以通过 `__array_function__` 被重写

    Parameters
    ----------
    func : callable
        可能可以通过 `__array_function__` 被重写的函数

    Returns
    -------
    bool
        如果 `func` 是可以在 Numpy API 中通过 `__array_function__` 被重写的函数则返回 `True`,否则返回 `False`。
    """
    return func in _array_functions

.\numpy\numpy\testing\print_coercion_tables.py

# 指定 Python 解释器为当前环境的 Python 3
#!/usr/bin/env python3
"""Prints type-coercion tables for the built-in NumPy types

"""
# 导入 NumPy 库并简写为 np
import numpy as np
# 从 NumPy 库中导入 obj2sctype 函数
from numpy._core.numerictypes import obj2sctype
# 导入 namedtuple 类
from collections import namedtuple

# 定义一个通用对象,可以进行加法操作但不做其他操作
class GenericObject:
    def __init__(self, v):
        self.v = v

    def __add__(self, other):
        return self

    def __radd__(self, other):
        return self

    # 设置 dtype 属性为对象类型 'O'
    dtype = np.dtype('O')

# 定义函数 print_cancast_table,打印 NumPy 类型间的类型转换表
def print_cancast_table(ntypes):
    # 打印表头,显示类型字符
    print('X', end=' ')
    for char in ntypes:
        print(char, end=' ')
    print()
    # 打印每行类型及其与其他类型间的转换关系
    for row in ntypes:
        print(row, end=' ')
        for col in ntypes:
            # 根据 np.can_cast 函数返回值选择合适的标记符号
            if np.can_cast(row, col, "equiv"):
                cast = "#"
            elif np.can_cast(row, col, "safe"):
                cast = "="
            elif np.can_cast(row, col, "same_kind"):
                cast = "~"
            elif np.can_cast(row, col, "unsafe"):
                cast = "."
            else:
                cast = " "
            print(cast, end=' ')
        print()

# 定义函数 print_coercion_table,打印 NumPy 类型间的类型强制转换表
def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, use_promote_types=False):
    # 打印表头,显示类型字符
    print('+', end=' ')
    for char in ntypes:
        print(char, end=' ')
    print()
    # 打印每行类型及其与其他类型间的强制转换关系
    for row in ntypes:
        if row == 'O':
            rowtype = GenericObject
        else:
            rowtype = obj2sctype(row)

        print(row, end=' ')
        for col in ntypes:
            if col == 'O':
                coltype = GenericObject
            else:
                coltype = obj2sctype(col)
            try:
                # 根据输入值创建 NumPy 数组或对象,计算强制转换结果
                if firstarray:
                    rowvalue = np.array([rowtype(inputfirstvalue)], dtype=rowtype)
                else:
                    rowvalue = rowtype(inputfirstvalue)
                colvalue = coltype(inputsecondvalue)
                if use_promote_types:
                    char = np.promote_types(rowvalue.dtype, colvalue.dtype).char
                else:
                    value = np.add(rowvalue, colvalue)
                    if isinstance(value, np.ndarray):
                        char = value.dtype.char
                    else:
                        char = np.dtype(type(value)).char
            except ValueError:
                char = '!'
            except OverflowError:
                char = '@'
            except TypeError:
                char = '#'
            print(char, end=' ')
        print()

# 定义函数 print_new_cast_table,打印新的类型转换表
def print_new_cast_table(*, can_cast=True, legacy=False, flags=False):
    """Prints new casts, the values given are default "can-cast" values, not
    actual ones.
    """
    # 导入私有模块函数 get_all_cast_information
    from numpy._core._multiarray_tests import get_all_cast_information

    # 设置新的类型转换标志
    cast_table = {
        -1: " ",
        0: "#",  # No cast (classify as equivalent here)
        1: "#",  # equivalent casting
        2: "=",  # safe casting
        3: "~",  # same-kind casting
        4: ".",  # unsafe casting
    }
    # 定义一个字典,将整数映射到对应的特定字符表示
    flags_table = {
        0 : "▗", 7: "█",
        1: "▚", 2: "▐", 4: "▄",
                3: "▜", 5: "▙",
                        6: "▟",
    }

    # 创建一个命名元组类型cast_info,包含can_cast、legacy、flags三个字段
    cast_info = namedtuple("cast_info", ["can_cast", "legacy", "flags"])
    # 定义一个用于表示没有转换信息的特殊命名元组实例
    no_cast_info = cast_info(" ", " ", " ")

    # 获取所有转换信息的列表
    casts = get_all_cast_information()
    # 创建一个空字典用于存储转换信息的表格
    table = {}
    # 创建一个空集合,用于收集所有出现过的数据类型
    dtypes = set()
    
    # 遍历每个转换信息
    for cast in casts:
        # 将转换源和目标数据类型添加到数据类型集合中
        dtypes.add(cast["from"])
        dtypes.add(cast["to"])

        # 如果转换源数据类型尚未在表格中,则创建一个空字典用于存储转换目标和转换信息
        if cast["from"] not in table:
            table[cast["from"]] = {}
        to_dict = table[cast["from"]]

        # 根据转换信息设置can_cast、legacy和flags字段
        can_cast = cast_table[cast["casting"]]
        legacy = "L" if cast["legacy"] else "."
        flags = 0
        if cast["requires_pyapi"]:
            flags |= 1
        if cast["supports_unaligned"]:
            flags |= 2
        if cast["no_floatingpoint_errors"]:
            flags |= 4

        # 将整数表示的flags映射为对应的字符
        flags = flags_table[flags]
        # 将转换目标和对应的cast_info存入表格中
        to_dict[cast["to"]] = cast_info(can_cast=can_cast, legacy=legacy, flags=flags)

    # 下面开始处理数据类型排序的函数和打印表格的函数
    # 注释以下函数
    types = np.typecodes["All"]
    def sorter(x):
        dtype = np.dtype(x.type)
        try:
            indx = types.index(dtype.char)
        except ValueError:
            indx = np.inf
        return (indx, dtype.char)

    # 对数据类型集合进行排序,使用sorter函数进行排序依据
    dtypes = sorted(dtypes, key=sorter)

    # 定义一个打印表格的函数,field参数指定打印哪个字段的信息
    def print_table(field="can_cast"):
        print('X', end=' ')
        for dt in dtypes:
            print(np.dtype(dt.type).char, end=' ')
        print()
        for from_dt in dtypes:
            print(np.dtype(from_dt.type).char, end=' ')
            row = table.get(from_dt, {})
            for to_dt in dtypes:
                print(getattr(row.get(to_dt, no_cast_info), field), end=' ')
            print()

    # 判断是否存在can_cast,如果存在则打印can_cast表格
    if can_cast:
        print()
        print("Casting: # is equivalent, = is safe, ~ is same-kind, and . is unsafe")
        print()
        print_table("can_cast")

    # 判断是否存在legacy,如果存在则打印legacy表格
    if legacy:
        print()
        print("L denotes a legacy cast . a non-legacy one.")
        print()
        print_table("legacy")

    # 判断是否存在flags,如果存在则打印flags相关信息和对应的表格
    if flags:
        print()
        print(f"{flags_table[0]}: no flags, {flags_table[1]}: PyAPI, "
              f"{flags_table[2]}: supports unaligned, {flags_table[4]}: no-float-errors")
        print()
        print_table("flags")
# 如果当前脚本作为主程序运行,则执行以下代码块
if __name__ == '__main__':
    # 打印提示信息:"can cast"
    print("can cast")
    # 调用函数 print_cancast_table,打印 numpy 所有数据类型的转换表格
    print_cancast_table(np.typecodes['All'])
    # 打印空行
    print()
    # 打印提示信息:"In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'"
    print("In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'")
    # 打印空行
    print()
    # 打印提示信息:"scalar + scalar"
    print("scalar + scalar")
    # 调用函数 print_coercion_table,打印将 numpy 所有数据类型与自身相加时的转换表格
    print_coercion_table(np.typecodes['All'], 0, 0, False)
    # 打印空行
    print()
    # 打印提示信息:"scalar + neg scalar"
    print("scalar + neg scalar")
    # 调用函数 print_coercion_table,打印将 numpy 所有数据类型与负数自身相加时的转换表格
    print_coercion_table(np.typecodes['All'], 0, -1, False)
    # 打印空行
    print()
    # 打印提示信息:"array + scalar"
    print("array + scalar")
    # 调用函数 print_coercion_table,打印将 numpy 所有数据类型与数组相加时的转换表格
    print_coercion_table(np.typecodes['All'], 0, 0, True)
    # 打印空行
    print()
    # 打印提示信息:"array + neg scalar"
    print("array + neg scalar")
    # 调用函数 print_coercion_table,打印将 numpy 所有数据类型与负数数组相加时的转换表格
    print_coercion_table(np.typecodes['All'], 0, -1, True)
    # 打印空行
    print()
    # 打印提示信息:"promote_types"
    print("promote_types")
    # 调用函数 print_coercion_table,打印 numpy 所有数据类型的提升表格
    print_coercion_table(np.typecodes['All'], 0, 0, False, True)
    # 打印提示信息:"New casting type promotion:"
    print("New casting type promotion:")
    # 调用函数 print_new_cast_table,打印新的类型转换提升表格
    print_new_cast_table(can_cast=True, legacy=True, flags=True)

.\numpy\numpy\testing\tests\test_utils.py

import warnings
import sys
import os
import itertools
import pytest
import weakref
import re

import numpy as np
import numpy._core._multiarray_umath as ncu
from numpy.testing import (
    assert_equal, assert_array_equal, assert_almost_equal,
    assert_array_almost_equal, assert_array_less, build_err_msg,
    assert_raises, assert_warns, assert_no_warnings, assert_allclose,
    assert_approx_equal, assert_array_almost_equal_nulp, assert_array_max_ulp,
    clear_and_catch_warnings, suppress_warnings, assert_string_equal, assert_,
    tempdir, temppath, assert_no_gc_cycles, HAS_REFCOUNT
)

# 定义一个名为 _GenericTest 的基类,用于测试数组相等性
class _GenericTest:

    # 辅助方法,测试两个对象是否相等
    def _test_equal(self, a, b):
        self._assert_func(a, b)

    # 辅助方法,测试两个对象是否不相等
    def _test_not_equal(self, a, b):
        with assert_raises(AssertionError):
            self._assert_func(a, b)

    # 测试两个 rank 1 数组是否相等
    def test_array_rank1_eq(self):
        """Test two equal array of rank 1 are found equal."""
        a = np.array([1, 2])
        b = np.array([1, 2])

        self._test_equal(a, b)

    # 测试两个不同的 rank 1 数组是否不相等
    def test_array_rank1_noteq(self):
        """Test two different array of rank 1 are found not equal."""
        a = np.array([1, 2])
        b = np.array([2, 2])

        self._test_not_equal(a, b)

    # 测试两个 rank 2 数组是否相等
    def test_array_rank2_eq(self):
        """Test two equal array of rank 2 are found equal."""
        a = np.array([[1, 2], [3, 4]])
        b = np.array([[1, 2], [3, 4]])

        self._test_equal(a, b)

    # 测试两个形状不同的数组是否不相等
    def test_array_diffshape(self):
        """Test two arrays with different shapes are found not equal."""
        a = np.array([1, 2])
        b = np.array([[1, 2], [1, 2]])

        self._test_not_equal(a, b)

    # 测试对象数组是否正确处理
    def test_objarray(self):
        """Test object arrays."""
        a = np.array([1, 1], dtype=object)
        self._test_equal(a, 1)

    # 测试类似数组的情况
    def test_array_likes(self):
        self._test_equal([1, 2, 3], (1, 2, 3))


# 定义一个测试类 TestArrayEqual,继承自 _GenericTest
class TestArrayEqual(_GenericTest):

    # 在每个测试方法执行前设置 assert_func 属性为 assert_array_equal
    def setup_method(self):
        self._assert_func = assert_array_equal

    # 测试不同类型的 rank 1 数组是否相等
    def test_generic_rank1(self):
        """Test rank 1 array for all dtypes."""
        def foo(t):
            # 创建一个指定类型 t 的空数组,填充为 1
            a = np.empty(2, t)
            a.fill(1)
            # 复制数组 a 到 b 和 c
            b = a.copy()
            c = a.copy()
            # 数组 c 填充为 0
            c.fill(0)
            # 测试 a 和 b 是否相等
            self._test_equal(a, b)
            # 测试 c 和 b 是否不相等
            self._test_not_equal(c, b)

        # 测试数值类型和对象类型
        for t in '?bhilqpBHILQPfdgFDG':
            foo(t)

        # 测试字符串类型
        for t in ['S1', 'U1']:
            foo(t)
    def test_0_ndim_array(self):
        # 创建包含一个大整数的 NumPy 数组 x
        x = np.array(473963742225900817127911193656584771)
        # 创建包含一个较小整数的 NumPy 数组 y
        y = np.array(18535119325151578301457182298393896)

        # 使用 pytest 检查是否会抛出 AssertionError 异常
        with pytest.raises(AssertionError) as exc_info:
            # 调用 self._assert_func 进行断言
            self._assert_func(x, y)
        # 获取异常信息的字符串表示
        msg = str(exc_info.value)
        # 断言异常信息中包含特定的字符串
        assert_('Mismatched elements: 1 / 1 (100%)\n'
                in msg)

        # 将 y 赋值为 x,以便进行下一次断言
        y = x
        # 调用 self._assert_func 进行断言
        self._assert_func(x, y)

        # 创建包含一个浮点数的 NumPy 数组 x
        x = np.array(4395065348745.5643764887869876)
        # 创建包含整数 0 的 NumPy 数组 y
        y = np.array(0)
        # 预期的异常消息,包含详细的差异信息
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: '
                        '4.39506535e+12\n'
                        'Max relative difference among violations: inf\n')
        # 使用 pytest 检查是否会抛出 AssertionError 异常,并匹配预期的异常消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            # 调用 self._assert_func 进行断言
            self._assert_func(x, y)

        # 将 x 赋值为 y,以便进行下一次断言
        x = y
        # 调用 self._assert_func 进行断言
        self._assert_func(x, y)

    def test_generic_rank3(self):
        """Test rank 3 array for all dtypes."""
        def foo(t):
            # 创建一个空的 NumPy 数组 a,形状为 (4, 2, 3),数据类型为 t,并填充为 1
            a = np.empty((4, 2, 3), t)
            a.fill(1)
            # 创建数组 b,复制自数组 a
            b = a.copy()
            # 创建数组 c,复制自数组 a,并填充为 0
            c = a.copy()
            c.fill(0)
            # 调用 self._test_equal 检查数组 a 和 b 是否相等
            self._test_equal(a, b)
            # 调用 self._test_not_equal 检查数组 c 和 b 是否不相等

        # 测试所有数字类型和对象类型
        for t in '?bhilqpBHILQPfdgFDG':
            foo(t)

        # 测试字符串类型
        for t in ['S1', 'U1']:
            foo(t)

    def test_nan_array(self):
        """Test arrays with nan values in them."""
        # 创建包含 NaN 值的 NumPy 数组 a
        a = np.array([1, 2, np.nan])
        # 创建包含 NaN 值的 NumPy 数组 b,与 a 相同
        b = np.array([1, 2, np.nan])

        # 调用 self._test_equal 检查数组 a 和 b 是否相等
        self._test_equal(a, b)

        # 创建不包含 NaN 值的 NumPy 数组 c
        c = np.array([1, 2, 3])
        # 调用 self._test_not_equal 检查数组 c 和 b 是否不相等
        self._test_not_equal(c, b)

    def test_string_arrays(self):
        """Test two arrays with different shapes are found not equal."""
        # 创建字符串数组 a
        a = np.array(['floupi', 'floupa'])
        # 创建字符串数组 b,与 a 相同
        b = np.array(['floupi', 'floupa'])

        # 调用 self._test_equal 检查数组 a 和 b 是否相等

        # 创建具有不同形状的字符串数组 c
        c = np.array(['floupipi', 'floupa'])
        # 调用 self._test_not_equal 检查数组 c 和 b 是否不相等

    def test_recarrays(self):
        """Test record arrays."""
        # 创建一个空的记录数组 a,包含两个字段 'floupi' 和 'floupa'
        a = np.empty(2, [('floupi', float), ('floupa', float)])
        a['floupi'] = [1, 2]
        a['floupa'] = [1, 2]
        # 复制记录数组 a 到数组 b
        b = a.copy()

        # 调用 self._test_equal 检查数组 a 和 b 是否相等

        # 创建一个空的记录数组 c,包含三个字段 'floupipi'、'floupi' 和 'floupa'
        c = np.empty(2, [('floupipi', float),
                         ('floupi', float), ('floupa', float)])
        c['floupipi'] = a['floupi'].copy()
        c['floupa'] = a['floupa'].copy()
        # 使用 pytest 检查是否会抛出 TypeError 异常
        with pytest.raises(TypeError):
            # 调用 self._test_not_equal 检查数组 c 和 b 是否不相等

    def test_masked_nan_inf(self):
        # Regression test for gh-11121
        # 创建包含掩码和 NaN 值的掩码数组 a
        a = np.ma.MaskedArray([3., 4., 6.5], mask=[False, True, False])
        # 创建包含 NaN 值的 NumPy 数组 b
        b = np.array([3., np.nan, 6.5])
        # 调用 self._test_equal 检查数组 a 和 b 是否相等
        self._test_equal(a, b)
        # 调用 self._test_equal 检查数组 b 和 a 是否相等
        self._test_equal(b, a)

        # 创建包含掩码和无穷大值的掩码数组 a
        a = np.ma.MaskedArray([3., 4., 6.5], mask=[True, False, False])
        # 创建包含无穷大值的 NumPy 数组 b
        b = np.array([np.inf, 4., 6.5])
        # 调用 self._test_equal 检查数组 a 和 b 是否相等
        self._test_equal(a, b)
        # 调用 self._test_equal 检查数组 b 和 a 是否相等
        self._test_equal(b, a)
    def test_subclass_that_overrides_eq(self):
        # 定义一个测试子类,覆盖了 __eq__ 方法来自定义相等比较行为
        # 这种子类不依赖于能够存储布尔值(例如 astropy Quantity 无法有效使用布尔值)
        # 参见 GitHub 问题 gh-8452。
        class MyArray(np.ndarray):
            def __eq__(self, other):
                return bool(np.equal(self, other).all())

            def __ne__(self, other):
                return not self == other

        # 创建两个 MyArray 的实例
        a = np.array([1., 2.]).view(MyArray)
        b = np.array([2., 3.]).view(MyArray)

        # 断言 a == a 的返回类型是布尔值
        assert_(type(a == a), bool)
        # 断言 a 等于自己
        assert_(a == a)
        # 断言 a 不等于 b
        assert_(a != b)

        # 调用测试函数,测试相等性
        self._test_equal(a, a)
        # 调用测试函数,测试不相等性
        self._test_not_equal(a, b)
        # 调用测试函数,测试不相等性(反向)
        self._test_not_equal(b, a)

        # 准备预期的错误消息
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 1.\n'
                        'Max relative difference among violations: 0.5')
        # 使用 pytest 检查是否会抛出 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._test_equal(a, b)

        # 创建另一个 MyArray 的实例 c
        c = np.array([0., 2.9]).view(MyArray)
        # 准备另一个预期的错误消息
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 2.\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 检查是否会抛出 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._test_equal(b, c)

    def test_subclass_that_does_not_implement_npall(self):
        # 定义一个不实现 np.all 方法的测试子类
        class MyArray(np.ndarray):
            def __array_function__(self, *args, **kwargs):
                return NotImplemented

        # 创建两个 MyArray 的实例
        a = np.array([1., 2.]).view(MyArray)
        b = np.array([2., 3.]).view(MyArray)

        # 使用 assert_raises 检查是否会抛出 TypeError
        with assert_raises(TypeError):
            np.all(a)

        # 调用测试函数,测试相等性
        self._test_equal(a, a)
        # 调用测试函数,测试不相等性
        self._test_not_equal(a, b)
        # 调用测试函数,测试不相等性(反向)
        self._test_not_equal(b, a)

    def test_suppress_overflow_warnings(self):
        # 基于问题 #18992 进行测试,验证是否会抑制溢出警告
        with pytest.raises(AssertionError):
            with np.errstate(all="raise"):
                np.testing.assert_array_equal(
                    np.array([1, 2, 3], np.float32),
                    np.array([1, 1e-40, 3], np.float32))

    def test_array_vs_scalar_is_equal(self):
        """测试当所有值相等时,比较数组和标量的相等性。"""
        # 创建数组 a 和标量 b
        a = np.array([1., 1., 1.])
        b = 1.

        # 调用测试函数,测试相等性
        self._test_equal(a, b)
    def test_array_vs_array_not_equal(self):
        """Test comparing an array with a scalar when not all values equal."""
        # 创建一个包含整数的 NumPy 数组
        a = np.array([34986, 545676, 439655, 563766])
        # 创建另一个包含整数和一个零的 NumPy 数组
        b = np.array([34986, 545676, 439655, 0])

        # 预期的错误信息,描述了不匹配元素的数量和最大差异
        expected_msg = ('Mismatched elements: 1 / 4 (25%)\n'
                        'Max absolute difference among violations: 563766\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 来验证预期的 AssertionError,并匹配指定的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b)

        # 创建一个包含浮点数和一个整数的 NumPy 数组
        a = np.array([34986, 545676, 439655.2, 563766])
        # 更新预期的错误信息,描述了不匹配元素的数量和最大差异
        expected_msg = ('Mismatched elements: 2 / 4 (50%)\n'
                        'Max absolute difference among violations: '
                        '563766.\n'
                        'Max relative difference among violations: '
                        '4.54902139e-07')
        # 使用 pytest 来验证预期的 AssertionError,并匹配指定的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b)

    def test_array_vs_scalar_strict(self):
        """Test comparing an array with a scalar with strict option."""
        # 创建一个包含浮点数的 NumPy 数组
        a = np.array([1., 1., 1.])
        # 创建一个浮点数标量
        b = 1.

        # 使用 pytest 来验证预期的 AssertionError
        with pytest.raises(AssertionError):
            self._assert_func(a, b, strict=True)

    def test_array_vs_array_strict(self):
        """Test comparing two arrays with strict option."""
        # 创建两个相同的包含浮点数的 NumPy 数组
        a = np.array([1., 1., 1.])
        b = np.array([1., 1., 1.])

        # 调用 _assert_func 函数来比较这两个数组,使用 strict=True 选项
        self._assert_func(a, b, strict=True)

    def test_array_vs_float_array_strict(self):
        """Test comparing two arrays with strict option."""
        # 创建一个包含整数的 NumPy 数组
        a = np.array([1, 1, 1])
        # 创建一个包含浮点数的 NumPy 数组
        b = np.array([1., 1., 1.])

        # 使用 pytest 来验证预期的 AssertionError
        with pytest.raises(AssertionError):
            self._assert_func(a, b, strict=True)
class TestBuildErrorMessage:

    def test_build_err_msg_defaults(self):
        # 创建两个 NumPy 数组作为比较的输入数据
        x = np.array([1.00001, 2.00002, 3.00003])
        y = np.array([1.00002, 2.00003, 3.00004])
        # 错误消息字符串
        err_msg = 'There is a mismatch'

        # 调用 build_err_msg 函数生成错误消息,包含详细信息
        a = build_err_msg([x, y], err_msg)
        # 期望的错误消息,包含详细的比较结果
        b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array(['
             '1.00001, 2.00002, 3.00003])\n DESIRED: array([1.00002, '
             '2.00003, 3.00004])')
        # 使用 assert_equal 断言 a 和 b 相等
        assert_equal(a, b)

    def test_build_err_msg_no_verbose(self):
        # 创建两个 NumPy 数组作为比较的输入数据
        x = np.array([1.00001, 2.00002, 3.00003])
        y = np.array([1.00002, 2.00003, 3.00004])
        # 错误消息字符串
        err_msg = 'There is a mismatch'

        # 调用 build_err_msg 函数生成简单错误消息,不包含详细信息
        a = build_err_msg([x, y], err_msg, verbose=False)
        # 期望的简单错误消息
        b = '\nItems are not equal: There is a mismatch'
        # 使用 assert_equal 断言 a 和 b 相等
        assert_equal(a, b)

    def test_build_err_msg_custom_names(self):
        # 创建两个 NumPy 数组作为比较的输入数据
        x = np.array([1.00001, 2.00002, 3.00003])
        y = np.array([1.00002, 2.00003, 3.00004])
        # 错误消息字符串
        err_msg = 'There is a mismatch'

        # 调用 build_err_msg 函数生成带有自定义命名的错误消息
        a = build_err_msg([x, y], err_msg, names=('FOO', 'BAR'))
        # 期望的带有自定义命名的错误消息,包含详细的比较结果
        b = ('\nItems are not equal: There is a mismatch\n FOO: array(['
             '1.00001, 2.00002, 3.00003])\n BAR: array([1.00002, 2.00003, '
             '3.00004])')
        # 使用 assert_equal 断言 a 和 b 相等
        assert_equal(a, b)

    def test_build_err_msg_custom_precision(self):
        # 创建两个 NumPy 数组作为比较的输入数据,其中一个有更高的精度
        x = np.array([1.000000001, 2.00002, 3.00003])
        y = np.array([1.000000002, 2.00003, 3.00004])
        # 错误消息字符串
        err_msg = 'There is a mismatch'

        # 调用 build_err_msg 函数生成带有自定义精度的错误消息
        a = build_err_msg([x, y], err_msg, precision=10)
        # 期望的带有自定义精度的错误消息,包含详细的比较结果
        b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array(['
             '1.000000001, 2.00002    , 3.00003    ])\n DESIRED: array(['
             '1.000000002, 2.00003    , 3.00004    ])')
        # 使用 assert_equal 断言 a 和 b 相等
        assert_equal(a, b)


class TestEqual(TestArrayEqual):

    def setup_method(self):
        # 设置测试中使用的断言函数为 assert_equal
        self._assert_func = assert_equal

    def test_nan_items(self):
        # 测试 NaN 值的相等性断言
        self._assert_func(np.nan, np.nan)
        self._assert_func([np.nan], [np.nan])
        # 测试 NaN 值的不等性断言
        self._test_not_equal(np.nan, [np.nan])
        self._test_not_equal(np.nan, 1)

    def test_inf_items(self):
        # 测试 Infinity 值的相等性断言
        self._assert_func(np.inf, np.inf)
        self._assert_func([np.inf], [np.inf])
        # 测试 Infinity 值的不等性断言
        self._test_not_equal(np.inf, [np.inf])

    def test_datetime(self):
        # 测试日期时间对象的相等性断言
        self._test_equal(
            np.datetime64("2017-01-01", "s"),
            np.datetime64("2017-01-01", "s")
        )
        self._test_equal(
            np.datetime64("2017-01-01", "s"),
            np.datetime64("2017-01-01", "m")
        )

        # gh-10081
        # 测试日期时间对象的不等性断言
        self._test_not_equal(
            np.datetime64("2017-01-01", "s"),
            np.datetime64("2017-01-02", "s")
        )
        self._test_not_equal(
            np.datetime64("2017-01-01", "s"),
            np.datetime64("2017-01-02", "m")
        )
    # 定义测试函数,验证非有效日期时间对象
    def test_nat_items(self):
        # 创建不是日期时间对象的 NaT(Not a Time)
        nadt_no_unit = np.datetime64("NaT")
        # 创建秒精度的 NaT
        nadt_s = np.datetime64("NaT", "s")
        # 创建纳秒精度的 NaT
        nadt_d = np.datetime64("NaT", "ns")
        
        # 创建不是时间差对象的 NaT(Not a Timedelta)
        natd_no_unit = np.timedelta64("NaT")
        # 创建秒精度的 NaT
        natd_s = np.timedelta64("NaT", "s")
        # 创建纳秒精度的 NaT
        natd_d = np.timedelta64("NaT", "ns")
        
        # 构建日期时间对象和时间差对象列表
        dts = [nadt_no_unit, nadt_s, nadt_d]
        tds = [natd_no_unit, natd_s, natd_d]
        
        # 遍历日期时间对象列表进行各种断言和不相等测试
        for a, b in itertools.product(dts, dts):
            self._assert_func(a, b)
            self._assert_func([a], [b])
            self._test_not_equal([a], b)
        
        # 遍历时间差对象列表进行各种断言和不相等测试
        for a, b in itertools.product(tds, tds):
            self._assert_func(a, b)
            self._assert_func([a], [b])
            self._test_not_equal([a], b)
        
        # 遍历日期时间对象和时间差对象列表进行不相等测试
        for a, b in itertools.product(tds, dts):
            self._test_not_equal(a, b)
            self._test_not_equal(a, [b])
            self._test_not_equal([a], [b])
            self._test_not_equal([a], np.datetime64("2017-01-01", "s"))
            self._test_not_equal([b], np.datetime64("2017-01-01", "s"))
            self._test_not_equal([a], np.timedelta64(123, "s"))
            self._test_not_equal([b], np.timedelta64(123, "s"))

    # 验证非数值对象
    def test_non_numeric(self):
        self._assert_func('ab', 'ab')
        self._test_not_equal('ab', 'abb')

    # 验证复杂对象
    def test_complex_item(self):
        self._assert_func(complex(1, 2), complex(1, 2))
        self._assert_func(complex(1, np.nan), complex(1, np.nan))
        self._test_not_equal(complex(1, np.nan), complex(1, 2))
        self._test_not_equal(complex(np.nan, 1), complex(1, np.nan))
        self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2))

    # 验证负零
    def test_negative_zero(self):
        self._test_not_equal(ncu.PZERO, ncu.NZERO)

    # 验证复杂对象数组
    def test_complex(self):
        x = np.array([complex(1, 2), complex(1, np.nan)])
        y = np.array([complex(1, 2), complex(1, 2)])
        self._assert_func(x, x)
        self._test_not_equal(x, y)

    # 验证对象数组
    def test_object(self):
        # gh-12942
        import datetime
        a = np.array([datetime.datetime(2000, 1, 1),
                      datetime.datetime(2000, 1, 2)])
        self._test_not_equal(a, a[::-1])
class TestArrayAlmostEqual(_GenericTest):

    def setup_method(self):
        # 设置断言函数为 assert_array_almost_equal
        self._assert_func = assert_array_almost_equal

    def test_closeness(self):
        # 在漫长的时间过程中,我们发现
        #     `abs(x - y) < 1.5 * 10**(-decimal)`
        # 取代了先前记录的
        #     `abs(x - y) < 0.5 * 10**(-decimal)`
        # 因此,这个检查旨在保留错误。

        # 测试标量
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 1.5\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 的断言来确保抛出 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(1.5, 0.0, decimal=0)

        # 测试数组
        self._assert_func([1.499999], [0.0], decimal=0)

        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 1.5\n'
                        'Max relative difference among violations: inf')
        # 再次使用 pytest 的断言来确保抛出 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func([1.5], [0.0], decimal=0)

        a = [1.4999999, 0.00003]
        b = [1.49999991, 0]
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 3.e-05\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 的断言来确保抛出 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b, decimal=7)

        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 3.e-05\n'
                        'Max relative difference among violations: 1.')
        # 再次使用 pytest 的断言来确保抛出 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(b, a, decimal=7)

    def test_simple(self):
        x = np.array([1234.2222])
        y = np.array([1234.2223])

        # 使用断言函数进行比较,精度为 3
        self._assert_func(x, y, decimal=3)
        # 使用断言函数进行比较,精度为 4
        self._assert_func(x, y, decimal=4)

        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: '
                        '1.e-04\n'
                        'Max relative difference among violations: '
                        '8.10226812e-08')
        # 使用 pytest 的断言来确保抛出 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y, decimal=5)
    # 定义测试函数,用于比较数组和标量的断言
    def test_array_vs_scalar(self):
        # 创建数组 a 和标量 b
        a = [5498.42354, 849.54345, 0.00]
        b = 5498.42354
        # 定义预期的错误消息,包含预期的差异统计信息
        expected_msg = ('Mismatched elements: 2 / 3 (66.7%)\n'
                        'Max absolute difference among violations: '
                        '5498.42354\n'
                        'Max relative difference among violations: 1.')
        # 使用 pytest 断言检查调用 self._assert_func(a, b, decimal=9) 是否会引发 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b, decimal=9)

        # 更新预期的错误消息,改变 b 和 a 的位置进行比较
        expected_msg = ('Mismatched elements: 2 / 3 (66.7%)\n'
                        'Max absolute difference among violations: '
                        '5498.42354\n'
                        'Max relative difference among violations: 5.4722099')
        # 使用 pytest 断言检查调用 self._assert_func(b, a, decimal=9) 是否会引发 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(b, a, decimal=9)

        # 更新数组 a 和预期的错误消息,调整精度 decimal=7
        a = [5498.42354, 0.00]
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: '
                        '5498.42354\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 断言检查调用 self._assert_func(b, a, decimal=7) 是否会引发 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(b, a, decimal=7)

        # 更新标量 b 和预期的错误消息,调整精度 decimal=7
        b = 0
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: '
                        '5498.42354\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest 断言检查调用 self._assert_func(a, b, decimal=7) 是否会引发 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b, decimal=7)

    # 测试处理 NaN 值的情况
    def test_nan(self):
        # 创建包含 NaN 的数组 anan 和包含数值 1 的数组 aone
        anan = np.array([np.nan])
        aone = np.array([1])
        # 断言调用 self._assert_func(anan, anan) 没有引发异常
        self._assert_func(anan, anan)
        # 使用 assert_raises 检查调用 self._assert_func(anan, aone) 是否会引发 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(anan, aone))
        # 使用 assert_raises 检查调用 self._assert_func(anan, ainf) 是否会引发 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(anan, ainf))
        # 使用 assert_raises 检查调用 self._assert_func(ainf, anan) 是否会引发 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(ainf, anan))

    # 测试处理无穷大值的情况
    def test_inf(self):
        # 创建数组 a 和其副本 b,修改 a 中的一个元素为 np.inf
        a = np.array([[1., 2.], [3., 4.]])
        b = a.copy()
        a[0, 0] = np.inf
        # 使用 assert_raises 检查调用 self._assert_func(a, b) 是否会引发 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(a, b))
        # 将 b 中相同位置的元素修改为 -np.inf
        b[0, 0] = -np.inf
        # 使用 assert_raises 检查调用 self._assert_func(a, b) 是否会引发 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(a, b))
    # 定义一个测试方法,用于测试特定的子类行为
    def test_subclass(self):
        # 创建一个普通的 NumPy 数组 a
        a = np.array([[1., 2.], [3., 4.]])
        # 创建一个带掩码的 NumPy 掩码数组 b
        b = np.ma.masked_array([[1., 2.], [0., 4.]],
                               [[False, False], [True, False]])
        # 断言 a 和 b 通过自定义的断言函数 _assert_func 相等
        self._assert_func(a, b)
        # 断言 b 和 a 通过自定义的断言函数 _assert_func 相等
        self._assert_func(b, a)
        # 断言 b 和 b 通过自定义的断言函数 _assert_func 相等
        self._assert_func(b, b)

        # 测试完全掩码的情况(参见 gh-11123)
        # 创建一个完全掩码的 NumPy 掩码数组 a
        a = np.ma.MaskedArray(3.5, mask=True)
        # 创建一个普通的 NumPy 数组 b
        b = np.array([3., 4., 6.5])
        # 断言 a 和 b 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(a, b)
        # 断言 b 和 a 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(b, a)
        # 创建一个未定义掩码的掩码数组 a
        a = np.ma.masked
        # 创建一个普通的 NumPy 数组 b
        b = np.array([3., 4., 6.5])
        # 断言 a 和 b 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(a, b)
        # 断言 b 和 a 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(b, a)
        # 创建一个带部分掩码的 NumPy 掩码数组 a
        a = np.ma.MaskedArray([3., 4., 6.5], mask=[True, True, True])
        # 创建一个普通的 NumPy 数组 b
        b = np.array([1., 2., 3.])
        # 断言 a 和 b 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(a, b)
        # 断言 b 和 a 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(b, a)
        # 创建一个带部分掩码的 NumPy 掩码数组 a
        a = np.ma.MaskedArray([3., 4., 6.5], mask=[True, True, True])
        # 创建一个普通的 NumPy 数组 b
        b = np.array(1.)
        # 断言 a 和 b 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(a, b)
        # 断言 b 和 a 通过自定义的测试相等函数 _test_equal 相等
        self._test_equal(b, a)

    # 定义另一个测试方法,测试无法用布尔值存储的子类行为
    def test_subclass_2(self):
        # 尽管我们无法保证测试函数总是适用于子类,测试理想情况下应该仅依赖于子类具有比较运算符,
        # 而不是依赖它们能够存储布尔值(例如 astropy Quantity 无法有用地执行此操作)。参见 gh-8452。
        class MyArray(np.ndarray):
            def __eq__(self, other):
                return super().__eq__(other).view(np.ndarray)

            def __lt__(self, other):
                return super().__lt__(other).view(np.ndarray)

            def all(self, *args, **kwargs):
                return all(self)

        # 创建一个视图为 MyArray 的普通 NumPy 数组 a
        a = np.array([1., 2.]).view(MyArray)
        # 断言 a 和 a 通过自定义的断言函数 _assert_func 相等
        self._assert_func(a, a)

        # 创建一个视图为 MyArray 的布尔值数组 z
        z = np.array([True, True]).view(MyArray)
        # 调用 all 方法,这里并未使用其返回值
        all(z)
        # 创建一个视图为 MyArray 的普通 NumPy 数组 b
        b = np.array([1., 202]).view(MyArray)
        # 创建预期的错误消息
        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 200.\n'
                        'Max relative difference among violations: 0.99009')
        # 使用 pytest 断言捕获 AssertionError 异常,并匹配预期消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b)

    # 定义另一个测试方法,测试无法用布尔值存储的子类行为
    def test_subclass_that_cannot_be_bool(self):
        # 尽管我们无法保证测试函数总是适用于子类,测试理想情况下应该仅依赖于子类具有比较运算符,
        # 而不是依赖它们能够存储布尔值(例如 astropy Quantity 无法有用地执行此操作)。参见 gh-8452。
        class MyArray(np.ndarray):
            def __eq__(self, other):
                return super().__eq__(other).view(np.ndarray)

            def __lt__(self, other):
                return super().__lt__(other).view(np.ndarray)

            def all(self, *args, **kwargs):
                raise NotImplementedError

        # 创建一个视图为 MyArray 的普通 NumPy 数组 a
        a = np.array([1., 2.]).view(MyArray)
        # 断言 a 和 a 通过自定义的断言函数 _assert_func 相等
        self._assert_func(a, a)
class TestAlmostEqual(_GenericTest):

    def setup_method(self):
        # 设置断言函数为 assert_almost_equal
        self._assert_func = assert_almost_equal

    def test_closeness(self):
        # 测试近似性
        # 注意,随着时间推移,我们将
        #     `abs(x - y) < 1.5 * 10**(-decimal)`
        # 替换了之前文档中的
        #     `abs(x - y) < 0.5 * 10**(-decimal)`
        # 因此这个检查用来保留错误行为。

        # 测试标量值
        self._assert_func(1.499999, 0.0, decimal=0)
        # 断言会抛出 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(1.5, 0.0, decimal=0))

        # 测试数组
        self._assert_func([1.499999], [0.0], decimal=0)
        # 断言会抛出 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func([1.5], [0.0], decimal=0))

    def test_nan_item(self):
        # 测试 NaN 值
        self._assert_func(np.nan, np.nan)
        # 断言会抛出 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(np.nan, 1))
        assert_raises(AssertionError,
                      lambda: self._assert_func(np.nan, np.inf))
        assert_raises(AssertionError,
                      lambda: self._assert_func(np.inf, np.nan))

    def test_inf_item(self):
        # 测试无穷大值
        self._assert_func(np.inf, np.inf)
        self._assert_func(-np.inf, -np.inf)
        # 断言会抛出 AssertionError
        assert_raises(AssertionError,
                      lambda: self._assert_func(np.inf, 1))
        assert_raises(AssertionError,
                      lambda: self._assert_func(-np.inf, np.inf))

    def test_simple_item(self):
        # 测试简单值的不相等情况
        self._test_not_equal(1, 2)

    def test_complex_item(self):
        # 测试复数值
        self._assert_func(complex(1, 2), complex(1, 2))
        self._assert_func(complex(1, np.nan), complex(1, np.nan))
        self._assert_func(complex(np.inf, np.nan), complex(np.inf, np.nan))
        self._test_not_equal(complex(1, np.nan), complex(1, 2))
        self._test_not_equal(complex(np.nan, 1), complex(1, np.nan))
        self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2))

    def test_complex(self):
        x = np.array([complex(1, 2), complex(1, np.nan)])
        z = np.array([complex(1, 2), complex(np.nan, 1)])
        y = np.array([complex(1, 2), complex(1, 2)])
        self._assert_func(x, x)
        self._test_not_equal(x, y)
        self._test_not_equal(x, z)
    # 定义一个测试方法,用于检查错误消息的格式化是否正确,特别是针对十进制值进行检查。
    # 还要检查包含 inf 或 nan 的输入时的错误消息 (gh12200)。
    def test_error_message(self):
        """Check the message is formatted correctly for the decimal value.
           Also check the message when input includes inf or nan (gh12200)"""

        # 创建两个 NumPy 数组,包含浮点数值,用于测试
        x = np.array([1.00000000001, 2.00000000002, 3.00003])
        y = np.array([1.00000000002, 2.00000000003, 3.00004])

        # 测试带有不同小数位数的情况
        expected_msg = ('Mismatched elements: 3 / 3 (100%)\n'
                        'Max absolute difference among violations: 1.e-05\n'
                        'Max relative difference among violations: '
                        '3.33328889e-06\n'
                        ' ACTUAL: array([1.00000000001, '
                        '2.00000000002, '
                        '3.00003      ])\n'
                        ' DESIRED: array([1.00000000002, 2.00000000003, '
                        '3.00004      ])')

        # 使用 pytest 的断言,验证是否抛出预期的 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y, decimal=12)

        # 使用默认的小数位数测试,只有第三个元素不同。注意,这里仅检查数组本身的格式化。
        expected_msg = ('Mismatched elements: 1 / 3 (33.3%)\n'
                        'Max absolute difference among violations: 1.e-05\n'
                        'Max relative difference among violations: '
                        '3.33328889e-06\n'
                        ' ACTUAL: array([1.     , 2.     , 3.00003])\n'
                        ' DESIRED: array([1.     , 2.     , 3.00004])')

        # 使用 pytest 的断言,验证是否抛出预期的 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 检查包含 inf 输入时的错误消息
        x = np.array([np.inf, 0])
        y = np.array([np.inf, 1])

        expected_msg = ('Mismatched elements: 1 / 2 (50%)\n'
                        'Max absolute difference among violations: 1.\n'
                        'Max relative difference among violations: 1.\n'
                        ' ACTUAL: array([inf,  0.])\n'
                        ' DESIRED: array([inf,  1.])')

        # 使用 pytest 的断言,验证是否抛出预期的 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 检查除以零时的错误消息
        x = np.array([1, 2])
        y = np.array([0, 0])

        expected_msg = ('Mismatched elements: 2 / 2 (100%)\n'
                        'Max absolute difference among violations: 2\n'
                        'Max relative difference among violations: inf')

        # 使用 pytest 的断言,验证是否抛出预期的 AssertionError,并匹配预期的消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)
    def test_error_message_2(self):
        """检查消息格式是否正确"""
        """当 x 或 y 中至少有一个是标量时。"""
        # 设置变量 x 为整数 2
        x = 2
        # 设置变量 y 为包含 20 个值为 1 的数组
        y = np.ones(20)
        # 设置期望的错误消息,用于匹配断言错误
        expected_msg = ('Mismatched elements: 20 / 20 (100%)\n'
                        'Max absolute difference among violations: 1.\n'
                        'Max relative difference among violations: 1.')
        # 使用 pytest 断言预期的 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 将变量 y 设置为整数 2
        y = 2
        # 将变量 x 设置为包含 20 个值为 1 的数组
        x = np.ones(20)
        # 更新期望的错误消息,用于匹配断言错误
        expected_msg = ('Mismatched elements: 20 / 20 (100%)\n'
                        'Max absolute difference among violations: 1.\n'
                        'Max relative difference among violations: 0.5')
        # 使用 pytest 断言预期的 AssertionError,并匹配预期的错误消息
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

    def test_subclass_that_cannot_be_bool(self):
        # 虽然我们无法保证测试函数始终适用于所有子类,
        # 但测试应该仅依赖于子类具有比较运算符,而不是依赖于它们能够存储布尔值
        # (例如,astropy Quantity 不能有用地执行此操作)。参见 gh-8452。
        # 定义一个自定义子类 MyArray,继承自 np.ndarray
        class MyArray(np.ndarray):
            # 重载等于运算符,返回 np.ndarray 视图
            def __eq__(self, other):
                return super().__eq__(other).view(np.ndarray)

            # 重载小于运算符,返回 np.ndarray 视图
            def __lt__(self, other):
                return super().__lt__(other).view(np.ndarray)

            # 定义 all 方法,抛出 NotImplementedError
            def all(self, *args, **kwargs):
                raise NotImplementedError

        # 创建一个包含 [1., 2.] 的 np.ndarray,并视图转换为 MyArray 类型
        a = np.array([1., 2.]).view(MyArray)
        # 使用自定义断言函数 _assert_func 对 a 进行断言
        self._assert_func(a, a)
class TestApproxEqual:

    # 设置测试方法的初始化,将 assert_approx_equal 函数赋给 self._assert_func
    def setup_method(self):
        self._assert_func = assert_approx_equal

    # 测试比较简单的零维数组情况
    def test_simple_0d_arrays(self):
        x = np.array(1234.22)   # 创建包含单个元素的 NumPy 数组 x
        y = np.array(1234.23)   # 创建包含单个元素的 NumPy 数组 y

        # 使用 self._assert_func 断言 x 和 y 相近,有效位数为 5 和 6
        self._assert_func(x, y, significant=5)
        self._assert_func(x, y, significant=6)
        
        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError,
                      lambda: self._assert_func(x, y, significant=7))

    # 测试比较简单的标量情况
    def test_simple_items(self):
        x = 1234.22   # 创建标量 x
        y = 1234.23   # 创建标量 y

        # 使用 self._assert_func 断言 x 和 y 相近,有效位数为 4、5 和 6
        self._assert_func(x, y, significant=4)
        self._assert_func(x, y, significant=5)
        self._assert_func(x, y, significant=6)
        
        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError,
                      lambda: self._assert_func(x, y, significant=7))

    # 测试包含 NaN 的数组情况
    def test_nan_array(self):
        anan = np.array(np.nan)   # 创建包含 NaN 的 NumPy 数组 anan
        aone = np.array(1)        # 创建包含单个元素的 NumPy 数组 aone
        ainf = np.array(np.inf)   # 创建包含 Inf 的 NumPy 数组 ainf
        
        # 使用 self._assert_func 断言 anan 和 anan 相等
        self._assert_func(anan, anan)
        
        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError, lambda: self._assert_func(anan, aone))
        assert_raises(AssertionError, lambda: self._assert_func(anan, ainf))
        assert_raises(AssertionError, lambda: self._assert_func(ainf, anan))

    # 测试包含 NaN 的标量情况
    def test_nan_items(self):
        anan = np.array(np.nan)   # 创建包含 NaN 的 NumPy 数组 anan
        aone = np.array(1)        # 创建包含单个元素的 NumPy 数组 aone
        ainf = np.array(np.inf)   # 创建包含 Inf 的 NumPy 数组 ainf
        
        # 使用 self._assert_func 断言 anan 和 anan 相等
        self._assert_func(anan, anan)
        
        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError, lambda: self._assert_func(anan, aone))
        assert_raises(AssertionError, lambda: self._assert_func(anan, ainf))
        assert_raises(AssertionError, lambda: self._assert_func(ainf, anan))


class TestArrayAssertLess:

    # 设置测试方法的初始化,将 assert_array_less 函数赋给 self._assert_func
    def setup_method(self):
        self._assert_func = assert_array_less

    # 测试比较简单的数组情况
    def test_simple_arrays(self):
        x = np.array([1.1, 2.2])   # 创建包含多个元素的 NumPy 数组 x
        y = np.array([1.2, 2.3])   # 创建包含多个元素的 NumPy 数组 y

        # 使用 self._assert_func 断言 x 小于 y
        self._assert_func(x, y)
        
        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

        y = np.array([1.0, 2.3])   # 创建包含多个元素的 NumPy 数组 y

        # 使用 lambda 函数和 assert_raises 检查 self._assert_func 报错情况
        assert_raises(AssertionError, lambda: self._assert_func(x, y))
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

        a = np.array([1, 3, 6, 20])   # 创建包含多个元素的 NumPy 数组 a
        b = np.array([2, 4, 6, 8])    # 创建包含多个元素的 NumPy 数组 b

        # 设置预期的错误信息
        expected_msg = ('Mismatched elements: 2 / 4 (50%)\n'
                        'Max absolute difference among violations: 12\n'
                        'Max relative difference among violations: 1.5')
        
        # 使用 pytest.raises 和 match=re.escape(expected_msg) 断言 self._assert_func 抛出错误
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(a, b)
    # 定义一个测试函数,用于测试二维数组的相等性断言
    def test_rank2(self):
        # 创建两个二维 NumPy 数组作为测试数据
        x = np.array([[1.1, 2.2], [3.3, 4.4]])
        y = np.array([[1.2, 2.3], [3.4, 4.5]])

        # 调用自定义的断言函数,验证两个数组是否相等
        self._assert_func(x, y)

        # 设置预期的错误消息,用于验证断言失败时的异常内容
        expected_msg = ('Mismatched elements: 4 / 4 (100%)\n'
                        'Max absolute difference among violations: 0.1\n'
                        'Max relative difference among violations: 0.09090909')
        
        # 使用 pytest 来验证调换参数顺序时的断言失败
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(y, x)

        # 修改 y 的值,使得与 x 不相等
        y = np.array([[1.0, 2.3], [3.4, 4.5]])

        # 使用 lambda 函数和 assert_raises 来验证断言失败
        assert_raises(AssertionError, lambda: self._assert_func(x, y))
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

    # 定义另一个测试函数,用于测试三维数组的相等性断言
    def test_rank3(self):
        # 创建两个全为 1 的三维 NumPy 数组作为测试数据
        x = np.ones(shape=(2, 2, 2))
        y = np.ones(shape=(2, 2, 2)) + 1

        # 调用自定义的断言函数,验证两个数组是否相等
        self._assert_func(x, y)

        # 使用 lambda 函数和 assert_raises 来验证断言失败
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

        # 修改 y 的一个元素,使得与 x 不相等
        y[0, 0, 0] = 0

        # 设置预期的错误消息,用于验证断言失败时的异常内容
        expected_msg = ('Mismatched elements: 1 / 8 (12.5%)\n'
                        'Max absolute difference among violations: 1.\n'
                        'Max relative difference among violations: inf')
        
        # 使用 pytest 来验证特定条件下的断言失败
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 使用 lambda 函数和 assert_raises 来验证断言失败
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

    # 定义第三个测试函数,用于测试简单数值和数组的相等性断言
    def test_simple_items(self):
        # 创建两个简单的数值作为测试数据
        x = 1.1
        y = 2.2

        # 调用自定义的断言函数,验证两个数值是否相等
        self._assert_func(x, y)

        # 设置预期的错误消息,用于验证断言失败时的异常内容
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 1.1\n'
                        'Max relative difference among violations: 1.')
        
        # 使用 pytest 来验证调换参数顺序时的断言失败
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(y, x)

        # 修改 y 的值,使得与 x 不相等
        y = np.array([2.2, 3.3])

        # 调用自定义的断言函数,验证数值与数组的相等性
        self._assert_func(x, y)

        # 使用 lambda 函数和 assert_raises 来验证断言失败
        assert_raises(AssertionError, lambda: self._assert_func(y, x))

        # 修改 y 的值,使得与 x 不相等
        y = np.array([1.0, 3.3])

        # 使用 lambda 函数和 assert_raises 来验证断言失败
        assert_raises(AssertionError, lambda: self._assert_func(x, y))
    # 定义一个测试函数,用于测试简单的数值和数组
    def test_simple_items_and_array(self):
        # 创建一个包含浮点数的 NumPy 数组
        x = np.array([[621.345454, 390.5436, 43.54657, 626.4535],
                      [54.54, 627.3399, 13., 405.5435],
                      [543.545, 8.34, 91.543, 333.3]])
        # 设置一个浮点数作为预期值 y,并调用 _assert_func 进行断言
        y = 627.34
        self._assert_func(x, y)

        # 更改预期值 y 为另一个浮点数,并再次调用 _assert_func 进行断言
        y = 8.339999
        self._assert_func(y, x)

        # 修改数组 x 为另一个包含浮点数的 NumPy 数组
        x = np.array([[3.4536, 2390.5436, 435.54657, 324525.4535],
                      [5449.54, 999090.54, 130303.54, 405.5435],
                      [543.545, 8.34, 91.543, 999090.53999]])
        # 设置预期值 y 为一个浮点数,并预计会引发 AssertionError
        y = 999090.54

        # 定义预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 1 / 12 (8.33%)\n'
                        'Max absolute difference among violations: 0.\n'
                        'Max relative difference among violations: 0.')
        # 使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 定义另一个预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 12 / 12 (100%)\n'
                        'Max absolute difference among violations: '
                        '999087.0864\n'
                        'Max relative difference among violations: '
                        '289288.5934676')
        # 再次使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(y, x)

    # 定义另一个测试函数,用于测试包含零值的情况
    def test_zeroes(self):
        # 创建一个包含浮点数的 NumPy 数组 x 和一个浮点数 y
        x = np.array([546456., 0, 15.455])
        y = np.array(87654.)

        # 定义预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 1 / 3 (33.3%)\n'
                        'Max absolute difference among violations: 458802.\n'
                        'Max relative difference among violations: 5.23423917')
        # 使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 定义另一个预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 2 / 3 (66.7%)\n'
                        'Max absolute difference among violations: 87654.\n'
                        'Max relative difference among violations: '
                        '5670.5626011')
        # 再次使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(y, x)

        # 修改预期值 y 为零
        y = 0

        # 定义预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 3 / 3 (100%)\n'
                        'Max absolute difference among violations: 546456.\n'
                        'Max relative difference among violations: inf')
        # 使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(x, y)

        # 定义另一个预期的错误消息,包含在 pytest 的断言中进行验证
        expected_msg = ('Mismatched elements: 1 / 3 (33.3%)\n'
                        'Max absolute difference among violations: 0.\n'
                        'Max relative difference among violations: inf')
        # 再次使用 pytest.raises 检查是否抛出预期的 AssertionError,验证 _assert_func 的行为
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            self._assert_func(y, x)
    # 测试处理 NaN 值的情况,使用 NumPy 数组进行比较
    def test_nan_noncompare(self):
        # 创建包含 NaN 的 NumPy 数组
        anan = np.array(np.nan)
        # 创建包含整数 1 的 NumPy 数组
        aone = np.array(1)
        # 创建包含正无穷大的 NumPy 数组
        ainf = np.array(np.inf)
        
        # 调用自定义断言函数,验证相等性
        self._assert_func(anan, anan)
        # 预期抛出断言错误,因为整数数组和 NaN 数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(aone, anan))
        # 预期抛出断言错误,因为 NaN 数组和整数数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(anan, aone))
        # 预期抛出断言错误,因为 NaN 数组和正无穷大数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(anan, ainf))
        # 预期抛出断言错误,因为正无穷大数组和 NaN 数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(ainf, anan))
    
    # 测试处理包含 NaN 值的 NumPy 数组的情况
    def test_nan_noncompare_array(self):
        # 创建包含浮点数的 NumPy 数组
        x = np.array([1.1, 2.2, 3.3])
        # 创建包含 NaN 的 NumPy 数组
        anan = np.array(np.nan)
        
        # 预期抛出断言错误,因为数组 x 和 NaN 数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(x, anan))
        # 预期抛出断言错误,因为 NaN 数组和数组 x 不相等
        assert_raises(AssertionError, lambda: self._assert_func(anan, x))
        
        # 修改数组 x,包含 NaN 值
        x = np.array([1.1, 2.2, np.nan])
        
        # 预期抛出断言错误,因为数组 x 和 NaN 数组不相等
        assert_raises(AssertionError, lambda: self._assert_func(x, anan))
        # 预期抛出断言错误,因为 NaN 数组和数组 x 不相等
        assert_raises(AssertionError, lambda: self._assert_func(anan, x))
        
        # 创建另一个包含 NaN 值的 NumPy 数组
        y = np.array([1.0, 2.0, np.nan])
        
        # 调用自定义断言函数,验证两个包含 NaN 值的数组相等
        self._assert_func(y, x)
        # 预期抛出断言错误,因为数组 x 和 y 不相等
        assert_raises(AssertionError, lambda: self._assert_func(x, y))
    
    # 测试处理无穷大值的情况,使用 NumPy 数组进行比较
    def test_inf_compare(self):
        # 创建包含整数 1 的 NumPy 数组
        aone = np.array(1)
        # 创建包含正无穷大的 NumPy 数组
        ainf = np.array(np.inf)
        
        # 调用自定义断言函数,验证 aone 和 ainf 相等
        self._assert_func(aone, ainf)
        # 调用自定义断言函数,验证 -ainf 和 aone 相等
        self._assert_func(-ainf, aone)
        # 调用自定义断言函数,验证 -ainf 和 ainf 相等
        self._assert_func(-ainf, ainf)
        # 预期抛出断言错误,因为 ainf 和 aone 不相等
        assert_raises(AssertionError, lambda: self._assert_func(ainf, aone))
        # 预期抛出断言错误,因为 aone 和 -ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(aone, -ainf))
        # 预期抛出断言错误,因为 ainf 和 ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(ainf, ainf))
        # 预期抛出断言错误,因为 ainf 和 -ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(ainf, -ainf))
        # 预期抛出断言错误,因为 -ainf 和 -ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(-ainf, -ainf))
    
    # 测试处理包含无穷大值的 NumPy 数组的情况
    def test_inf_compare_array(self):
        # 创建包含浮点数的 NumPy 数组
        x = np.array([1.1, 2.2, np.inf])
        # 创建包含正无穷大的 NumPy 数组
        ainf = np.array(np.inf)
        
        # 预期抛出断言错误,因为数组 x 和 ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(x, ainf))
        # 预期抛出断言错误,因为 ainf 和数组 x 不相等
        assert_raises(AssertionError, lambda: self._assert_func(ainf, x))
        # 预期抛出断言错误,因为数组 x 和 -ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(x, -ainf))
        # 预期抛出断言错误,因为 -x 和 -ainf 不相等
        assert_raises(AssertionError, lambda: self._assert_func(-x, -ainf))
        # 预期抛出断言错误,因为 -ainf 和 -x 不相等
        assert_raises(AssertionError, lambda: self._assert_func(-ainf, -x))
        # 调用自定义断言函数,验证 -ainf 和数组 x 相等
        self._assert_func(-ainf, x)
    
    # 测试严格模式(strict)的行为
    def test_strict(self):
        """Test the behavior of the `strict` option."""
        # 创建包含三个元素的零数组
        x = np.zeros(3)
        # 创建包含单个元素 1.0 的数组
        y = np.ones(())
        
        # 调用自定义断言函数,验证 x 和 y 相等
        self._assert_func(x, y)
        # 预期抛出断言错误,因为严格模式下,x 和 y 不相等
        with pytest.raises(AssertionError):
            self._assert_func(x, y, strict=True)
        
        # 将数组 y 广播至与 x 相同的形状
        y = np.broadcast_to(y, x.shape)
        
        # 调用自定义断言函数,验证 x 和 y 相等
        self._assert_func(x, y)
        # 预期抛出断言错误,因为严格模式下,x 和 y 的类型不同
        with pytest.raises(AssertionError):
            self._assert_func(x, y.astype(np.float32), strict=True)
    # 定义一个名为 TestWarns 的测试类
class TestWarns:

    # 定义一个测试方法 test_warn,用于测试警告功能
    def test_warn(self):
        # 定义内部函数 f,其中发出一个警告 "yo",然后返回 3
        def f():
            warnings.warn("yo")
            return 3
        
        # 备份当前警告过滤器
        before_filters = sys.modules['warnings'].filters[:]
        # 使用 assert_warns 检查 f 函数是否会发出 UserWarning,并返回其返回值
        assert_equal(assert_warns(UserWarning, f), 3)
        # 获取执行 assert_warns 后的警告过滤器状态
        after_filters = sys.modules['warnings'].filters

        # 使用 assert_raises 检查 assert_no_warnings 是否会抛出 AssertionError
        assert_raises(AssertionError, assert_no_warnings, f)
        # 使用 assert_no_warnings 检查 lambda 函数是否不会发出警告
        assert_equal(assert_no_warnings(lambda x: x, 1), 1)

        # 检查警告状态是否未发生变化
        assert_equal(before_filters, after_filters,
                     "assert_warns does not preserve warnings state")

    # 定义另一个测试方法 test_context_manager,测试上下文管理器的警告功能
    def test_context_manager(self):
        # 备份当前警告过滤器
        before_filters = sys.modules['warnings'].filters[:]
        # 使用 assert_warns 上下文管理器检查代码块是否会发出 UserWarning
        with assert_warns(UserWarning):
            warnings.warn("yo")
        # 获取执行 assert_warns 后的警告过滤器状态
        after_filters = sys.modules['warnings'].filters

        # 定义一个内部函数 no_warnings,使用 assert_no_warnings 上下文管理器检查代码块不会发出警告
        def no_warnings():
            with assert_no_warnings():
                warnings.warn("yo")

        # 使用 assert_raises 检查 no_warnings 是否会抛出 AssertionError
        assert_raises(AssertionError, no_warnings)
        # 检查警告状态是否未发生变化
        assert_equal(before_filters, after_filters,
                     "assert_warns does not preserve warnings state")

    # 定义另一个测试方法 test_args,测试带参数的函数警告功能
    def test_args(self):
        # 定义函数 f,带有默认参数 a=0, b=1,发出警告 "yo",并返回 a + b 的值
        def f(a=0, b=1):
            warnings.warn("yo")
            return a + b

        # 使用 assert_warns 检查 f 函数是否会发出 UserWarning,并返回其正确的返回值 20
        assert assert_warns(UserWarning, f, b=20) == 20

        # 使用 pytest.raises 检查使用错误参数调用 assert_warns 是否会抛出 RuntimeError
        with pytest.raises(RuntimeError) as exc:
            # assert_warns 无法进行正则表达式匹配,应使用 pytest.warns
            with assert_warns(UserWarning, match="A"):
                warnings.warn("B", UserWarning)
        assert "assert_warns" in str(exc)
        assert "pytest.warns" in str(exc)

        # 使用 pytest.raises 检查使用错误参数调用 assert_warns 是否会抛出 RuntimeError
        with pytest.raises(RuntimeError) as exc:
            # assert_warns 无法进行正则表达式匹配,应使用 pytest.warns
            with assert_warns(UserWarning, wrong="A"):
                warnings.warn("B", UserWarning)
        assert "assert_warns" in str(exc)
        assert "pytest.warns" not in str(exc)

    # 定义测试方法 test_warn_wrong_warning,测试错误的警告类型
    def test_warn_wrong_warning(self):
        # 定义函数 f,发出一个带有 DeprecationWarning 的警告 "yo"
        def f():
            warnings.warn("yo", DeprecationWarning)

        # 设置一个标志变量 failed
        failed = False
        # 使用 warnings.catch_warnings 上下文管理器捕获警告
        with warnings.catch_warnings():
            # 将 DeprecationWarning 设置为错误,以便触发异常
            warnings.simplefilter("error", DeprecationWarning)
            try:
                # 使用 assert_warns 检查 f 函数是否会发出 DeprecationWarning
                assert_warns(UserWarning, f)
                # 如果未触发预期的 DeprecationWarning,将 failed 设为 True
                failed = True
            except DeprecationWarning:
                pass

        # 如果 failed 为 True,抛出 AssertionError,表示捕获了错误的警告类型
        if failed:
            raise AssertionError("wrong warning caught by assert_warn")
    def test_simple(self):
        # 设置变量 x 和 y 分别为 0.001 和 1e-9
        x = 1e-3
        y = 1e-9

        # 断言 x 和 y 的绝对误差不超过 1,应该通过测试
        assert_allclose(x, y, atol=1)
        # 断言 x 和 y 的绝对误差超过 1,预期抛出 AssertionError
        assert_raises(AssertionError, assert_allclose, x, y)

        # 预期的错误消息,包含了详细的误差信息
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 0.001\n'
                        'Max relative difference among violations: 999999.')
        # 断言 x 和 y 的误差匹配预期错误消息,预期抛出 AssertionError
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(x, y)

        # 设置 z 为 0
        z = 0
        # 预期的错误消息,包含了详细的误差信息
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 1.e-09\n'
                        'Max relative difference among violations: inf')
        # 断言 y 和 z 的误差匹配预期错误消息,预期抛出 AssertionError
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(y, z)

        # 预期的错误消息,包含了详细的误差信息
        expected_msg = ('Mismatched elements: 1 / 1 (100%)\n'
                        'Max absolute difference among violations: 1.e-09\n'
                        'Max relative difference among violations: 1.')
        # 断言 z 和 y 的误差匹配预期错误消息,预期抛出 AssertionError
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(z, y)

        # 创建数组 a 和 b
        a = np.array([x, y, x, y])
        b = np.array([x, y, x, x])

        # 断言 a 和 b 的绝对误差不超过 1,应该通过测试
        assert_allclose(a, b, atol=1)
        # 断言 a 和 b 的绝对误差超过 1,预期抛出 AssertionError
        assert_raises(AssertionError, assert_allclose, a, b)

        # 修改 b 的最后一个元素,使其与 a 的最后一个元素略有偏差
        b[-1] = y * (1 + 1e-8)
        # 断言 a 和修改后的 b 的误差在默认容差内,应该通过测试
        assert_allclose(a, b)
        # 断言 a 和修改后的 b 的误差超过指定相对容差,预期抛出 AssertionError
        assert_raises(AssertionError, assert_allclose, a, b, rtol=1e-9)

        # 断言 6 和 10 的相对误差不超过 50%,应该通过测试
        assert_allclose(6, 10, rtol=0.5)
        # 断言 10 和 6 的相对误差超过 50%,预期抛出 AssertionError
        assert_raises(AssertionError, assert_allclose, 10, 6, rtol=0.5)

        # 重新设置 b 和 c 数组
        b = np.array([x, y, x, x])
        c = np.array([x, y, x, z])

        # 预期的错误消息,包含了详细的误差信息
        expected_msg = ('Mismatched elements: 1 / 4 (25%)\n'
                        'Max absolute difference among violations: 0.001\n'
                        'Max relative difference among violations: inf')
        # 断言 b 和 c 的误差匹配预期错误消息,预期抛出 AssertionError
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(b, c)

        # 预期的错误消息,包含了详细的误差信息
        expected_msg = ('Mismatched elements: 1 / 4 (25%)\n'
                        'Max absolute difference among violations: 0.001\n'
                        'Max relative difference among violations: 1.')
        # 断言 c 和 b 的误差匹配预期错误消息,预期抛出 AssertionError
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(c, b)
    def test_equal_nan(self):
        a = np.array([np.nan])
        b = np.array([np.nan])
        # 应该不会引发异常:
        assert_allclose(a, b, equal_nan=True)

    def test_not_equal_nan(self):
        a = np.array([np.nan])
        b = np.array([np.nan])
        # 应该引发 AssertionError:
        assert_raises(AssertionError, assert_allclose, a, b, equal_nan=False)

    def test_equal_nan_default(self):
        # 确保 equal_nan 的默认行为保持不变。 (这些函数都在底层使用 assert_array_compare。)
        # 以下都不应该引发异常。
        a = np.array([np.nan])
        b = np.array([np.nan])
        assert_array_equal(a, b)
        assert_array_almost_equal(a, b)
        assert_array_less(a, b)
        assert_allclose(a, b)

    def test_report_max_relative_error(self):
        a = np.array([0, 1])
        b = np.array([0, 2])

        expected_msg = 'Max relative difference among violations: 0.5'
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(a, b)

    def test_timedelta(self):
        # 见 gh-18286
        a = np.array([[1, 2, 3, "NaT"]], dtype="m8[ns]")
        assert_allclose(a, a)

    def test_error_message_unsigned(self):
        """检查溢出可能发生时消息的格式是否正确 (gh21768)"""
        # 确保在以下情况下测试潜在的溢出:
        #        x - y
        # 和
        #        y - x
        x = np.asarray([0, 1, 8], dtype='uint8')
        y = np.asarray([4, 4, 4], dtype='uint8')
        expected_msg = 'Max absolute difference among violations: 4'
        with pytest.raises(AssertionError, match=re.escape(expected_msg)):
            assert_allclose(x, y, atol=3)

    def test_strict(self):
        """测试 `strict` 选项的行为。"""
        x = np.ones(3)
        y = np.ones(())
        assert_allclose(x, y)
        with pytest.raises(AssertionError):
            assert_allclose(x, y, strict=True)
        assert_allclose(x, x)
        with pytest.raises(AssertionError):
            assert_allclose(x, x.astype(np.float32), strict=True)
class TestArrayAlmostEqualNulp:

    def test_float64_pass(self):
        # 定义单位最小精度的数量
        nulp = 5
        # 生成一个包含50个元素的浮点数数组,范围从-20到20
        x = np.linspace(-20, 20, 50, dtype=np.float64)
        # 对数组中的每个元素取10的幂
        x = 10**x
        # 在数组的前后添加相反数形成一个新的数组
        x = np.r_[-x, x]

        # 计算浮点数类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 构造与数组x相加后差异在几个单位最小精度内的数组y
        y = x + x*eps*nulp/2.
        # 断言数组x与数组y在指定单位最小精度内几乎相等
        assert_array_almost_equal_nulp(x, y, nulp)

        # 构造与数组x相减后差异在几个单位最小精度内的数组y
        epsneg = np.finfo(x.dtype).epsneg
        y = x - x*epsneg*nulp/2.
        # 断言数组x与数组y在指定单位最小精度内几乎相等
        assert_array_almost_equal_nulp(x, y, nulp)

    def test_float64_fail(self):
        # 定义单位最小精度的数量
        nulp = 5
        # 生成一个包含50个元素的浮点数数组,范围从-20到20
        x = np.linspace(-20, 20, 50, dtype=np.float64)
        # 对数组中的每个元素取10的幂
        x = 10**x
        # 在数组的前后添加相反数形成一个新的数组
        x = np.r_[-x, x]

        # 计算浮点数类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 构造与数组x相加后超出几个单位最小精度内的数组y
        y = x + x*eps*nulp*2.
        # 断言抛出AssertionError异常,因为数组x与数组y不在指定的单位最小精度内几乎相等
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)

        # 构造与数组x相减后超出几个单位最小精度内的数组y
        epsneg = np.finfo(x.dtype).epsneg
        y = x - x*epsneg*nulp*2.
        # 断言抛出AssertionError异常,因为数组x与数组y不在指定的单位最小精度内几乎相等
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)

    def test_float64_ignore_nan(self):
        # 忽略各种NaN之间的单位最小精度差异
        # 注意在MIPS中,可能会颠倒安静NaN和信号NaN
        # 所以我们使用内建版本作为基础
        offset = np.uint64(0xffffffff)
        # 将NaN转换为64位浮点数,并获取其对应的64位整数表示
        nan1_i64 = np.array(np.nan, dtype=np.float64).view(np.uint64)
        # 对第一个NaN的整数表示进行位异或操作,得到另一个NaN的整数表示
        nan2_i64 = nan1_i64 ^ offset  # 在MIPS上,NaN的有效载荷是全1
        # 将64位整数表示转换回64位浮点数
        nan1_f64 = nan1_i64.view(np.float64)
        nan2_f64 = nan2_i64.view(np.float64)
        # 断言两个NaN在最大单位最小精度内的差异为0
        assert_array_max_ulp(nan1_f64, nan2_f64, 0)

    def test_float32_pass(self):
        # 定义单位最小精度的数量
        nulp = 5
        # 生成一个包含50个元素的浮点数数组,范围从-20到20
        x = np.linspace(-20, 20, 50, dtype=np.float32)
        # 对数组中的每个元素取10的幂
        x = 10**x
        # 在数组的前后添加相反数形成一个新的数组
        x = np.r_[-x, x]

        # 计算浮点数类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 构造与数组x相加后差异在几个单位最小精度内的数组y
        y = x + x*eps*nulp/2.
        # 断言数组x与数组y在指定单位最小精度内几乎相等
        assert_array_almost_equal_nulp(x, y, nulp)

        # 构造与数组x相减后差异在几个单位最小精度内的数组y
        epsneg = np.finfo(x.dtype).epsneg
        y = x - x*epsneg*nulp/2.
        # 断言数组x与数组y在指定单位最小精度内几乎相等
        assert_array_almost_equal_nulp(x, y, nulp)

    def test_float32_fail(self):
        # 定义单位最小精度的数量
        nulp = 5
        # 生成一个包含50个元素的浮点数数组,范围从-20到20
        x = np.linspace(-20, 20, 50, dtype=np.float32)
        # 对数组中的每个元素取10的幂
        x = 10**x
        # 在数组的前后添加相反数形成一个新的数组
        x = np.r_[-x, x]

        # 计算浮点数类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 构造与数组x相加后超出几个单位最小精度内的数组y
        y = x + x*eps*nulp*2.
        # 断言抛出AssertionError异常,因为数组x与数组y不在指定的单位最小精度内几乎相等
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)

        # 构造与数组x相减后超出几个单位最小精度内的数组y
        epsneg = np.finfo(x.dtype).epsneg
        y = x - x*epsneg*nulp*2.
        # 断言抛出AssertionError异常,因为数组x与数组y不在指定的单位最小精度内几乎相等
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)
    def test_float32_ignore_nan(self):
        # Ignore ULP differences between various NAN's
        # Note that MIPS may reverse quiet and signaling nans
        # so we use the builtin version as a base.
        
        # 定义偏移量为 0xffff,用于处理不同类型的 NaN 时的ULP差异
        offset = np.uint32(0xffff)
        
        # 创建一个 np.float32 类型的数组,视图转换为 np.uint32 类型
        nan1_i32 = np.array(np.nan, dtype=np.float32).view(np.uint32)
        
        # 对第一个 NaN 使用偏移量,MIPS架构下 NaN 的负载位为全 1
        nan2_i32 = nan1_i32 ^ offset  # nan payload on MIPS is all ones.
        
        # 将处理后的 NaN 转换回 np.float32 类型
        nan1_f32 = nan1_i32.view(np.float32)
        nan2_f32 = nan2_i32.view(np.float32)
        
        # 检查两个浮点数数组的最大 ULP(单位最小精度差异)
        assert_array_max_ulp(nan1_f32, nan2_f32, 0)

    def test_float16_pass(self):
        # 定义 NULP 的值为 5
        nulp = 5
        
        # 生成一个 np.float16 类型的数组 x,从 -4 到 4 之间等间距取 10 个数
        x = np.linspace(-4, 4, 10, dtype=np.float16)
        
        # 对数组 x 中的每个元素取 10 的 x 次方
        x = 10**x
        
        # 将数组 x 扩展为一个更大的数组,包含其相反数
        x = np.r_[-x, x]

        # 获取 x 数组的精度范围
        eps = np.finfo(x.dtype).eps
        
        # 计算浮点数数组 y,考虑 x 的 NULP 误差
        y = x + x*eps*nulp/2.
        
        # 检查两个浮点数数组 x 和 y 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(x, y, nulp)

        # 获取 x 数组的负精度范围
        epsneg = np.finfo(x.dtype).epsneg
        
        # 计算浮点数数组 y,考虑 x 的负 NULP 误差
        y = x - x*epsneg*nulp/2.
        
        # 检查两个浮点数数组 x 和 y 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(x, y, nulp)

    def test_float16_fail(self):
        # 定义 NULP 的值为 5
        nulp = 5
        
        # 生成一个 np.float16 类型的数组 x,从 -4 到 4 之间等间距取 10 个数
        x = np.linspace(-4, 4, 10, dtype=np.float16)
        
        # 对数组 x 中的每个元素取 10 的 x 次方
        x = 10**x
        
        # 将数组 x 扩展为一个更大的数组,包含其相反数
        x = np.r_[-x, x]

        # 获取 x 数组的精度范围
        eps = np.finfo(x.dtype).eps
        
        # 计算浮点数数组 y,考虑 x 的 NULP 误差的两倍
        y = x + x*eps*nulp*2.
        
        # 断言抛出异常,检查两个浮点数数组 x 和 y 的 NULP 误差是否小于等于 nulp
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)

        # 获取 x 数组的负精度范围
        epsneg = np.finfo(x.dtype).epsneg
        
        # 计算浮点数数组 y,考虑 x 的负 NULP 误差的两倍
        y = x - x*epsneg*nulp*2.
        
        # 断言抛出异常,检查两个浮点数数组 x 和 y 的 NULP 误差是否小于等于 nulp
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      x, y, nulp)

    def test_float16_ignore_nan(self):
        # Ignore ULP differences between various NAN's
        # Note that MIPS may reverse quiet and signaling nans
        # so we use the builtin version as a base.
        
        # 定义偏移量为 0xff,用于处理不同类型的 NaN 时的ULP差异
        offset = np.uint16(0xff)
        
        # 创建一个 np.float16 类型的数组,视图转换为 np.uint16 类型
        nan1_i16 = np.array(np.nan, dtype=np.float16).view(np.uint16)
        
        # 对第一个 NaN 使用偏移量,MIPS架构下 NaN 的负载位为全 1
        nan2_i16 = nan1_i16 ^ offset  # nan payload on MIPS is all ones.
        
        # 将处理后的 NaN 转换回 np.float16 类型
        nan1_f16 = nan1_i16.view(np.float16)
        nan2_f16 = nan2_i16.view(np.float16)
        
        # 检查两个浮点数数组的最大 ULP(单位最小精度差异)
        assert_array_max_ulp(nan1_f16, nan2_f16, 0)

    def test_complex128_pass(self):
        # 定义 NULP 的值为 5
        nulp = 5
        
        # 生成一个 np.float64 类型的数组 x,从 -20 到 20 之间等间距取 50 个数
        x = np.linspace(-20, 20, 50, dtype=np.float64)
        
        # 对数组 x 中的每个元素取 10 的 x 次方
        x = 10**x
        
        # 将数组 x 扩展为一个更大的数组,包含其相反数
        x = np.r_[-x, x]
        
        # 将数组 x 转换为复数数组 xi
        xi = x + x*1j

        # 获取 x 数组的精度范围
        eps = np.finfo(x.dtype).eps
        
        # 计算复数数组 y,考虑 x 的 NULP 误差
        y = x + x*eps*nulp/2.
        
        # 检查两个复数数组 xi 和 x + y*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, x + y*1j, nulp)
        
        # 检查两个复数数组 xi 和 y + x*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, y + x*1j, nulp)
        
        # 由于实部和虚部都发生变化,测试条件至少要小于 sqrt(2) 的因子
        y = x + x*eps*nulp/4.
        
        # 检查两个复数数组 xi 和 y + y*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, y + y*1j, nulp)

        # 获取 x 数组的负精度范围
        epsneg = np.finfo(x.dtype).epsneg
        
        # 计算复数数组 y,考虑 x 的负 NULP 误差
        y = x - x*epsneg*nulp/2.
        
        # 检查两个复数数组 xi 和 x + y*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, x + y*1j, nulp)
        
        # 检查两个复数数组 xi 和 y + x*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, y + x*1j, nulp)
        
        y = x - x*epsneg*nulp/4.
        
        # 检查两个复数数组 xi 和 y + y*1j 的 NULP 误差是否小于等于 nulp
        assert_array_almost_equal_nulp(xi, y
    # 定义一个测试函数,用于测试复数类型为 complex128 的情况,预期测试失败
    def test_complex128_fail(self):
        # 设置 Nulp 值为 5
        nulp = 5
        # 生成一个包含 50 个元素的浮点数数组,范围从 -20 到 20
        x = np.linspace(-20, 20, 50, dtype=np.float64)
        # 将数组 x 中的元素转换为 10 的指数值
        x = 10**x
        # 将数组 x 与其负值拼接形成新数组
        x = np.r_[-x, x]
        # 创建一个复数数组 xi,由 x 与 x 乘以虚数单位 1j 构成
        xi = x + x*1j

        # 获取数组 x 的数据类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 计算 y,将 x 与 x 乘以 eps 和 nulp*2 后相加
        y = x + x*eps*nulp*2.
        # 断言 xi 与 x + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, x + y*1j, nulp)
        # 断言 xi 与 y + x*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + x*1j, nulp)
        
        # 调整 y 的计算,以确保测试条件至少要比 sqrt(2) 小,因为实部和虚部都在变化
        y = x + x*eps*nulp
        # 断言 xi 与 y + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + y*1j, nulp)

        # 获取数组 x 的数据类型的负机器精度
        epsneg = np.finfo(x.dtype).epsneg
        # 计算 y,将 x 与 x 乘以 epsneg 和 nulp*2 后相减
        y = x - x*epsneg*nulp*2.
        # 断言 xi 与 x + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, x + y*1j, nulp)
        # 断言 xi 与 y + x*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + x*1j, nulp)
        
        # 调整 y 的计算,以确保测试条件至少要比 sqrt(2) 小,因为实部和虚部都在变化
        y = x - x*epsneg*nulp
        # 断言 xi 与 y + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + y*1j, nulp)

    # 定义一个测试函数,用于测试复数类型为 complex64 的情况,预期测试通过
    def test_complex64_pass(self):
        # 设置 Nulp 值为 5
        nulp = 5
        # 生成一个包含 50 个元素的浮点数数组,范围从 -20 到 20,数据类型为 np.float32
        x = np.linspace(-20, 20, 50, dtype=np.float32)
        # 将数组 x 中的元素转换为 10 的指数值
        x = 10**x
        # 将数组 x 与其负值拼接形成新数组
        x = np.r_[-x, x]
        # 创建一个复数数组 xi,由 x 与 x 乘以虚数单位 1j 构成
        xi = x + x*1j

        # 获取数组 x 的数据类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 计算 y,将 x 与 x 乘以 eps 和 nulp/2 后相加
        y = x + x*eps*nulp/2.
        # 断言 xi 与 x + y*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, x + y*1j, nulp)
        # 断言 xi 与 y + x*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, y + x*1j, nulp)
        
        # 调整 y 的计算,以确保测试通过
        y = x + x*eps*nulp/4.
        # 断言 xi 与 y + y*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, y + y*1j, nulp)

        # 获取数组 x 的数据类型的负机器精度
        epsneg = np.finfo(x.dtype).epsneg
        # 计算 y,将 x 与 x 乘以 epsneg 和 nulp/2 后相减
        y = x - x*epsneg*nulp/2.
        # 断言 xi 与 x + y*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, x + y*1j, nulp)
        # 断言 xi 与 y + x*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, y + x*1j, nulp)
        
        # 调整 y 的计算,以确保测试通过
        y = x - x*epsneg*nulp/4.
        # 断言 xi 与 y + y*1j 几乎相等,nulp 个单位
        assert_array_almost_equal_nulp(xi, y + y*1j, nulp)

    # 定义一个测试函数,用于测试复数类型为 complex64 的情况,预期测试失败
    def test_complex64_fail(self):
        # 设置 Nulp 值为 5
        nulp = 5
        # 生成一个包含 50 个元素的浮点数数组,范围从 -20 到 20,数据类型为 np.float32
        x = np.linspace(-20, 20, 50, dtype=np.float32)
        # 将数组 x 中的元素转换为 10 的指数值
        x = 10**x
        # 将数组 x 与其负值拼接形成新数组
        x = np.r_[-x, x]
        # 创建一个复数数组 xi,由 x 与 x 乘以虚数单位 1j 构成
        xi = x + x*1j

        # 获取数组 x 的数据类型的机器精度
        eps = np.finfo(x.dtype).eps
        # 计算 y,将 x 与 x 乘以 eps 和 nulp*2 后相加
        y = x + x*eps*nulp*2.
        # 断言 xi 与 x + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, x + y*1j, nulp)
        # 断言 xi 与 y + x*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + x*1j, nulp)
        
        # 调整 y 的计算,以确保测试条件至少要比 sqrt(2) 小,因为实部和虚部都在变化
        y = x + x*eps*nulp
        # 断言 xi 与 y + y*1j 几乎相等,nulp 个单位
        assert_raises(AssertionError, assert_array_almost_equal_nulp,
                      xi, y + y*1j, nulp)

        # 获取数组 x 的数据类型的负机器精度
        epsneg = np.finfo(x.dtype).epsneg
        # 计算 y,将 x 与 x 乘以 epsneg 和 nulp*2 后相减
        y = x - x*epsneg*nulp*2.
        #
class TestULP:

    def test_equal(self):
        # 生成一个包含10个随机数的数组
        x = np.random.randn(10)
        # 断言数组x与自身的最大ULP误差不超过0
        assert_array_max_ulp(x, x, maxulp=0)

    def test_single(self):
        # 生成一个包含10个单精度浮点数的数组,初始值为1,并添加小的随机浮动
        x = np.ones(10).astype(np.float32)
        x += 0.01 * np.random.randn(10).astype(np.float32)
        # 获取单精度浮点数的机器精度eps
        eps = np.finfo(np.float32).eps
        # 断言数组x与x加上eps之后的最大ULP误差不超过20
        assert_array_max_ulp(x, x+eps, maxulp=20)

    def test_double(self):
        # 生成一个包含10个双精度浮点数的数组,初始值为1,并添加小的随机浮动
        x = np.ones(10).astype(np.float64)
        x += 0.01 * np.random.randn(10).astype(np.float64)
        # 获取双精度浮点数的机器精度eps
        eps = np.finfo(np.float64).eps
        # 断言数组x与x加上eps之后的最大ULP误差不超过200
        assert_array_max_ulp(x, x+eps, maxulp=200)

    def test_inf(self):
        # 分别对单精度和双精度浮点数进行测试
        for dt in [np.float32, np.float64]:
            # 生成一个包含正无穷大的数组和一个包含浮点数dt类型最大值的数组
            inf = np.array([np.inf]).astype(dt)
            big = np.array([np.finfo(dt).max])
            # 断言inf数组与big数组的最大ULP误差不超过200
            assert_array_max_ulp(inf, big, maxulp=200)

    def test_nan(self):
        # 测试nan与各种值之间的ULP误差
        for dt in [np.float32, np.float64]:
            if dt == np.float32:
                maxulp = 1e6
            else:
                maxulp = 1e12
            # 生成包含正无穷大、nan、最大值、最小非负数、零、负零的数组
            inf = np.array([np.inf]).astype(dt)
            nan = np.array([np.nan]).astype(dt)
            big = np.array([np.finfo(dt).max])
            tiny = np.array([np.finfo(dt).tiny])
            zero = np.array([0.0]).astype(dt)
            nzero = np.array([-0.0]).astype(dt)
            # 断言nan与inf、big、tiny、zero、nzero数组的最大ULP误差不超过设定的maxulp
            assert_raises(AssertionError,
                          lambda: assert_array_max_ulp(nan, inf,
                                                       maxulp=maxulp))
            assert_raises(AssertionError,
                          lambda: assert_array_max_ulp(nan, big,
                                                       maxulp=maxulp))
            assert_raises(AssertionError,
                          lambda: assert_array_max_ulp(nan, tiny,
                                                       maxulp=maxulp))
            assert_raises(AssertionError,
                          lambda: assert_array_max_ulp(nan, zero,
                                                       maxulp=maxulp))
            assert_raises(AssertionError,
                          lambda: assert_array_max_ulp(nan, nzero,
                                                       maxulp=maxulp))


class TestStringEqual:
    def test_simple(self):
        # 断言两个字符串相等
        assert_string_equal("hello", "hello")
        assert_string_equal("hello\nmultiline", "hello\nmultiline")

        # 使用pytest断言异常类型为AssertionError,并检查异常信息是否符合预期
        with pytest.raises(AssertionError) as exc_info:
            assert_string_equal("foo\nbar", "hello\nbar")
        msg = str(exc_info.value)
        assert_equal(msg, "Differences in strings:\n- foo\n+ hello")

        # 使用assert_raises断言两个字符串不相等会触发AssertionError异常
        assert_raises(AssertionError,
                      lambda: assert_string_equal("foo", "hello"))
    # 定义一个测试方法,用于测试正则表达式的功能
    def test_regex(self):
        # 断言两个字符串相等,如果不相等则抛出 AssertionError
        assert_string_equal("a+*b", "a+*b")

        # 断言 lambda 表达式抛出指定的异常类型(AssertionError),如果不抛出则测试失败
        assert_raises(AssertionError,
                      lambda: assert_string_equal("aaa", "a+b"))
# 检查模块是否具有 __warningregistry__ 属性,获取其中的警告信息字典
try:
    mod_warns = mod.__warningregistry__
except AttributeError:
    # 如果模块缺少 __warningregistry__ 属性,则说明没有警告发生;
    # 这种情况可能发生在并行测试场景中,在串行测试场景中,初始警告(因此属性)总是首先创建的
    mod_warns = {}

# 获取当前警告的数量
num_warns = len(mod_warns)

# 如果警告字典中有 'version' 键,Python 3 会向注册表中添加一个 'version' 条目,不计入警告数量
if 'version' in mod_warns:
    num_warns -= 1

# 断言当前警告的数量与期望的数量 n_in_context 相等
assert_equal(num_warns, n_in_context)


def test_warn_len_equal_call_scenarios():
    # assert_warn_len_equal 在不同情境下被调用,取决于串行 vs 并行测试场景;
    # 本测试旨在探索两种代码路径,并检查是否有断言未被捕获

    # 并行测试场景 -- 尚未发出警告
    class mod:
        pass

    mod_inst = mod()

    assert_warn_len_equal(mod=mod_inst,
                          n_in_context=0)

    # 串行测试场景 -- 应该存在 __warningregistry__ 属性
    class mod:
        def __init__(self):
            self.__warningregistry__ = {'warning1': 1,
                                        'warning2': 2}

    mod_inst = mod()
    assert_warn_len_equal(mod=mod_inst,
                          n_in_context=2)


def _get_fresh_mod():
    # 获取当前模块,并清空警告注册表
    my_mod = sys.modules[__name__]
    try:
        my_mod.__warningregistry__.clear()
    except AttributeError:
        # 除非模块中曾经引发过警告,否则不会有 __warningregistry__
        pass
    return my_mod


def test_clear_and_catch_warnings():
    # 模块的初始状态,没有警告
    my_mod = _get_fresh_mod()
    assert_equal(getattr(my_mod, '__warningregistry__', {}), {})
    
    # 在指定模块下,清除并捕获警告
    with clear_and_catch_warnings(modules=[my_mod]):
        warnings.simplefilter('ignore')
        warnings.warn('Some warning')
    assert_equal(my_mod.__warningregistry__, {})
    
    # 在未指定模块的情况下,不在上下文期间清除警告
    # catch_warnings 对 'ignore' 不会做出记录
    with clear_and_catch_warnings():
        warnings.simplefilter('ignore')
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)

    # 手动向注册表中添加两个警告
    my_mod.__warningregistry__ = {'warning1': 1,
                                  'warning2': 2}

    # 确认指定模块保留旧警告,并且不添加新警告
    with clear_and_catch_warnings(modules=[my_mod]):
        warnings.simplefilter('ignore')
        warnings.warn('Another warning')
    assert_warn_len_equal(my_mod, 2)

    # 另一个警告,没有指定模块,它会清理注册表
    # 使用 clear_and_catch_warnings() 上下文管理器,用于捕获和清除警告
    with clear_and_catch_warnings():
        # 设置警告过滤器,忽略所有警告
        warnings.simplefilter('ignore')
        # 发出一个自定义警告消息 'Another warning'
        warnings.warn('Another warning')
    
    # 断言语句,验证 my_mod 的警告数量是否等于 0
    assert_warn_len_equal(my_mod, 0)
def test_suppress_warnings_module():
    # 初始状态下,模块没有警告
    my_mod = _get_fresh_mod()
    # 断言确保模块的 __warningregistry__ 属性为空字典
    assert_equal(getattr(my_mod, '__warningregistry__', {}), {})

    def warn_other_module():
        # apply_along_axis 在 Python 中实现;stacklevel=2 表示
        # 我们会在其模块内部执行,而不是在我们的模块内部。
        def warn(arr):
            # 发出警告 "Some warning 2",stacklevel=2 表示警告来自于调用栈的上一层
            warnings.warn("Some warning 2", stacklevel=2)
            return arr
        np.apply_along_axis(warn, 0, [0])

    # 测试基于模块的警告抑制:
    assert_warn_len_equal(my_mod, 0)
    with suppress_warnings() as sup:
        sup.record(UserWarning)
        # 抑制来自其他模块的警告(可能以 .pyc 结尾),
        # 如果 apply_along_axis 被移动,这里需要修改。
        sup.filter(module=np.lib._shape_base_impl)
        warnings.warn("Some warning")
        warn_other_module()
    # 检查抑制是否正确测试了文件(本模块被过滤)
    assert_equal(len(sup.log), 1)
    assert_equal(sup.log[0].message.args[0], "Some warning")
    assert_warn_len_equal(my_mod, 0)
    sup = suppress_warnings()
    # 如果 apply_along_axis 被移动,这里需要修改:
    sup.filter(module=my_mod)
    with sup:
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)
    # 并且测试重复是否有效:
    sup.filter(module=my_mod)
    with sup:
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)

    # 没有指定模块时
    with suppress_warnings():
        warnings.simplefilter('ignore')
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)


def test_suppress_warnings_type():
    # 初始状态下,模块没有警告
    my_mod = _get_fresh_mod()
    assert_equal(getattr(my_mod, '__warningregistry__', {}), {})

    # 测试基于类型的警告抑制:
    with suppress_warnings() as sup:
        sup.filter(UserWarning)
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)
    sup = suppress_warnings()
    sup.filter(UserWarning)
    with sup:
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)
    # 并且测试重复是否有效:
    sup.filter(module=my_mod)
    with sup:
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)

    # 没有指定模块时
    with suppress_warnings():
        warnings.simplefilter('ignore')
        warnings.warn('Some warning')
    assert_warn_len_equal(my_mod, 0)


def test_suppress_warnings_decorate_no_record():
    sup = suppress_warnings()
    sup.filter(UserWarning)

    @sup
    def warn(category):
        warnings.warn('Some warning', category)

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        warn(UserWarning)  # 应该被抑制
        warn(RuntimeWarning)
        assert_equal(len(w), 1)


def test_suppress_warnings_record():
    sup = suppress_warnings()
    log1 = sup.record()
    # 使用上下文管理器 `sup` 来捕获警告信息和操作
    with sup:
        # 记录一条警告消息到 `log2`
        log2 = sup.record(message='Some other warning 2')
        # 过滤掉特定消息为 'Some warning' 的警告
        sup.filter(message='Some warning')
        # 发出一条 'Some warning' 的警告
        warnings.warn('Some warning')
        # 发出一条 'Some other warning' 的警告
        warnings.warn('Some other warning')
        # 再次发出一条 'Some other warning 2' 的警告
        warnings.warn('Some other warning 2')

        # 断言捕获的警告日志条数为 2
        assert_equal(len(sup.log), 2)
        # 断言 `log1` 的长度为 1
        assert_equal(len(log1), 1)
        # 断言 `log2` 的长度为 1
        assert_equal(len(log2), 1)
        # 断言 `log2` 中的第一条消息的参数为 'Some other warning 2'
        assert_equal(log2[0].message.args[0], 'Some other warning 2')

    # 再次使用相同的上下文 `sup` 来测试警告是否被正确捕获:
    with sup:
        # 记录一条 'Some other warning 2' 的警告消息到 `log2`
        log2 = sup.record(message='Some other warning 2')
        # 过滤掉特定消息为 'Some warning' 的警告
        sup.filter(message='Some warning')
        # 发出一条 'Some warning' 的警告
        warnings.warn('Some warning')
        # 发出一条 'Some other warning' 的警告
        warnings.warn('Some other warning')
        # 再次发出一条 'Some other warning 2' 的警告
        warnings.warn('Some other warning 2')

        # 断言捕获的警告日志条数为 2
        assert_equal(len(sup.log), 2)
        # 断言 `log1` 的长度为 1
        assert_equal(len(log1), 1)
        # 断言 `log2` 的长度为 1
        assert_equal(len(log2), 1)
        # 断言 `log2` 中的第一条消息的参数为 'Some other warning 2'
        assert_equal(log2[0].message.args[0], 'Some other warning 2')

    # 测试嵌套情况下的警告捕获:
    with suppress_warnings() as sup:
        # 记录当前上下文中的警告
        sup.record()
        # 嵌套使用另一个 `suppress_warnings` 上下文 `sup2`
        with suppress_warnings() as sup2:
            # 记录一条 'Some warning' 的警告消息到 `sup2` 的日志中
            sup2.record(message='Some warning')
            # 发出一条 'Some warning' 的警告
            warnings.warn('Some warning')
            # 发出一条 'Some other warning' 的警告
            warnings.warn('Some other warning')
            # 断言 `sup2` 日志中的条目数量为 1
            assert_equal(len(sup2.log), 1)
        # 断言 `sup` 日志中的条目数量为 1
        assert_equal(len(sup.log), 1)
# 定义一个测试函数,用于测试警告抑制和转发
def test_suppress_warnings_forwarding():
    # 定义一个内部函数,用于发出警告
    def warn_other_module():
        # warn 函数发出警告信息:"Some warning",stacklevel=2 表示警告位置在其模块内部
        def warn(arr):
            warnings.warn("Some warning", stacklevel=2)
            return arr
        # 应用 np.apply_along_axis 函数,对数组应用 warn 函数
        np.apply_along_axis(warn, 0, [0])

    # 使用 suppress_warnings 上下文管理器,捕获并记录警告
    with suppress_warnings() as sup:
        # 记录当前的警告状态
        sup.record()
        # 在 "always" 模式下抑制警告
        with suppress_warnings("always"):
            # 循环发出两次警告信息:"Some warning"
            for i in range(2):
                warnings.warn("Some warning")
        # 断言捕获到的警告数量为 2
        assert_equal(len(sup.log), 2)

    with suppress_warnings() as sup:
        sup.record()
        # 在 "location" 模式下抑制警告
        with suppress_warnings("location"):
            # 循环发出两次警告信息:"Some warning"
            for i in range(2):
                warnings.warn("Some warning")
                # 再次发出一次警告信息:"Some warning"
                warnings.warn("Some warning")
        # 断言捕获到的警告数量为 2
        assert_equal(len(sup.log), 2)

    with suppress_warnings() as sup:
        sup.record()
        # 在 "module" 模式下抑制警告
        with suppress_warnings("module"):
            # 循环发出两次警告信息:"Some warning"
            for i in range(2):
                warnings.warn("Some warning")
                # 再次发出一次警告信息:"Some warning"
                warnings.warn("Some warning")
                # 调用外部函数发出警告
                warn_other_module()
        # 断言捕获到的警告数量为 2
        assert_equal(len(sup.log), 2)

    with suppress_warnings() as sup:
        sup.record()
        # 在 "once" 模式下抑制警告
        with suppress_warnings("once"):
            # 循环发出两次警告信息:"Some warning" 和 "Some other warning"
            for i in range(2):
                warnings.warn("Some warning")
                warnings.warn("Some other warning")
                # 调用外部函数发出警告
                warn_other_module()
        # 断言捕获到的警告数量为 2
        assert_equal(len(sup.log), 2)


# 测试临时目录管理器的功能
def test_tempdir():
    # 在 tempdir 上下文中创建临时目录 tdir
    with tempdir() as tdir:
        # 在 tdir 中创建临时文件 'tmp'
        fpath = os.path.join(tdir, 'tmp')
        with open(fpath, 'w'):
            pass
    # 断言 tdir 不再存在
    assert_(not os.path.isdir(tdir))

    raised = False
    try:
        with tempdir() as tdir:
            # 在 tempdir 上下文中抛出 ValueError 异常
            raise ValueError()
    except ValueError:
        raised = True
    # 断言捕获到异常,并且 tdir 不再存在
    assert_(raised)
    assert_(not os.path.isdir(tdir))


# 测试临时文件路径管理器的功能
def test_temppath():
    # 在 temppath 上下文中创建临时文件路径 fpath
    with temppath() as fpath:
        # 在 fpath 中创建临时文件
        with open(fpath, 'w'):
            pass
    # 断言 fpath 不再存在
    assert_(not os.path.isfile(fpath))

    raised = False
    try:
        with temppath() as fpath:
            # 在 temppath 上下文中抛出 ValueError 异常
            raise ValueError()
    except ValueError:
        raised = True
    # 断言捕获到异常,并且 fpath 不再存在
    assert_(raised)
    assert_(not os.path.isfile(fpath))


# 自定义的警告清除和捕获上下文管理器
class my_cacw(clear_and_catch_warnings):

    # 指定要处理的模块,这里处理当前模块
    class_modules = (sys.modules[__name__],)


# 测试自定义警告清除和捕获上下文管理器的继承行为
def test_clear_and_catch_warnings_inherit():
    # 获取一个新的模块对象
    my_mod = _get_fresh_mod()
    # 在 my_cacw 上下文中使用警告清除和捕获功能
    with my_cacw():
        # 忽略所有警告
        warnings.simplefilter('ignore')
        # 发出一条警告信息:"Some warning"
        warnings.warn('Some warning')
    # 断言当前模块的警告注册表为空字典
    assert_equal(my_mod.__warningregistry__, {})


# 使用 pytest 的条件标记,如果没有 refcount 功能则跳过该测试
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
class TestAssertNoGcCycles:
    """ Test assert_no_gc_cycles """

    def test_passes(self):
        # 内部函数,创建一个无循环引用的对象
        def no_cycle():
            b = []
            b.append([])
            return b

        # 使用 assert_no_gc_cycles 上下文管理器,测试无循环引用的情况
        with assert_no_gc_cycles():
            no_cycle()

        # 使用 assert_no_gc_cycles 函数,直接测试无循环引用的情况
        assert_no_gc_cycles(no_cycle)
    def test_asserts(self):
        # 定义一个函数,创建一个包含自身引用的循环列表
        def make_cycle():
            a = []
            a.append(a)
            a.append(a)
            return a

        # 测试断言:期望抛出 AssertionError
        with assert_raises(AssertionError):
            # 断言在不产生垃圾循环的情况下执行 make_cycle 函数
            with assert_no_gc_cycles():
                make_cycle()

        # 另一种测试断言:期望抛出 AssertionError
        with assert_raises(AssertionError):
            # 断言在不产生垃圾循环的情况下执行 make_cycle 函数
            assert_no_gc_cycles(make_cycle)

    @pytest.mark.slow
    def test_fails(self):
        """
        Test that in cases where the garbage cannot be collected, we raise an
        error, instead of hanging forever trying to clear it.
        """
        
        # 定义一个带有 __del__ 方法的类,创建并释放引用循环的对象
        class ReferenceCycleInDel:
            """
            An object that not only contains a reference cycle, but creates new
            cycles whenever it's garbage-collected and its __del__ runs
            """
            make_cycle = True

            def __init__(self):
                self.cycle = self

            def __del__(self):
                # 断开当前循环,以便可以释放 self 对象
                self.cycle = None

                if ReferenceCycleInDel.make_cycle:
                    # 但创建一个新的循环,使得垃圾收集器需要更多工作
                    ReferenceCycleInDel()

        try:
            # 创建一个对 ReferenceCycleInDel 对象的弱引用
            w = weakref.ref(ReferenceCycleInDel())
            try:
                with assert_raises(RuntimeError):
                    # 尝试在无基准空闲垃圾的情况下执行 assert_no_gc_cycles
                    assert_no_gc_cycles(lambda: None)
            except AssertionError:
                # 如果垃圾收集器尝试释放我们的对象,才需要进行上述测试
                if w() is not None:
                    pytest.skip("GC does not call __del__ on cyclic objects")
                    raise

        finally:
            # 确保停止创建引用循环
            ReferenceCycleInDel.make_cycle = False
# 使用 pytest.mark.parametrize 装饰器,参数化测试函数 assert_func,以便多次运行测试用例
@pytest.mark.parametrize('assert_func', [assert_array_equal,
                                         assert_array_almost_equal])
def test_xy_rename(assert_func):
    # 测试关键字 `x` 和 `y` 是否已重命名为 `actual` 和 `desired`,这些测试和 `_rename_parameter` 装饰器在 NumPy 2.2.0 发布之前可以移除
    assert_func(1, 1)
    assert_func(actual=1, desired=1)

    # 断言消息字符串,指示数组不相等的情况
    assert_message = "Arrays are not..."
    # 使用 pytest.raises 检查断言错误,确保抛出 Assertion Error,并匹配特定消息
    with pytest.raises(AssertionError, match=assert_message):
        assert_func(1, 2)
    with pytest.raises(AssertionError, match=assert_message):
        assert_func(actual=1, desired=2)

    # 警告消息字符串,指示关键字参数的使用已不推荐
    dep_message = 'Use of keyword argument...'
    # 使用 pytest.warns 检查是否抛出 DeprecationWarning,并匹配特定的警告消息
    with pytest.warns(DeprecationWarning, match=dep_message):
        assert_func(x=1, desired=1)
    with pytest.warns(DeprecationWarning, match=dep_message):
        assert_func(1, y=1)

    # 类型错误消息字符串,指示函数调用中参数重复赋值
    type_message = '...got multiple values for argument'
    # 显式使用换行以支持 Python 3.9,同时检查是否抛出 DeprecationWarning 和 TypeError,并匹配特定的警告和错误消息
    with pytest.warns(DeprecationWarning, match=dep_message), \
          pytest.raises(TypeError, match=type_message):
        assert_func(1, x=1)
        assert_func(1, 2, y=2)