NumPy-源码解析-三十三-

76 阅读1小时+

NumPy 源码解析(三十三)

.\numpy\numpy\polynomial\legendre.py

"""
==================================================
Legendre Series (:mod:`numpy.polynomial.legendre`)
==================================================

This module provides a number of objects (mostly functions) useful for
dealing with Legendre series, including a `Legendre` class that
encapsulates the usual arithmetic operations.  (General information
on how this module represents and works with such polynomials is in the
docstring for its "parent" sub-package, `numpy.polynomial`).

Classes
-------
.. autosummary::
   :toctree: generated/

    Legendre

Constants
---------

.. autosummary::
   :toctree: generated/

   legdomain
   legzero
   legone
   legx

Arithmetic
----------

.. autosummary::
   :toctree: generated/

   legadd
   legsub
   legmulx
   legmul
   legdiv
   legpow
   legval
   legval2d
   legval3d
   leggrid2d
   leggrid3d

Calculus
--------

.. autosummary::
   :toctree: generated/

   legder
   legint

Misc Functions
--------------

.. autosummary::
   :toctree: generated/

   legfromroots
   legroots
   legvander
   legvander2d
   legvander3d
   leggauss
   legweight
   legcompanion
   legfit
   legtrim
   legline
   leg2poly
   poly2leg

See also
--------
numpy.polynomial

"""
import numpy as np
import numpy.linalg as la
from numpy.lib.array_utils import normalize_axis_index

from . import polyutils as pu
from ._polybase import ABCPolyBase

__all__ = [
    'legzero', 'legone', 'legx', 'legdomain', 'legline', 'legadd',
    'legsub', 'legmulx', 'legmul', 'legdiv', 'legpow', 'legval', 'legder',
    'legint', 'leg2poly', 'poly2leg', 'legfromroots', 'legvander',
    'legfit', 'legtrim', 'legroots', 'Legendre', 'legval2d', 'legval3d',
    'leggrid2d', 'leggrid3d', 'legvander2d', 'legvander3d', 'legcompanion',
    'leggauss', 'legweight']

# 使用pu模块中的trimcoef函数,将其赋值给全局变量legtrim
legtrim = pu.trimcoef


def poly2leg(pol):
    """
    Convert a polynomial to a Legendre series.

    Convert an array representing the coefficients of a polynomial (relative
    to the "standard" basis) ordered from lowest degree to highest, to an
    array of the coefficients of the equivalent Legendre series, ordered
    from lowest to highest degree.

    Parameters
    ----------
    pol : array_like
        1-D array containing the polynomial coefficients

    Returns
    -------
    c : ndarray
        1-D array containing the coefficients of the equivalent Legendre
        series.

    See Also
    --------
    leg2poly

    Notes
    -----
    The easy way to do conversions between polynomial basis sets
    is to use the convert method of a class instance.

    Examples
    --------
    >>> from numpy import polynomial as P
    >>> p = P.Polynomial(np.arange(4))
    >>> p
    Polynomial([0.,  1.,  2.,  3.], domain=[-1.,  1.], window=[-1.,  1.], ...
    >>> c = P.Legendre(P.legendre.poly2leg(p.coef))
    >>> c
    Legendre([ 1.  ,  3.25,  1.  ,  0.75], domain=[-1,  1], window=[-1,  1]) # may vary

    """
    # 将输入的多项式系数转换为系列(series)
    [pol] = pu.as_series([pol])
    # 计算多项式的最高次数
    deg = len(pol) - 1
    # 初始化结果为0
    res = 0
    # 从最高次数 deg 到常数项 0 逐步计算多项式的值
    for i in range(deg, -1, -1):
        # 使用 legmulx 函数将当前结果 res 乘以 x,然后使用 legadd 函数加上 pol[i] 多项式
        res = legadd(legmulx(res), pol[i])
    # 返回计算后的多项式结果 res
    return res
def leg2poly(c):
    """
    Convert a Legendre series to a polynomial.

    Convert an array representing the coefficients of a Legendre series,
    ordered from lowest degree to highest, to an array of the coefficients
    of the equivalent polynomial (relative to the "standard" basis) ordered
    from lowest to highest degree.

    Parameters
    ----------
    c : array_like
        1-D array containing the Legendre series coefficients, ordered
        from lowest order term to highest.

    Returns
    -------
    pol : ndarray
        1-D array containing the coefficients of the equivalent polynomial
        (relative to the "standard" basis) ordered from lowest order term
        to highest.

    See Also
    --------
    poly2leg

    Notes
    -----
    The easy way to do conversions between polynomial basis sets
    is to use the convert method of a class instance.

    Examples
    --------
    >>> from numpy import polynomial as P
    >>> c = P.Legendre(range(4))
    >>> c
    Legendre([0., 1., 2., 3.], domain=[-1.,  1.], window=[-1.,  1.], symbol='x')
    >>> p = c.convert(kind=P.Polynomial)
    >>> p
    Polynomial([-1. , -3.5,  3. ,  7.5], domain=[-1.,  1.], window=[-1., ...
    >>> P.legendre.leg2poly(range(4))
    array([-1. , -3.5,  3. ,  7.5])


    """
    from .polynomial import polyadd, polysub, polymulx  # 导入多项式运算函数

    [c] = pu.as_series([c])  # 确保c是一个系列对象
    n = len(c)  # 获取系列的长度
    if n < 3:  # 如果系列长度小于3
        return c  # 直接返回系列c
    else:
        c0 = c[-2]  # 设置初始值c0为系列倒数第二项
        c1 = c[-1]  # 设置初始值c1为系列最后一项
        # i 是当前 c1 的阶数
        for i in range(n - 1, 1, -1):  # 从n-1到1逆序遍历
            tmp = c0  # 临时变量tmp为c0
            c0 = polysub(c[i - 2], (c1*(i - 1))/i)  # 更新c0为c[i-2]减去(c1*(i-1))/i
            c1 = polyadd(tmp, (polymulx(c1)*(2*i - 1))/i)  # 更新c1为tmp加上(polymulx(c1)*(2*i-1))/i
        return polyadd(c0, polymulx(c1))  # 返回c0与polymulx(c1)的和


#
# These are constant arrays are of integer type so as to be compatible
# with the widest range of other types, such as Decimal.
#

# Legendre
legdomain = np.array([-1., 1.])  # 定义Legendre多项式的定义域

# Legendre coefficients representing zero.
legzero = np.array([0])  # 定义表示零的Legendre系数数组

# Legendre coefficients representing one.
legone = np.array([1])  # 定义表示一的Legendre系数数组

# Legendre coefficients representing the identity x.
legx = np.array([0, 1])  # 定义表示x的Legendre系数数组


def legline(off, scl):
    """
    Legendre series whose graph is a straight line.

    Parameters
    ----------
    off, scl : scalars
        The specified line is given by ``off + scl*x``.

    Returns
    -------
    y : ndarray
        This module's representation of the Legendre series for
        ``off + scl*x``.

    See Also
    --------
    numpy.polynomial.polynomial.polyline
    numpy.polynomial.chebyshev.chebline
    numpy.polynomial.laguerre.lagline
    numpy.polynomial.hermite.hermline
    numpy.polynomial.hermite_e.hermeline

    Examples
    --------
    >>> import numpy.polynomial.legendre as L
    >>> L.legline(3,2)
    array([3, 2])
    >>> L.legval(-3, L.legline(3,2)) # should be -3
    -3.0

    """
    if scl != 0:
        return np.array([off, scl])  # 如果scl不等于0,返回数组[off, scl]
    else:
        return np.array([off])  # 如果scl等于0,返回数组[off]


def legfromroots(roots):
    """
    """
    Generate a Legendre series with given roots.

    The function returns the coefficients of the polynomial

    .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n),

    in Legendre form, where the :math:`r_n` are the roots specified in `roots`.
    If a zero has multiplicity n, then it must appear in `roots` n times.
    For instance, if 2 is a root of multiplicity three and 3 is a root of
    multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The
    roots can appear in any order.

    If the returned coefficients are `c`, then

    .. math:: p(x) = c_0 + c_1 * L_1(x) + ... +  c_n * L_n(x)

    The coefficient of the last term is not generally 1 for monic
    polynomials in Legendre form.

    Parameters
    ----------
    roots : array_like
        Sequence containing the roots.

    Returns
    -------
    out : ndarray
        1-D array of coefficients.  If all roots are real then `out` is a
        real array, if some of the roots are complex, then `out` is complex
        even if all the coefficients in the result are real (see Examples
        below).

    See Also
    --------
    numpy.polynomial.polynomial.polyfromroots
    numpy.polynomial.chebyshev.chebfromroots
    numpy.polynomial.laguerre.lagfromroots
    numpy.polynomial.hermite.hermfromroots
    numpy.polynomial.hermite_e.hermefromroots

    Examples
    --------
    >>> import numpy.polynomial.legendre as L
    >>> L.legfromroots((-1,0,1)) # x^3 - x relative to the standard basis
    array([ 0. , -0.4,  0. ,  0.4])
    >>> j = complex(0,1)
    >>> L.legfromroots((-j,j)) # x^2 + 1 relative to the standard basis
    array([ 1.33333333+0.j,  0.00000000+0.j,  0.66666667+0.j]) # may vary

    """
    # 使用传入的 roots 参数调用内部函数 _fromroots,生成 Legendre 多项式的系数
    return pu._fromroots(legline, legmul, roots)
# 将两个 Legendre 级数相加。

# 返回两个 Legendre 级数 `c1` + `c2` 的和。参数 `c1` 和 `c2` 是按从低到高排序的系数序列,
# 比如,[1,2,3] 表示级数 ``P_0 + 2*P_1 + 3*P_2``。

# 导入必要的包 numpy.polynomial.legendre as L
# c1 和 c2:Legendre 级数系数的 1-D 数组,按从低到高排序。

# 返回
# -------
# out : ndarray
#     表示它们的和的 Legendre 级数的数组。

# See Also
# --------
# legsub, legmulx, legmul, legdiv, legpow

# Notes
# -----
# 与乘法、除法等不同,两个 Legendre 级数的和是一个 Legendre 级数(不需要将结果“重新投影”到基函数集中),
# 因此加法,就像“标准”多项式一样,只是“分量方式”。

# Examples
# --------
# >>> from numpy.polynomial import legendre as L
# >>> c1 = (1,2,3)
# >>> c2 = (3,2,1)
# >>> L.legadd(c1,c2)
# array([4.,  4.,  4.])



# 将一个 Legendre 级数从另一个中减去。

# 返回两个 Legendre 级数 `c1` - `c2` 的差。系数序列是按从低到高排序的,
# 比如,[1,2,3] 表示级数 ``P_0 + 2*P_1 + 3*P_2``。

# Parameters
# ----------
# c1, c2 : array_like
#     1-D 数组的 Legendre 级数系数,按从低到高排序。

# Returns
# -------
# out : ndarray
#     表示它们的差的 Legendre 级数系数。

# See Also
# --------
# legadd, legmulx, legmul, legdiv, legpow

# Notes
# -----
# 与乘法、除法等不同,两个 Legendre 级数的差是一个 Legendre 级数(不需要将结果“重新投影”到基函数集中),
# 因此减法,就像“标准”多项式一样,只是“分量方式”。

# Examples
# --------
# >>> from numpy.polynomial import legendre as L
# >>> c1 = (1,2,3)
# >>> c2 = (3,2,1)
# >>> L.legsub(c1,c2)
# array([-2.,  0.,  2.])
# >>> L.legsub(c2,c1) # -C.legsub(c1,c2)
# array([ 2.,  0., -2.])



# 将 Legendre 级数乘以 x。

# 将 Legendre 级数 `c` 乘以 x,其中 x 是自变量。

# Parameters
# ----------
# c : array_like
#     按从低到高排序的 1-D 数组的 Legendre 级数系数。

# Returns
# -------
# out : ndarray
#     表示乘法结果的数组。

# See Also
# --------
# legadd, legsub, legmul, legdiv, legpow

# Notes
# -----
# 乘法使用 Legendre 多项式的递归关系形式

# .. math::

#   xP_i(x) = ((i + 1)*P_{i + 1}(x) + i*P_{i - 1}(x))/(2i + 1)

# Examples
# --------
# >>> from numpy.polynomial import legendre as L
# >>> L.legmulx([1,2,3])
    array([ 0.66666667, 2.2, 1.33333333, 1.8]) # may vary

    """
    # 创建一个包含浮点数的数组,实际数值可能会有所不同
    # 这里的数组表示可能是某个算法或计算过程中的输出结果
    # 数组的具体含义和用途需要结合上下文来理解
    # 如果这是函数的返回值,则这个数组将被返回给调用方
    # 可能需要根据上下文进一步推断数组的具体作用和含义
    # 如果这个数组作为某个更大计算过程的一部分,可能需要查看上下文以获取更多信息
    [c] = pu.as_series([c])
    # 创建一个包含单个元素的列表,元素是经过处理的输入参数 c 的序列
    # 如果输入参数 c 是一个标量,将其转换为一个序列以便进行后续处理
    # 如果 c 是一个序列,则保持不变
    # 本行代码确保了后续操作始终能够处理 c 作为序列的情况

    # 需要特殊处理的情况是零序列
    if len(c) == 1 and c[0] == 0:
        # 如果 c 的长度为 1,并且唯一的元素是 0,则直接返回 c
        return c

    # 创建一个与 c 长度加一相同的空数组,数组的数据类型与 c 相同
    prd = np.empty(len(c) + 1, dtype=c.dtype)
    # 将第一个元素设置为 c 的第一个元素乘以 0
    prd[0] = c[0]*0
    # 将第二个元素设置为 c 的第一个元素
    prd[1] = c[0]
    # 遍历 c 中的每个元素,计算 prd 数组中对应的值
    for i in range(1, len(c)):
        j = i + 1
        k = i - 1
        s = i + j
        # 计算 prd 数组的第 j 个元素值
        prd[j] = (c[i]*j)/s
        # 将 c 的第 i 个元素乘以 i/s 加到 prd 数组的第 k 个元素上
        prd[k] += (c[i]*i)/s
    # 返回计算结果数组 prd
    return prd
    """
def legdiv(c1, c2):
    """
    Divide one Legendre series by another.

    Returns the quotient-with-remainder of two Legendre series
    `c1` / `c2`.  The arguments are sequences of coefficients from lowest
    order "term" to highest, e.g., [1,2,3] represents the series
    ``P_0 + 2*P_1 + 3*P_2``.

    Parameters
    ----------
    c1, c2 : array_like
        1-D arrays of Legendre series coefficients ordered from low to
        high.

    Returns
    -------
    quo, rem : ndarrays
        Of Legendre series coefficients representing the quotient and
        remainder.

    See Also
    --------
    legadd, legsub, legmulx, legmul, legpow

    Notes
    -----
    In general, the (polynomial) division of one Legendre series by another
    results in quotient and remainder terms that are not in the Legendre
    polynomial basis set.  Thus, to express these results as a Legendre
    series, it is necessary to "reproject" the results onto the Legendre
    basis set, which may produce "unintuitive" (but correct) results; see
    Examples section below.

    Examples
    --------
    >>> from numpy.polynomial import legendre as L
    """
    # s1, s2 are trimmed copies
    [c1, c2] = pu.as_series([c1, c2])

    # Determine the smaller and larger series
    if len(c1) > len(c2):
        c = c2
        xs = c1
    else:
        c = c1
        xs = c2

    # Handle division for different lengths of c
    if len(c) == 1:
        c0 = c[0] / xs
        c1 = 0
    elif len(c) == 2:
        c0 = c[0] / xs
        c1 = c[1] / xs
    else:
        nd = len(c)
        c0 = c[-2] / xs
        c1 = c[-1] / xs
        for i in range(3, len(c) + 1):
            tmp = c0
            nd = nd - 1
            c0 = legsub(c[-i] / xs, (c1 * (nd - 1)) / nd)
            c1 = legadd(tmp, (legmulx(c1) * (2 * nd - 1)) / nd)

    # Return the result of the division as a Legendre series
    return legadd(c0, legmulx(c1))
    # 定义两个元组 c1 和 c2,表示为 (1,2,3) 和 (3,2,1)
    >>> c1 = (1,2,3)
    >>> c2 = (3,2,1)
    # 调用 L 对象的 legdiv 方法,对 c1 和 c2 进行 Legendre 多项式的除法运算,返回商和余数
    >>> L.legdiv(c1,c2) # quotient "intuitive," remainder not
    # 返回结果为 (array([3.]), array([-8., -4.])),第一个数组是商,第二个数组是余数
    (array([3.]), array([-8., -4.]))
    # 修改 c2 的值为 (0,1,2,3),重新调用 legdiv 方法进行除法运算
    >>> c2 = (0,1,2,3)
    # 返回结果为 (array([-0.07407407,  1.66666667]), array([-1.03703704, -2.51851852])),可能会有变化
    >>> L.legdiv(c2,c1) # neither "intuitive"
    # 返回结果分别是商和余数,注意这里的结果可能会有所不同
    (array([-0.07407407,  1.66666667]), array([-1.03703704, -2.51851852])) # may vary

    """
    # 调用 pu 对象的 _div 方法,进行 Legendre 多项式的除法运算,传入的参数是 legmul, c1, c2
    return pu._div(legmul, c1, c2)
def legder(c, m=1, scl=1, axis=0):
    """
    Differentiate a Legendre series.

    Returns the Legendre series coefficients `c` differentiated `m` times
    along `axis`.  At each iteration the result is multiplied by `scl` (the
    scaling factor is for use in a linear change of variable). The argument
    `c` is an array of coefficients from low to high degree along each
    axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2``
    while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) +
    2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is
    ``y``.

    Parameters
    ----------
    c : array_like
        Array of Legendre series coefficients. If c is multidimensional the
        different axis correspond to different variables with the degree in
        each axis given by the corresponding index.
    m : int, optional
        Number of derivatives taken, must be non-negative. (Default: 1)
    scl : scalar, optional
        Each differentiation is multiplied by `scl`.  The end result is
        multiplication by ``scl**m``.  This is for use in a linear change of
        variable. (Default: 1)
    axis : int, optional
        Axis over which the derivative is taken. (Default: 0).

        .. versionadded:: 1.7.0

    Returns
    -------
    der : ndarray
        Legendre series of the derivative.

    See Also
    --------
    legint

    Notes
    -----
    In general, the result of differentiating a Legendre series does not
    resemble the same operation on a power series. Thus the result of this
    function may be "unintuitive," albeit correct; see Examples section
    below.

    Examples
    --------
    >>> from numpy.polynomial import legendre as L
    >>> c = (1,2,3,4)
    >>> L.legder(c)
    array([  6.,   9.,  20.])
    >>> L.legder(c, 3)
    array([60.])
    >>> L.legder(c, scl=-1)
    array([ -6.,  -9., -20.])
    >>> L.legder(c, 2,-1)
    array([  9.,  60.])

    """
    # Ensure `c` is at least 1-dimensional and make a copy
    c = np.array(c, ndmin=1, copy=True)
    # Convert `c` to double precision if it is of a different type
    if c.dtype.char in '?bBhHiIlLqQpP':
        c = c.astype(np.double)
    # Convert `m` to integer; raise an error if not possible
    cnt = pu._as_int(m, "the order of derivation")
    # 将 axis 转换为整数索引,如果无效则引发异常
    iaxis = pu._as_int(axis, "the axis")
    
    # 如果 cnt 小于 0,则抛出数值错误异常
    if cnt < 0:
        raise ValueError("The order of derivation must be non-negative")
    
    # 根据数组 c 的维度,规范化 iaxis 的索引
    iaxis = normalize_axis_index(iaxis, c.ndim)
    
    # 如果 cnt 等于 0,直接返回数组 c
    if cnt == 0:
        return c
    
    # 将 c 数组的轴 iaxis 移动到索引 0 的位置
    c = np.moveaxis(c, iaxis, 0)
    
    # 获取数组 c 的长度
    n = len(c)
    
    # 如果 cnt 大于等于 n,则将 c 的第一个元素置零并返回
    if cnt >= n:
        c = c[:1]*0
    else:
        # 对于 cnt 次导数计算
        for i in range(cnt):
            n = n - 1  # 更新导数的阶数
            c *= scl  # 对 c 应用缩放因子
            # 创建导数数组 der
            der = np.empty((n,) + c.shape[1:], dtype=c.dtype)
            for j in range(n, 2, -1):
                der[j - 1] = (2*j - 1)*c[j]  # 计算高阶导数
                c[j - 2] += c[j]  # 更新 c 数组
            if n > 1:
                der[1] = 3*c[2]  # 计算第二阶导数
            der[0] = c[1]  # 计算一阶导数
            c = der  # 更新 c 数组为新的导数数组
    
    # 将 c 数组的索引 0 移回到 iaxis 轴的位置
    c = np.moveaxis(c, 0, iaxis)
    
    # 返回计算结果数组 c
    return c
# 定义函数 `legint`,用于对勒让德级数进行积分操作
def legint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
    """
    Integrate a Legendre series.

    Returns the Legendre series coefficients `c` integrated `m` times from
    `lbnd` along `axis`. At each iteration the resulting series is
    **multiplied** by `scl` and an integration constant, `k`, is added.
    The scaling factor is for use in a linear change of variable.  ("Buyer
    beware": note that, depending on what one is doing, one may want `scl`
    to be the reciprocal of what one might expect; for more information,
    see the Notes section below.)  The argument `c` is an array of
    coefficients from low to high degree along each axis, e.g., [1,2,3]
    represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]]
    represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) +
    2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``.

    Parameters
    ----------
    c : array_like
        Array of Legendre series coefficients. If c is multidimensional the
        different axis correspond to different variables with the degree in
        each axis given by the corresponding index.
    m : int, optional
        Order of integration, must be positive. (Default: 1)
    k : {[], list, scalar}, optional
        Integration constant(s).  The value of the first integral at
        ``lbnd`` is the first value in the list, the value of the second
        integral at ``lbnd`` is the second value, etc.  If ``k == []`` (the
        default), all constants are set to zero.  If ``m == 1``, a single
        scalar can be given instead of a list.
    lbnd : scalar, optional
        The lower bound of the integral. (Default: 0)
    scl : scalar, optional
        Following each integration the result is *multiplied* by `scl`
        before the integration constant is added. (Default: 1)
    axis : int, optional
        Axis over which the integral is taken. (Default: 0).

        .. versionadded:: 1.7.0

    Returns
    -------
    S : ndarray
        Legendre series coefficient array of the integral.

    Raises
    ------
    ValueError
        If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
        ``np.ndim(scl) != 0``.

    See Also
    --------
    legder

    Notes
    -----
    Note that the result of each integration is *multiplied* by `scl`.
    Why is this important to note?  Say one is making a linear change of
    variable :math:`u = ax + b` in an integral relative to `x`.  Then
    :math:`dx = du/a`, so one will need to set `scl` equal to
    :math:`1/a` - perhaps not what one would have first thought.

    Also note that, in general, the result of integrating a C-series needs
    to be "reprojected" onto the C-series basis set.  Thus, typically,
    the result of this function is "unintuitive," albeit correct; see
    Examples section below.

    Examples
    --------
    >>> from numpy.polynomial import legendre as L
    >>> c = (1,2,3)
    >>> L.legint(c)

    """
    # 数组包含四个浮点数,可能会有变化
    array([ 0.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
    # 使用 L 对象的 legint 方法,传入参数 c 和 3
    >>> L.legint(c, 3)
    # 返回一个数组,可能会有变化
    array([  1.66666667e-02,  -1.78571429e-02,   4.76190476e-02, # may vary
             -1.73472348e-18,   1.90476190e-02,   9.52380952e-03])
    # 使用 L 对象的 legint 方法,传入参数 c 和 k=3
    >>> L.legint(c, k=3)
     # 返回一个数组,可能会有变化
     array([ 3.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
    # 使用 L 对象的 legint 方法,传入参数 c 和 lbnd=-2
    >>> L.legint(c, lbnd=-2)
    # 返回一个数组,可能会有变化
    array([ 7.33333333,  0.4       ,  0.66666667,  0.6       ]) # may vary
    # 使用 L 对象的 legint 方法,传入参数 c 和 scl=2
    >>> L.legint(c, scl=2)
    # 返回一个数组,可能会有变化
    array([ 0.66666667,  0.8       ,  1.33333333,  1.2       ]) # may vary

    """
    # 将 c 转换成至少一维的数组,确保是副本
    c = np.array(c, ndmin=1, copy=True)
    # 如果 c 是布尔类型或者整数类型,将其转换成双精度浮点型
    if c.dtype.char in '?bBhHiIlLqQpP':
        c = c.astype(np.double)
    # 如果 k 不可迭代,将其转换成列表
    if not np.iterable(k):
        k = [k]
    # 将 m 转换成整数,表示积分的阶数
    cnt = pu._as_int(m, "the order of integration")
    # 将 axis 转换成整数,表示坐标轴
    iaxis = pu._as_int(axis, "the axis")
    # 如果积分阶数为负数,抛出异常
    if cnt < 0:
        raise ValueError("The order of integration must be non-negative")
    # 如果 k 的长度大于积分阶数,抛出异常
    if len(k) > cnt:
        raise ValueError("Too many integration constants")
    # 如果 lbnd 不是标量,抛出异常
    if np.ndim(lbnd) != 0:
        raise ValueError("lbnd must be a scalar.")
    # 如果 scl 不是标量,抛出异常
    if np.ndim(scl) != 0:
        raise ValueError("scl must be a scalar.")
    # 根据 c 的维度和 axis 规范化 iaxis
    iaxis = normalize_axis_index(iaxis, c.ndim)

    # 如果阶数为 0,直接返回 c
    if cnt == 0:
        return c

    # 将 c 沿着轴移动到第一个位置
    c = np.moveaxis(c, iaxis, 0)
    # 将 k 转换成列表,并在末尾补充 0 至 cnt 长度
    k = list(k) + [0]*(cnt - len(k))
    for i in range(cnt):
        n = len(c)
        c *= scl
        if n == 1 and np.all(c[0] == 0):
            c[0] += k[i]
        else:
            tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype)
            tmp[0] = c[0]*0
            tmp[1] = c[0]
            if n > 1:
                tmp[2] = c[1]/3
            for j in range(2, n):
                t = c[j]/(2*j + 1)
                tmp[j + 1] = t
                tmp[j - 1] -= t
            tmp[0] += k[i] - legval(lbnd, tmp)
            c = tmp
    # 将 c 沿着第一个轴移动到 iaxis 轴上
    c = np.moveaxis(c, 0, iaxis)
    # 返回 c
    return c
# 定义函数,用于在给定点 x 处评估 Legendre 级数
def legval(x, c, tensor=True):
    """
    Evaluate a Legendre series at points x.

    If `c` is of length ``n + 1``, this function returns the value:

    .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x)

    The parameter `x` is converted to an array only if it is a tuple or a
    list, otherwise it is treated as a scalar. In either case, either `x`
    or its elements must support multiplication and addition both with
    themselves and with the elements of `c`.

    If `c` is a 1-D array, then ``p(x)`` will have the same shape as `x`.  If
    `c` is multidimensional, then the shape of the result depends on the
    value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
    x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
    scalars have shape (,).

    Trailing zeros in the coefficients will be used in the evaluation, so
    they should be avoided if efficiency is a concern.

    Parameters
    ----------
    x : array_like, compatible object
        If `x` is a list or tuple, it is converted to an ndarray, otherwise
        it is left unchanged and treated as a scalar. In either case, `x`
        or its elements must support addition and multiplication with
        themselves and with the elements of `c`.
    c : array_like
        Array of coefficients ordered so that the coefficients for terms of
        degree n are contained in c[n]. If `c` is multidimensional the
        remaining indices enumerate multiple polynomials. In the two
        dimensional case the coefficients may be thought of as stored in
        the columns of `c`.
    tensor : boolean, optional
        If True, the shape of the coefficient array is extended with ones
        on the right, one for each dimension of `x`. Scalars have dimension 0
        for this action. The result is that every column of coefficients in
        `c` is evaluated for every element of `x`. If False, `x` is broadcast
        over the columns of `c` for the evaluation.  This keyword is useful
        when `c` is multidimensional. The default value is True.

        .. versionadded:: 1.7.0

    Returns
    -------
    values : ndarray, algebra_like
        The shape of the return value is described above.

    See Also
    --------
    legval2d, leggrid2d, legval3d, leggrid3d

    Notes
    -----
    The evaluation uses Clenshaw recursion, aka synthetic division.

    """
    # 将 c 转换为至少是一维的 numpy 数组,确保数据类型为浮点型
    c = np.array(c, ndmin=1, copy=None)
    # 如果 c 的数据类型为布尔型、字节型、短整型、整型或长整型,转换为双精度浮点型
    if c.dtype.char in '?bBhHiIlLqQpP':
        c = c.astype(np.double)
    # 如果 x 是元组或列表,则将其转换为 ndarray
    if isinstance(x, (tuple, list)):
        x = np.asarray(x)
    # 如果 x 是 ndarray 且 tensor=True,则将 c 的形状重塑为 c.shape + (1,)*x.ndim
    if isinstance(x, np.ndarray) and tensor:
        c = c.reshape(c.shape + (1,)*x.ndim)

    # 根据 c 的长度选择性地设置 c0 和 c1
    if len(c) == 1:
        c0 = c[0]
        c1 = 0
    elif len(c) == 2:
        c0 = c[0]
        c1 = c[1]
    else:
        # 计算输入列表 c 的长度
        nd = len(c)
        # 获取 c 的倒数第二个元素
        c0 = c[-2]
        # 获取 c 的最后一个元素
        c1 = c[-1]
        # 循环遍历 c 的子集,从索引 3 开始到末尾
        for i in range(3, len(c) + 1):
            # 临时保存 c0 的值
            tmp = c0
            # 更新 nd 的值
            nd = nd - 1
            # 更新 c0 的值,根据公式计算
            c0 = c[-i] - (c1*(nd - 1))/nd
            # 更新 c1 的值,根据公式计算
            c1 = tmp + (c1*x*(2*nd - 1))/nd
    # 返回计算结果 c0 + c1*x
    return c0 + c1*x
# 计算二维Legendre级数在点(x, y)处的值。

def legval2d(x, y, c):
    """
    Evaluate a 2-D Legendre series at points (x, y).

    This function returns the values:

    .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y)

    The parameters `x` and `y` are converted to arrays only if they are
    tuples or a lists, otherwise they are treated as scalars and they
    must have the same shape after conversion. In either case, either `x`
    and `y` or their elements must support multiplication and addition both
    with themselves and with the elements of `c`.

    If `c` is a 1-D array a one is implicitly appended to its shape to make
    it 2-D. The shape of the result will be c.shape[2:] + x.shape.

    Parameters
    ----------
    x, y : array_like, compatible objects
        The two-dimensional series is evaluated at the points ``(x, y)``,
        where `x` and `y` must have the same shape. If `x` or `y` is a list
        or tuple, it is first converted to an ndarray, otherwise it is left
        unchanged and if it isn't an ndarray it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficient of the term
        of multi-degree i,j is contained in ``c[i,j]``. If `c` has
        dimension greater than two the remaining indices enumerate multiple
        sets of coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the two-dimensional Legendre series at points formed
        from pairs of corresponding values from `x` and `y`.

    See Also
    --------
    legval, leggrid2d, legval3d, leggrid3d

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    # 调用私有函数 `_valnd` 计算Legendre级数在给定点 `(x, y)` 处的值,使用系数 `c`
    return pu._valnd(legval, c, x, y)


def leggrid2d(x, y, c):
    """
    Evaluate a 2-D Legendre series on the Cartesian product of x and y.

    This function returns the values:

    .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b)

    where the points ``(a, b)`` consist of all pairs formed by taking
    `a` from `x` and `b` from `y`. The resulting points form a grid with
    `x` in the first dimension and `y` in the second.

    The parameters `x` and `y` are converted to arrays only if they are
    tuples or a lists, otherwise they are treated as scalars. In either
    case, either `x` and `y` or their elements must support multiplication
    and addition both with themselves and with the elements of `c`.

    If `c` has fewer than two dimensions, ones are implicitly appended to
    its shape to make it 2-D. The shape of the result will be c.shape[2:] +
    x.shape + y.shape.

    Parameters
    ----------
    x, y : array_like, compatible objects
        The two-dimensional series is evaluated at the points in the
        Cartesian product of `x` and `y`.  If `x` or `y` is a list or
        tuple, it is first converted to an ndarray, otherwise it is left
        unchanged and, if it isn't an ndarray, it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficient of the term
        of multi-degree i,j is contained in ``c[i,j]``. If `c` has
        dimension greater than two the remaining indices enumerate multiple
        sets of coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the two-dimensional Legendre series at points formed
        from pairs of corresponding values from `x` and `y`.

    See Also
    --------
    legval, leggrid2d, legval3d, leggrid3d
    """
    c : array_like
        # 输入参数 c 是一个类数组对象,用于存储系数,按照多重度 i,j 的项的系数存储在 c[i,j] 中。
        # 如果 c 的维度大于两维,则剩余的索引用于枚举多组系数。

    Returns
    -------
    values : ndarray, compatible object
        # 返回值是一个 ndarray 数组或兼容对象,表示在笛卡尔积空间中点 (x, y) 处的二维切比雪夫级数的值。

    See Also
    --------
    legval, legval2d, legval3d, leggrid3d
        # 参见相关函数 legval, legval2d, legval3d, leggrid3d。

    Notes
    -----
    # 版本备注:自版本 1.7.0 起添加。

    """
    # 调用 pu 模块中的 _gridnd 函数,计算二维切比雪夫级数在点 (x, y) 处的值,并返回结果。
    return pu._gridnd(legval, c, x, y)
# 计算三维Legendre系列在点(x, y, z)处的值。

def legval3d(x, y, z, c):
    """
    Evaluate a 3-D Legendre series at points (x, y, z).

    This function returns the values:

    .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z)

    The parameters `x`, `y`, and `z` are converted to arrays only if
    they are tuples or a lists, otherwise they are treated as scalars and
    must have the same shape after conversion. In either case, either
    `x`, `y`, and `z` or their elements must support multiplication and
    addition both with themselves and with the elements of `c`.

    If `c` has fewer than 3 dimensions, ones are implicitly appended to its
    shape to make it 3-D. The shape of the result will be c.shape[3:] +
    x.shape.

    Parameters
    ----------
    x, y, z : array_like, compatible object
        The three-dimensional series is evaluated at the points
        ``(x, y, z)``, where `x`, `y`, and `z` must have the same shape. If
        any of `x`, `y`, or `z` is a list or tuple, it is first converted
        to an ndarray; otherwise, it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficient of the term of
        multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
        greater than 3, the remaining indices enumerate multiple sets of
        coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the multidimensional polynomial on points formed with
        triples of corresponding values from `x`, `y`, and `z`.

    See Also
    --------
    legval, legval2d, leggrid2d, leggrid3d

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    # 调用内部函数 _valnd,传递参数 legval, c, x, y, z,并返回结果
    return pu._valnd(legval, c, x, y, z)


def leggrid3d(x, y, z, c):
    """
    Evaluate a 3-D Legendre series on the Cartesian product of x, y, and z.

    This function returns the values:

    .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c)

    where the points ``(a, b, c)`` consist of all triples formed by taking
    `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form
    a grid with `x` in the first dimension, `y` in the second, and `z` in
    the third.

    The parameters `x`, `y`, and `z` are converted to arrays only if they
    are tuples or lists; otherwise, they are treated as scalars. In
    either case, either `x`, `y`, and `z` or their elements must support
    multiplication and addition both with themselves and with the elements
    of `c`.

    If `c` has fewer than three dimensions, ones are implicitly appended to
    its shape to make it 3-D. The shape of the result will be c.shape[3:] +
    x.shape + y.shape + z.shape.

    Parameters
    ----------
    x, y, z : array_like, compatible object
        Arrays defining the grid points where the Legendre series is evaluated.
        These arrays should have compatible shapes.
    c : array_like
        Array of coefficients ordered such that the coefficient of the term of
        multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension
        greater than 3, the remaining indices enumerate multiple sets of
        coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the multidimensional polynomial on the Cartesian product
        of `x`, `y`, and `z`.

    See Also
    --------
    legval, legval2d, leggrid2d, leggrid3d

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    x, y, z : array_like, compatible objects
        三维序列在 `x`、`y` 和 `z` 的笛卡尔积点处进行评估。如果 `x`、`y` 或 `z` 是列表或元组,则首先转换为 ndarray;否则保持不变,并且如果它不是 ndarray,则视为标量。
    c : array_like
        按照次数 i,j 排列的系数数组,系数 `c[i,j]` 对应于二维多项式的系数。如果 `c` 的维度大于二,则其余的索引用于枚举多组系数。

    Returns
    -------
    values : ndarray, compatible object
        二维多项式在 `x` 和 `y` 的笛卡尔积点处的值。

    See Also
    --------
    legval, legval2d, leggrid2d, legval3d

    Notes
    -----
    在版本 1.7.0 中添加

    """
    返回 pu._gridnd(legval, c, x, y, z)


注释:
- `x, y, z : array_like, compatible objects`: 描述了函数参数 `x`, `y`, `z` 应为类似数组的兼容对象,表示三维序列在这些坐标的笛卡尔积点处进行评估。
- `c : array_like`: 描述了参数 `c` 应为类似数组的对象,按照二维多项式的次数排列,用于存储系数。
- `Returns`: 描述了函数返回一个 ndarray 或兼容对象,表示二维多项式在给定点处的值。
- `See Also`: 提供了相关函数的链接,供进一步参考。
- `Notes`: 指出该功能是在版本 1.7.0 中添加的。
def legvander(x, deg):
    """Pseudo-Vandermonde matrix of given degree.

    Returns the pseudo-Vandermonde matrix of degree `deg` and sample points
    `x`. The pseudo-Vandermonde matrix is defined by

    .. math:: V[..., i] = L_i(x)

    where ``0 <= i <= deg``. The leading indices of `V` index the elements of
    `x` and the last index is the degree of the Legendre polynomial.

    If `c` is a 1-D array of coefficients of length ``n + 1`` and `V` is the
    array ``V = legvander(x, n)``, then ``np.dot(V, c)`` and
    ``legval(x, c)`` are the same up to roundoff. This equivalence is
    useful both for least squares fitting and for the evaluation of a large
    number of Legendre series of the same degree and sample points.

    Parameters
    ----------
    x : array_like
        Array of points. The dtype is converted to float64 or complex128
        depending on whether any of the elements are complex. If `x` is
        scalar it is converted to a 1-D array.
    deg : int
        Degree of the resulting matrix.

    Returns
    -------
    vander : ndarray
        The pseudo-Vandermonde matrix. The shape of the returned matrix is
        ``x.shape + (deg + 1,)``, where The last index is the degree of the
        corresponding Legendre polynomial.  The dtype will be the same as
        the converted `x`.

    """
    # Convert deg to an integer if possible, raises ValueError if deg < 0
    ideg = pu._as_int(deg, "deg")
    if ideg < 0:
        raise ValueError("deg must be non-negative")

    # Ensure x is converted to a 1-D array of float64 or complex128
    x = np.array(x, copy=None, ndmin=1) + 0.0

    # Calculate dimensions for the output array
    dims = (ideg + 1,) + x.shape
    dtyp = x.dtype

    # Create an uninitialized array v with dimensions and dtype calculated above
    v = np.empty(dims, dtype=dtyp)

    # Initialize the first column of v with ones
    v[0] = x*0 + 1

    # Fill the remaining columns using forward recursion
    if ideg > 0:
        v[1] = x
        for i in range(2, ideg + 1):
            v[i] = (v[i-1]*x*(2*i - 1) - v[i-2]*(i - 1))/i

    # Move the first axis to the last axis of v and return
    return np.moveaxis(v, 0, -1)
    x, y : array_like
        Arrays of point coordinates, all of the same shape. The dtypes
        will be converted to either float64 or complex128 depending on
        whether any of the elements are complex. Scalars are converted to
        1-D arrays.
    deg : list of ints
        List of maximum degrees of the form [x_deg, y_deg].

    Returns
    -------
    vander2d : ndarray
        The shape of the returned matrix is ``x.shape + (order,)``, where
        :math:`order = (deg[0]+1)*(deg[1]+1)`.  The dtype will be the same
        as the converted `x` and `y`.

    See Also
    --------
    legvander, legvander3d, legval2d, legval3d

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    # 调用 _vander_nd_flat 函数来生成 2D Vandermonde 矩阵
    return pu._vander_nd_flat((legvander, legvander), (x, y), deg)
# 返回给定三维样本点 (x, y, z) 和阶数 deg 的伪范德蒙矩阵
def legvander3d(x, y, z, deg):
    """Pseudo-Vandermonde matrix of given degrees.

    Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
    points ``(x, y, z)``. If `l`, `m`, `n` are the given degrees in `x`, `y`, `z`,
    then The pseudo-Vandermonde matrix is defined by

    .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z),

    where ``0 <= i <= l``, ``0 <= j <= m``, and ``0 <= j <= n``.  The leading
    indices of `V` index the points ``(x, y, z)`` and the last index encodes
    the degrees of the Legendre polynomials.

    If ``V = legvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns
    of `V` correspond to the elements of a 3-D coefficient array `c` of
    shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order

    .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...

    and ``np.dot(V, c.flat)`` and ``legval3d(x, y, z, c)`` will be the
    same up to roundoff. This equivalence is useful both for least squares
    fitting and for the evaluation of a large number of 3-D Legendre
    series of the same degrees and sample points.

    Parameters
    ----------
    x, y, z : array_like
        Arrays of point coordinates, all of the same shape. The dtypes will
        be converted to either float64 or complex128 depending on whether
        any of the elements are complex. Scalars are converted to 1-D
        arrays.
    deg : list of ints
        List of maximum degrees of the form [x_deg, y_deg, z_deg].

    Returns
    -------
    vander3d : ndarray
        The shape of the returned matrix is ``x.shape + (order,)``, where
        :math:`order = (deg[0]+1)*(deg[1]+1)*(deg[2]+1)`.  The dtype will
        be the same as the converted `x`, `y`, and `z`.

    See Also
    --------
    legvander, legval2d, legval3d

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    # 调用 _vander_nd_flat 函数计算伪范德蒙矩阵
    return pu._vander_nd_flat((legvander, legvander, legvander), (x, y, z), deg)


# 最小二乘拟合 Legendre 级数到数据
def legfit(x, y, deg, rcond=None, full=False, w=None):
    """
    Least squares fit of Legendre series to data.

    Return the coefficients of a Legendre series of degree `deg` that is the
    least squares fit to the data values `y` given at points `x`. If `y` is
    1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple
    fits are done, one for each column of `y`, and the resulting
    coefficients are stored in the corresponding columns of a 2-D return.
    The fitted polynomial(s) are in the form

    .. math::  p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x),

    where `n` is `deg`.

    Parameters
    ----------
    x : array_like, shape (M,)
        x-coordinates of the M sample points ``(x[i], y[i])``.
    y : array_like, shape (M,) or (M, K)
        y-coordinates of the sample points. Several data sets of sample
        points sharing the same x-coordinates can be fitted at once by
        passing in a 2D-array that contains one dataset per column.
    deg : int
        Degree of the Legendre series to fit.

    Returns
    -------
    c : ndarray, shape (deg + 1,) or (deg + 1, K)
        Coefficients of the Legendre series that minimizes the squared
        error in the least-squares sense.

    See Also
    --------
    legvander, legvander2d, legvander3d, legval, legval2d, legval3d
    """
    # 返回拟合数据的 Legendre 级数的系数
    return pu._fit((legvander, legvander, legvander), x, y, deg, rcond, full, w)
    deg : int or 1-D array_like
        # 多项式拟合的次数或次数列表。如果 `deg` 是一个整数,那么包括直到第 `deg` 项的所有项在内。
        # 对于 NumPy 版本 >= 1.11.0,可以使用整数列表指定要包括的项的次数。
    rcond : float, optional
        # 拟合过程中使用的相对条件数。忽略比最大奇异值小的奇异值的相对值。
        # 默认值为 len(x)*eps,其中 eps 是浮点数类型的相对精度,在大多数情况下约为 2e-16。
    full : bool, optional
        # 返回值的性质开关。当为 False(默认值)时,只返回系数;当为 True 时,同时返回奇异值分解的诊断信息。
    w : array_like, shape (`M`,), optional
        # 权重数组。如果不为 None,则权重 `w[i]` 适用于 `x[i]` 处的未平方残差 `y[i] - y_hat[i]`。
        # 理想情况下,应选择使得乘积 `w[i]*y[i]` 的误差具有相同的方差的权重。
        # 当使用逆方差加权时,使用 `w[i] = 1/sigma(y[i])`。默认值为 None。

        .. versionadded:: 1.5.0

    Returns
    -------
    coef : ndarray, shape (M,) or (M, K)
        # 按从低到高顺序排列的 Legendre 系数。如果 `y` 是二维的,那么 `y` 中第 k 列的数据的系数位于返回的 `coef` 的第 k 列中。
        # 如果 `deg` 被指定为一个列表,则在拟合中未包含的项的系数在返回的 `coef` 中被设为零。

    [residuals, rank, singular_values, rcond] : list
        # 只有在 ``full == True`` 时才返回这些值

        - residuals -- 最小二乘拟合的残差平方和
        - rank -- 缩放后的 Vandermonde 矩阵的数值秩
        - singular_values -- 缩放后的 Vandermonde 矩阵的奇异值
        - rcond -- `rcond` 的值

        更多细节请参阅 `numpy.linalg.lstsq`。

    Warns
    -----
    RankWarning
        # 在最小二乘拟合中,系数矩阵的秩是不足的。只有在 ``full == False`` 时才会发出警告。
        # 可以通过以下方式关闭警告:

        >>> import warnings
        >>> warnings.simplefilter('ignore', np.exceptions.RankWarning)

    See Also
    --------
    numpy.polynomial.polynomial.polyfit
    numpy.polynomial.chebyshev.chebfit
    numpy.polynomial.laguerre.lagfit
    numpy.polynomial.hermite.hermfit
    numpy.polynomial.hermite_e.hermefit
    legval : 对 Legendre 级数进行求值。
    legvander : Legendre 级数的 Vandermonde 矩阵。
    legweight : Legendre 权重函数(= 1)。
    numpy.linalg.lstsq : 计算矩阵的最小二乘拟合。
    scipy.interpolate.UnivariateSpline : 计算样条拟合。

    Notes
    -----
    # 解决方案是 Legendre 级数 `p` 的系数,满足以下条件:
    minimizes the sum of the weighted squared errors

    .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,

    where :math:`w_j` are the weights. This problem is solved by setting up
    as the (typically) overdetermined matrix equation

    .. math:: V(x) * c = w * y,

    where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the
    coefficients to be solved for, `w` are the weights, and `y` are the
    observed values.  This equation is then solved using the singular value
    decomposition of `V`.

    If some of the singular values of `V` are so small that they are
    neglected, then a `~exceptions.RankWarning` will be issued. This means that
    the coefficient values may be poorly determined. Using a lower order fit
    will usually get rid of the warning.  The `rcond` parameter can also be
    set to a value smaller than its default, but the resulting fit may be
    spurious and have large contributions from roundoff error.

    Fits using Legendre series are usually better conditioned than fits
    using power series, but much can depend on the distribution of the
    sample points and the smoothness of the data. If the quality of the fit
    is inadequate splines may be a good alternative.

    References
    ----------
    .. [1] Wikipedia, "Curve fitting",
           https://en.wikipedia.org/wiki/Curve_fitting

    Examples
    --------

    """
    使用Legendre多项式进行最小二乘拟合,并返回拟合结果。

    Parameters
    ----------
    legvander : callable
        函数用于计算Legendre多项式的伪Vandermonde矩阵。
    x : array_like, shape (M,)
        输入数据点的数组。
    y : array_like, shape (M,)
        观测到的数据值。
    deg : int
        拟合多项式的次数。
    rcond : float, optional
        用于判断奇异值的截断值,默认为None。
    full : bool, optional
        控制输出内容,若为True则返回完整的分解,否则返回拟合系数,默认为False。
    w : array_like, shape (M,), optional
        每个观测值的权重。

    Returns
    -------
    ndarray
        拟合系数。

    Notes
    -----
    使用Legendre多项式进行拟合通常比使用幂级数更好,但很大程度上取决于样本点的分布和数据的平滑程度。
    如果拟合质量不足,样条曲线可能是一个更好的选择。

    """
    return pu._fit(legvander, x, y, deg, rcond, full, w)
def legcompanion(c):
    """
    Return the scaled companion matrix of c.

    The basis polynomials are scaled so that the companion matrix is
    symmetric when `c` is an Legendre basis polynomial. This provides
    better eigenvalue estimates than the unscaled case and for basis
    polynomials the eigenvalues are guaranteed to be real if
    `numpy.linalg.eigvalsh` is used to obtain them.

    Parameters
    ----------
    c : array_like
        1-D array of Legendre series coefficients ordered from low to high
        degree.

    Returns
    -------
    mat : ndarray
        Scaled companion matrix of dimensions (deg, deg).

    Notes
    -----

    .. versionadded:: 1.7.0

    """
    # c is a trimmed copy
    [c] = pu.as_series([c])  # 将输入的系数数组 c 转换为一个修剪过的系列
    if len(c) < 2:
        raise ValueError('Series must have maximum degree of at least 1.')  # 如果系数数组长度小于2,抛出异常
    if len(c) == 2:
        return np.array([[-c[0]/c[1]]])  # 如果系数数组长度为2,返回一个1x1的数组

    n = len(c) - 1
    mat = np.zeros((n, n), dtype=c.dtype)  # 创建一个形状为 (n, n) 的零矩阵,数据类型与 c 的数据类型相同
    scl = 1./np.sqrt(2*np.arange(n) + 1)  # 计算一个尺度系数,用于缩放伴随矩阵的每一行
    top = mat.reshape(-1)[1::n+1]  # 获取矩阵的上三角元素
    bot = mat.reshape(-1)[n::n+1]  # 获取矩阵的下三角元素
    top[...] = np.arange(1, n)*scl[:n-1]*scl[1:n]  # 对上三角元素赋值,这些值是尺度系数的函数
    bot[...] = top  # 下三角元素与上三角元素相同
    mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*(n/(2*n - 1))  # 调整矩阵的最后一列,以便估算伴随矩阵的特征值
    return mat


def legroots(c):
    """
    Compute the roots of a Legendre series.

    Return the roots (a.k.a. "zeros") of the polynomial

    .. math:: p(x) = \\sum_i c[i] * L_i(x).

    Parameters
    ----------
    c : 1-D array_like
        1-D array of coefficients.

    Returns
    -------
    out : ndarray
        Array of the roots of the series. If all the roots are real,
        then `out` is also real, otherwise it is complex.

    See Also
    --------
    numpy.polynomial.polynomial.polyroots
    numpy.polynomial.chebyshev.chebroots
    numpy.polynomial.laguerre.lagroots
    numpy.polynomial.hermite.hermroots
    numpy.polynomial.hermite_e.hermeroots

    Notes
    -----
    The root estimates are obtained as the eigenvalues of the companion
    matrix, Roots far from the origin of the complex plane may have large
    errors due to the numerical instability of the series for such values.
    Roots with multiplicity greater than 1 will also show larger errors as
    the value of the series near such points is relatively insensitive to
    errors in the roots. Isolated roots near the origin can be improved by
    a few iterations of Newton's method.

    The Legendre series basis polynomials aren't powers of ``x`` so the
    results of this function may seem unintuitive.

    Examples
    --------
    >>> import numpy.polynomial.legendre as leg
    >>> leg.legroots((1, 2, 3, 4)) # 4L_3 + 3L_2 + 2L_1 + 1L_0, all real roots
    array([-0.85099543, -0.11407192,  0.51506735]) # may vary

    """
    # c is a trimmed copy
    [c] = pu.as_series([c])  # 将输入的系数数组 c 转换为一个修剪过的系列
    if len(c) < 2:
        return np.array([], dtype=c.dtype)  # 如果系数数组长度小于2,返回一个空数组
    if len(c) == 2:
        return np.array([-c[0]/c[1]])  # 如果系数数组长度为2,返回一个包含一个根的数组

    # rotated companion matrix reduces error
    m = legcompanion(c)[::-1,::-1]  # 计算伴随矩阵并进行旋转,以减小数值误差
    # 计算矩阵 m 的特征值
    r = la.eigvals(m)
    # 对特征值进行排序(默认按照实部进行排序)
    r.sort()
    # 返回排序后的特征值数组作为结果
    return r
# Gauss-Legendre quadrature function to compute sample points and weights for integration
def leggauss(deg):
    # Ensure deg is a positive integer; raise error if not
    ideg = pu._as_int(deg, "deg")
    if ideg <= 0:
        raise ValueError("deg must be a positive integer")

    # Initial approximation of roots using companion matrix symmetry
    c = np.array([0]*deg + [1])
    m = legcompanion(c)  # Compute companion matrix
    x = la.eigvalsh(m)   # Compute eigenvalues of the companion matrix

    # Improve roots using one application of Newton's method
    dy = legval(x, c)     # Compute polynomial value at roots
    df = legval(x, legder(c))  # Compute derivative of the polynomial at roots
    x -= dy / df          # Apply Newton's method to improve roots

    # Compute the weights, scaling to avoid numerical overflow
    fm = legval(x, c[1:])  # Compute polynomial value at improved roots
    fm /= np.abs(fm).max()  # Scale to avoid overflow
    df /= np.abs(df).max()
    w = 1 / (fm * df)     # Compute weights using the formula

    # Symmetrize weights and roots for Legendre polynomial
    w = (w + w[::-1]) / 2
    x = (x - x[::-1]) / 2

    # Scale weights to ensure correct integration value
    w *= 2. / w.sum()

    return x, w


# Function defining weight function of Legendre polynomials
def legweight(x):
    # Weight function is 1 over the interval [-1, 1]
    w = x * 0.0 + 1.0
    return w


# Legendre series class implementing various numerical methods and attributes
class Legendre(ABCPolyBase):
    """A Legendre series class.

    The Legendre class provides the standard Python numerical methods
    '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the
    attributes and methods listed below.

    Parameters
    ----------
    coef : array_like
        Legendre coefficients in order of increasing degree, i.e.,
        ``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``.
    """
    # domain : (2,) array_like, optional
    #     Domain to use. The interval ``[domain[0], domain[1]]`` is mapped
    #     to the interval ``[window[0], window[1]]`` by shifting and scaling.
    #     The default value is [-1, 1].

    # window : (2,) array_like, optional
    #     Window, see `domain` for its use. The default value is [-1, 1].
    #
    #     .. versionadded:: 1.6.0

    # symbol : str, optional
    #     Symbol used to represent the independent variable in string
    #     representations of the polynomial expression, e.g. for printing.
    #     The symbol must be a valid Python identifier. Default value is 'x'.
    #
    #     .. versionadded:: 1.24

    """
    # Virtual Functions
    # 定义静态方法来实现多项式的不同操作
    _add = staticmethod(legadd)
    _sub = staticmethod(legsub)
    _mul = staticmethod(legmul)
    _div = staticmethod(legdiv)
    _pow = staticmethod(legpow)
    _val = staticmethod(legval)
    _int = staticmethod(legint)
    _der = staticmethod(legder)
    _fit = staticmethod(legfit)
    _line = staticmethod(legline)
    _roots = staticmethod(legroots)
    _fromroots = staticmethod(legfromroots)

    # Virtual properties
    # 将定义的区间数组转换为NumPy数组并赋值给domain和window属性
    domain = np.array(legdomain)
    window = np.array(legdomain)
    # 设置多项式的基函数名称为'P'
    basis_name = 'P'

.\numpy\numpy\polynomial\legendre.pyi

# 引入类型提示中的 Any 类型
from typing import Any

# 引入整数类型 NDArray 以及 int_ 别名
from numpy import int_
# 引入 NDArray 类型别名
from numpy.typing import NDArray
# 引入 ABCPolyBase 类
from numpy.polynomial._polybase import ABCPolyBase
# 引入 trimcoef 函数
from numpy.polynomial.polyutils import trimcoef

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

# 将 trimcoef 函数赋值给 legtrim 变量
legtrim = trimcoef

# 定义 poly2leg 函数,用于将多项式转换为勒让德多项式
def poly2leg(pol): ...

# 定义 leg2poly 函数,用于将勒让德多项式转换为多项式
def leg2poly(c): ...

# 定义数组 legdomain,存储勒让德多项式的定义域
legdomain: NDArray[int_]
# 定义数组 legzero,存储勒让德多项式的零多项式
legzero: NDArray[int_]
# 定义数组 legone,存储勒让德多项式的单位多项式
legone: NDArray[int_]
# 定义数组 legx,存储勒让德多项式的 x 多项式
legx: NDArray[int_]

# 定义 legline 函数,生成从 off 到 scl 的勒让德多项式
def legline(off, scl): ...

# 定义 legfromroots 函数,根据给定的根生成勒让德多项式
def legfromroots(roots): ...

# 定义 legadd 函数,实现勒让德多项式的加法
def legadd(c1, c2): ...

# 定义 legsub 函数,实现勒让德多项式的减法
def legsub(c1, c2): ...

# 定义 legmulx 函数,实现勒让德多项式与 x 的乘法
def legmulx(c): ...

# 定义 legmul 函数,实现勒让德多项式的乘法
def legmul(c1, c2): ...

# 定义 legdiv 函数,实现勒让德多项式的除法
def legdiv(c1, c2): ...

# 定义 legpow 函数,实现勒让德多项式的幂次运算
def legpow(c, pow, maxpower=...): ...

# 定义 legder 函数,实现勒让德多项式的导数计算
def legder(c, m=..., scl=..., axis=...): ...

# 定义 legint 函数,实现勒让德多项式的积分计算
def legint(c, m=..., k = ..., lbnd=..., scl=..., axis=...): ...

# 定义 legval 函数,用于计算勒让德多项式在给定点 x 处的值
def legval(x, c, tensor=...): ...

# 定义 legval2d 函数,用于计算二维勒让德多项式在给定点 (x, y) 处的值
def legval2d(x, y, c): ...

# 定义 leggrid2d 函数,用于计算二维勒让德多项式在网格点 (x, y) 上的值
def leggrid2d(x, y, c): ...

# 定义 legval3d 函数,用于计算三维勒让德多项式在给定点 (x, y, z) 处的值
def legval3d(x, y, z, c): ...

# 定义 leggrid3d 函数,用于计算三维勒让德多项式在网格点 (x, y, z) 上的值
def leggrid3d(x, y, z, c): ...

# 定义 legvander 函数,用于计算 Vandermonde 矩阵,生成勒让德多项式的基函数
def legvander(x, deg): ...

# 定义 legvander2d 函数,用于计算二维 Vandermonde 矩阵,生成二维勒让德多项式的基函数
def legvander2d(x, y, deg): ...

# 定义 legvander3d 函数,用于计算三维 Vandermonde 矩阵,生成三维勒让德多项式的基函数
def legvander3d(x, y, z, deg): ...

# 定义 legfit 函数,用于拟合勒让德多项式到给定的数据点 (x, y)
def legfit(x, y, deg, rcond=..., full=..., w=...): ...

# 定义 legcompanion 函数,用于生成勒让德多项式的伴随矩阵
def legcompanion(c): ...

# 定义 legroots 函数,用于计算勒让德多项式的根
def legroots(c): ...

# 定义 leggauss 函数,用于计算勒让德多项式的 Gauss 积分点和权重
def leggauss(deg): ...

# 定义 legweight 函数,用于计算勒让德多项式在给定点上的权重
def legweight(x): ...

# 定义 Legendre 类,继承 ABCPolyBase 基类,表示勒让德多项式
class Legendre(ABCPolyBase):
    # domain 属性,表示勒让德多项式的定义域
    domain: Any
    # window 属性,表示勒让德多项式的窗口
    window: Any
    # basis_name 属性,表示勒让德多项式的基函数名称
    basis_name: Any

.\numpy\numpy\polynomial\polynomial.py

# 定义一个模块级别变量,包含此模块公开的所有函数和常量的列表
__all__ = [
    'polyzero', 'polyone', 'polyx', 'polydomain', 'polyline', 'polyadd',
    'polysub', 'polymulx', 'polymul', 'polydiv', 'polypow', 'polyval',
    'polyvalfromroots', 'polyder', 'polyint', 'polyfromroots', 'polyvander',
    'polyfit', 'polytrim', 'polyroots', 'Polynomial', 'polyval2d', 'polyval3d',
    'polygrid2d', 'polygrid3d', 'polyvander2d', 'polyvander3d',
    'polycompanion']

# 导入 NumPy 库,并将其命名为 np
import numpy as np
# 导入 NumPy 的线性代数模块,并将其命名为 la
import numpy.linalg as la
# 从 NumPy 的数组工具模块中导入 normalize_axis_index 函数
from numpy.lib.array_utils import normalize_axis_index

# 从当前包中导入 polyutils 模块,并将其命名为 pu
from . import polyutils as pu
# 从当前包中导入 _polybase 模块中的 ABCPolyBase 类
from ._polybase import ABCPolyBase

# 将 polytrim 函数指向 polyutils 模块中的 trimcoef 函数
polytrim = pu.trimcoef

# 定义一个常数数组,表示多项式的默认定义域,值为 [-1., 1.]
polydomain = np.array([-1., 1.])

# 定义一个常数数组,表示多项式系数为零,值为 [0]
polyzero = np.array([0])

# 定义一个常数数组,表示多项式系数为一,值为 [1]
polyone = np.array([1])

# 定义一个常数数组,表示多项式的标识符 x,系数为 [0, 1]
polyx = np.array([0, 1])

# 定义一个函数 polyline,返回表示线性多项式的数组
def polyline(off, scl):
    """
    返回表示线性多项式的数组。

    Parameters
    ----------
    off, scl : scalars
        线性多项式的截距和斜率。

    Returns
    -------
    y : ndarray
        表示线性多项式 `off + scl*x` 的数组。

    See Also
    --------
    numpy.polynomial.chebyshev.chebline
    numpy.polynomial.legendre.legline
    numpy.polynomial.laguerre.lagline
    numpy.polynomial.hermite.hermline
    numpy.polynomial.hermite_e.hermeline

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> P.polyline(1, -1)
    array([ 1, -1])
    >>> P.polyval(1, P.polyline(1, -1))  # 应该为 0
    """
    # 返回线性多项式的系数数组
    return np.array([off, scl])
    # 检查缩放因子是否为零,根据情况返回包含偏移量和缩放因子的 NumPy 数组或仅包含偏移量的 NumPy 数组
    if scl != 0:
        # 如果缩放因子不为零,返回包含偏移量和缩放因子的 NumPy 数组
        return np.array([off, scl])
    else:
        # 如果缩放因子为零,返回仅包含偏移量的 NumPy 数组
        return np.array([off])
# 生成一个以给定根数为根的首一多项式

def polyfromroots(roots):
    # 返回的多项式系数是通过传入的根数生成的
    return pu._fromroots(polyline, polymul, roots)


# 将两个多项式相加

def polyadd(c1, c2):
    # 返回两个多项式的和,其中参数 c1 和 c2 是按照从低到高阶排列的多项式系数序列
    return pu._add(c1, c2)


# 将一个多项式减去另一个多项式

def polysub(c1, c2):
    # 返回两个多项式的差,其中参数 c1 和 c2 是按照从低到高阶排列的多项式系数序列
    # 定义一个函数,用于计算两个多项式系数之间的差
    def polysub(c1, c2):
        # 被减数和减数是一维数组,表示多项式的系数,从低到高排序
        # c1 表示第一个多项式的系数
        # c2 表示第二个多项式的系数
        # 返回一个包含系数的数组,表示两个多项式的差
        return pu._sub(c1, c2)
# 定义函数:将多项式乘以 x
def polymulx(c):
    """Multiply a polynomial by x.

    Multiply the polynomial `c` by x, where x is the independent
    variable.

    Parameters
    ----------
    c : array_like
        1-D array of polynomial coefficients ordered from low to
        high.

    Returns
    -------
    out : ndarray
        Array representing the result of the multiplication.

    See Also
    --------
    polyadd, polysub, polymul, polydiv, polypow

    Notes
    -----

    .. versionadded:: 1.5.0

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = (1, 2, 3)
    >>> P.polymulx(c)
    array([0., 1., 2., 3.])

    """
    # 使用 pu.as_series([c]) 将 c 转换成修剪后的副本
    [c] = pu.as_series([c])
    # 如果 c 只包含一个元素且为 0,则直接返回 c
    if len(c) == 1 and c[0] == 0:
        return c

    # 创建一个长度比 c 长度大一的空数组,其数据类型与 c 相同
    prd = np.empty(len(c) + 1, dtype=c.dtype)
    # 将 prd 的第一个元素设置为 c[0] * 0
    prd[0] = c[0]*0
    # 将 prd 的剩余元素设置为 c 的内容
    prd[1:] = c
    return prd


# 定义函数:将一个多项式乘以另一个多项式
def polymul(c1, c2):
    """
    Multiply one polynomial by another.

    Returns the product of two polynomials `c1` * `c2`.  The arguments are
    sequences of coefficients, from lowest order term to highest, e.g.,
    [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2.``

    Parameters
    ----------
    c1, c2 : array_like
        1-D arrays of coefficients representing a polynomial, relative to the
        "standard" basis, and ordered from lowest order term to highest.

    Returns
    -------
    out : ndarray
        Of the coefficients of their product.

    See Also
    --------
    polyadd, polysub, polymulx, polydiv, polypow

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c1 = (1, 2, 3)
    >>> c2 = (3, 2, 1)
    >>> P.polymul(c1, c2)
    array([  3.,   8.,  14.,   8.,   3.])

    """
    # 使用 pu.as_series([c1, c2]) 将 c1 和 c2 转换成修剪后的副本
    [c1, c2] = pu.as_series([c1, c2])
    # 计算 c1 和 c2 的卷积(convolution),即它们的乘积
    ret = np.convolve(c1, c2)
    return pu.trimseq(ret)


# 定义函数:将一个多项式除以另一个多项式
def polydiv(c1, c2):
    """
    Divide one polynomial by another.

    Returns the quotient-with-remainder of two polynomials `c1` / `c2`.
    The arguments are sequences of coefficients, from lowest order term
    to highest, e.g., [1,2,3] represents ``1 + 2*x + 3*x**2``.

    Parameters
    ----------
    c1, c2 : array_like
        1-D arrays of polynomial coefficients ordered from low to high.

    Returns
    -------
    [quo, rem] : ndarrays
        Of coefficient series representing the quotient and remainder.

    See Also
    --------
    polyadd, polysub, polymulx, polymul, polypow

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c1 = (1, 2, 3)
    >>> c2 = (3, 2, 1)
    >>> P.polydiv(c1, c2)
    (array([3.]), array([-8., -4.]))
    >>> P.polydiv(c2, c1)
    (array([ 0.33333333]), array([ 2.66666667,  1.33333333]))  # may vary

    """
    # 使用 pu.as_series([c1, c2]) 将 c1 和 c2 转换成修剪后的副本
    [c1, c2] = pu.as_series([c1, c2])
    # 如果 c2 的最高阶系数为 0,则抛出 ZeroDivisionError
    if c2[-1] == 0:
        raise ZeroDivisionError()

    # 计算 c1 和 c2 的商和余数,使用 np.convolve 实现
    lc1 = len(c1)
    # 计算列表 c1 和 c2 的长度
    lc2 = len(c2)
    # 如果 c1 的长度小于 c2 的长度,则返回 c1 的第一个元素重复零次的列表和 c1 本身
    if lc1 < lc2:
        return c1[:1]*0, c1
    # 如果 c2 的长度为 1,则返回 c1 除以 c2 的最后一个元素的结果和 c1 的第一个元素重复零次的列表
    elif lc2 == 1:
        return c1/c2[-1], c1[:1]*0
    # 否则,计算 c1 和 c2 的长度差,初始化除数 scl 为 c2 的最后一个元素
    else:
        dlen = lc1 - lc2
        scl = c2[-1]
        # 对 c2 进行除法运算,将结果重新赋值给 c2
        c2 = c2[:-1]/scl
        # 初始化循环变量 i 和 j
        i = dlen
        j = lc1 - 1
        # 循环执行减法操作,修改 c1 的部分值
        while i >= 0:
            c1[i:j] -= c2*c1[j]
            i -= 1
            j -= 1
        # 返回计算后的 c1 的剩余部分除以 scl 的结果和经过 pu.trimseq 函数处理后的 c1 的前部分
        return c1[j+1:]/scl, pu.trimseq(c1[:j+1])
def polypow(c, pow, maxpower=None):
    """Raise a polynomial to a power.

    Returns the polynomial `c` raised to the power `pow`. The argument
    `c` is a sequence of coefficients ordered from low to high. i.e.,
    [1,2,3] is the series  ``1 + 2*x + 3*x**2.``

    Parameters
    ----------
    c : array_like
        1-D array of array of series coefficients ordered from low to
        high degree.
    pow : integer
        Power to which the series will be raised
    maxpower : integer, optional
        Maximum power allowed. This is mainly to limit growth of the series
        to unmanageable size. Default is 16

    Returns
    -------
    coef : ndarray
        Power series of power.

    See Also
    --------
    polyadd, polysub, polymulx, polymul, polydiv

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> P.polypow([1, 2, 3], 2)
    array([ 1., 4., 10., 12., 9.])

    """
    # note: this is more efficient than `pu._pow(polymul, c1, c2)`, as it
    # avoids calling `as_series` repeatedly
    return pu._pow(np.convolve, c, pow, maxpower)


def polyder(c, m=1, scl=1, axis=0):
    """
    Differentiate a polynomial.

    Returns the polynomial coefficients `c` differentiated `m` times along
    `axis`.  At each iteration the result is multiplied by `scl` (the
    scaling factor is for use in a linear change of variable).  The
    argument `c` is an array of coefficients from low to high degree along
    each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2``
    while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is
    ``x`` and axis=1 is ``y``.

    Parameters
    ----------
    c : array_like
        Array of polynomial coefficients. If c is multidimensional the
        different axis correspond to different variables with the degree
        in each axis given by the corresponding index.
    m : int, optional
        Number of derivatives taken, must be non-negative. (Default: 1)
    scl : scalar, optional
        Each differentiation is multiplied by `scl`.  The end result is
        multiplication by ``scl**m``.  This is for use in a linear change
        of variable. (Default: 1)
    axis : int, optional
        Axis over which the derivative is taken. (Default: 0).

        .. versionadded:: 1.7.0

    Returns
    -------
    der : ndarray
        Polynomial coefficients of the derivative.

    See Also
    --------
    polyint

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = (1, 2, 3, 4)
    >>> P.polyder(c)  # (d/dx)(c)
    array([  2.,   6.,  12.])
    >>> P.polyder(c, 3)  # (d**3/dx**3)(c)
    array([24.])
    >>> P.polyder(c, scl=-1)  # (d/d(-x))(c)
    array([ -2.,  -6., -12.])
    >>> P.polyder(c, 2, -1)  # (d**2/d(-x)**2)(c)
    array([  6.,  24.])

    """
    c = np.array(c, ndmin=1, copy=True)  # 将输入的多项式系数转换为数组
    if c.dtype.char in '?bBhHiIlLqQpP':
        # astype fails with NA
        c = c + 0.0  # 将数组中的元素转换为浮点数
    cdt = c.dtype  # 获取数组的数据类型
    # 获取导数的阶数,使用 pu._as_int 函数将 m 转换为整数,"the order of derivation" 是错误消息的一部分
    cnt = pu._as_int(m, "the order of derivation")
    
    # 获取轴的索引,使用 pu._as_int 函数将 axis 转换为整数,"the axis" 是错误消息的一部分
    iaxis = pu._as_int(axis, "the axis")
    
    # 如果导数的阶数小于 0,则抛出 ValueError 异常
    if cnt < 0:
        raise ValueError("The order of derivation must be non-negative")
    
    # 根据轴的索引,将其规范化为 c 的维度中的有效索引
    iaxis = normalize_axis_index(iaxis, c.ndim)
    
    # 如果导数的阶数为 0,则直接返回 c,不需要进行导数计算
    if cnt == 0:
        return c
    
    # 将 c 数组的轴 iaxis 移动到第一个位置,以便进行导数计算
    c = np.moveaxis(c, iaxis, 0)
    
    # 获取 c 数组的长度
    n = len(c)
    
    # 如果导数的阶数大于等于 c 的长度 n,则将 c 的第一个元素置为零数组
    if cnt >= n:
        c = c[:1]*0
    else:
        # 否则,进行 cnt 次导数计算
        for i in range(cnt):
            n = n - 1  # 更新导数次数
            c *= scl  # 将 c 数组每个元素乘以 scl
            # 创建一个空数组 der,用于存储导数结果,形状为 (n,) + c.shape[1:]
            der = np.empty((n,) + c.shape[1:], dtype=cdt)
            # 计算导数,j 从 n 递减到 1
            for j in range(n, 0, -1):
                der[j - 1] = j * c[j]
            # 将导数结果赋给 c
            c = der
    
    # 将 c 数组的第一个轴移动回 iaxis 轴的位置
    c = np.moveaxis(c, 0, iaxis)
    
    # 返回最终的导数计算结果 c
    return c
# 定义一个函数用于对多项式进行积分操作
def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0):
    """
    Integrate a polynomial.

    Returns the polynomial coefficients `c` integrated `m` times from
    `lbnd` along `axis`.  At each iteration the resulting series is
    **multiplied** by `scl` and an integration constant, `k`, is added.
    The scaling factor is for use in a linear change of variable.  ("Buyer
    beware": note that, depending on what one is doing, one may want `scl`
    to be the reciprocal of what one might expect; for more information,
    see the Notes section below.) The argument `c` is an array of
    coefficients, from low to high degree along each axis, e.g., [1,2,3]
    represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]]
    represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is
    ``y``.

    Parameters
    ----------
    c : array_like
        1-D array of polynomial coefficients, ordered from low to high.
    m : int, optional
        Order of integration, must be positive. (Default: 1)
    k : {[], list, scalar}, optional
        Integration constant(s).  The value of the first integral at zero
        is the first value in the list, the value of the second integral
        at zero is the second value, etc.  If ``k == []`` (the default),
        all constants are set to zero.  If ``m == 1``, a single scalar can
        be given instead of a list.
    lbnd : scalar, optional
        The lower bound of the integral. (Default: 0)
    scl : scalar, optional
        Following each integration the result is *multiplied* by `scl`
        before the integration constant is added. (Default: 1)
    axis : int, optional
        Axis over which the integral is taken. (Default: 0).

        .. versionadded:: 1.7.0

    Returns
    -------
    S : ndarray
        Coefficient array of the integral.

    Raises
    ------
    ValueError
        If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or
        ``np.ndim(scl) != 0``.

    See Also
    --------
    polyder

    Notes
    -----
    Note that the result of each integration is *multiplied* by `scl`.  Why
    is this important to note?  Say one is making a linear change of
    variable :math:`u = ax + b` in an integral relative to `x`. Then
    :math:`dx = du/a`, so one will need to set `scl` equal to
    :math:`1/a` - perhaps not what one would have first thought.

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = (1, 2, 3)
    >>> P.polyint(c)  # should return array([0, 1, 1, 1])
    array([0.,  1.,  1.,  1.])
    >>> P.polyint(c, 3)  # should return array([0, 0, 0, 1/6, 1/12, 1/20])
     array([ 0.        ,  0.        ,  0.        ,  0.16666667,  0.08333333, # may vary
             0.05      ])
    >>> P.polyint(c, k=3)  # should return array([3, 1, 1, 1])
    array([3.,  1.,  1.,  1.])
    >>> P.polyint(c,lbnd=-2)  # should return array([6, 1, 1, 1])
    array([6.,  1.,  1.,  1.])
    """

    # 确认积分次数大于等于1,且积分常数列表长度不超过积分次数
    if m < 1 or len(k) > m:
        raise ValueError("Invalid integration parameters.")

    # 确认积分下限为标量
    if np.ndim(lbnd) != 0:
        raise ValueError("Lower bound lbnd must be scalar.")

    # 确认缩放因子为标量
    if np.ndim(scl) != 0:
        raise ValueError("Scaling factor scl must be scalar.")

    # 遍历积分次数,执行多次积分操作
    for _ in range(m):
        # 执行积分操作,乘以缩放因子后加上积分常数
        c = np.polyint(c, lbnd=lbnd, axis=axis) * scl + k.pop(0)

    # 返回积分后的多项式系数数组
    return c
    # 将输入参数 c 转换为至少包含一个维度的 NumPy 数组,并确保是副本
    c = np.array(c, ndmin=1, copy=True)
    
    # 如果 c 的数据类型是布尔型或者整型,将其强制转换为浮点型,以便后续操作
    if c.dtype.char in '?bBhHiIlLqQpP':
        c = c + 0.0
    
    # 保存 c 的原始数据类型
    cdt = c.dtype
    
    # 如果 k 不是可迭代对象,则将其转换为包含 k 的单元素列表
    if not np.iterable(k):
        k = [k]
    
    # 将 m 强制转换为整数,表示积分的阶数
    cnt = pu._as_int(m, "the order of integration")
    
    # 将 axis 强制转换为整数,表示操作的轴
    iaxis = pu._as_int(axis, "the axis")
    
    # 如果 cnt 小于 0,则抛出 ValueError
    if cnt < 0:
        raise ValueError("The order of integration must be non-negative")
    
    # 如果 k 的长度大于 cnt,则抛出 ValueError
    if len(k) > cnt:
        raise ValueError("Too many integration constants")
    
    # 如果 lbnd 不是标量,则抛出 ValueError
    if np.ndim(lbnd) != 0:
        raise ValueError("lbnd must be a scalar.")
    
    # 如果 scl 不是标量,则抛出 ValueError
    if np.ndim(scl) != 0:
        raise ValueError("scl must be a scalar.")
    
    # 根据 iaxis 的值标准化轴的索引,确保在 c 的维度范围内
    iaxis = normalize_axis_index(iaxis, c.ndim)

    # 如果 cnt 为 0,则直接返回 c
    if cnt == 0:
        return c

    # 将 k 扩展为长度为 cnt 的列表,不足部分用 0 填充
    k = list(k) + [0]*(cnt - len(k))
    
    # 将 c 在维度 iaxis 上进行移动,以便后续操作
    c = np.moveaxis(c, iaxis, 0)
    
    # 执行 cnt 次积分操作
    for i in range(cnt):
        n = len(c)
        c *= scl
        if n == 1 and np.all(c[0] == 0):
            c[0] += k[i]
        else:
            tmp = np.empty((n + 1,) + c.shape[1:], dtype=cdt)
            tmp[0] = c[0]*0
            tmp[1] = c[0]
            for j in range(1, n):
                tmp[j + 1] = c[j]/(j + 1)
            tmp[0] += k[i] - polyval(lbnd, tmp)
            c = tmp
    
    # 将 c 恢复原来的轴顺序
    c = np.moveaxis(c, 0, iaxis)
    
    # 返回积分后的结果 c
    return c
# 定义一个函数用于在指定点 x 处评估多项式的值
def polyval(x, c, tensor=True):
    """
    Evaluate a polynomial at points x.

    If `c` is of length ``n + 1``, this function returns the value

    .. math:: p(x) = c_0 + c_1 * x + ... + c_n * x^n

    The parameter `x` is converted to an array only if it is a tuple or a
    list, otherwise it is treated as a scalar. In either case, either `x`
    or its elements must support multiplication and addition both with
    themselves and with the elements of `c`.

    If `c` is a 1-D array, then ``p(x)`` will have the same shape as `x`.  If
    `c` is multidimensional, then the shape of the result depends on the
    value of `tensor`. If `tensor` is true the shape will be c.shape[1:] +
    x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that
    scalars have shape (,).

    Trailing zeros in the coefficients will be used in the evaluation, so
    they should be avoided if efficiency is a concern.

    Parameters
    ----------
    x : array_like, compatible object
        If `x` is a list or tuple, it is converted to an ndarray, otherwise
        it is left unchanged and treated as a scalar. In either case, `x`
        or its elements must support addition and multiplication with
        with themselves and with the elements of `c`.
    c : array_like
        Array of coefficients ordered so that the coefficients for terms of
        degree n are contained in c[n]. If `c` is multidimensional the
        remaining indices enumerate multiple polynomials. In the two
        dimensional case the coefficients may be thought of as stored in
        the columns of `c`.
    tensor : boolean, optional
        If True, the shape of the coefficient array is extended with ones
        on the right, one for each dimension of `x`. Scalars have dimension 0
        for this action. The result is that every column of coefficients in
        `c` is evaluated for every element of `x`. If False, `x` is broadcast
        over the columns of `c` for the evaluation.  This keyword is useful
        when `c` is multidimensional. The default value is True.

        .. versionadded:: 1.7.0

    Returns
    -------
    values : ndarray, compatible object
        The shape of the returned array is described above.

    See Also
    --------
    polyval2d, polygrid2d, polyval3d, polygrid3d

    Notes
    -----
    The evaluation uses Horner's method.

    Examples
    --------
    >>> from numpy.polynomial.polynomial import polyval
    >>> polyval(1, [1,2,3])
    6.0
    >>> a = np.arange(4).reshape(2,2)
    >>> a
    array([[0, 1],
           [2, 3]])
    >>> polyval(a, [1, 2, 3])
    array([[ 1.,   6.],
           [17.,  34.]])
    >>> coef = np.arange(4).reshape(2, 2)  # multidimensional coefficients
    >>> coef
    array([[0, 1],
           [2, 3]])
    >>> polyval([1, 2], coef, tensor=True)
    array([[2.,  4.],
           [4.,  7.]])
    >>> polyval([1, 2], coef, tensor=False)
    array([2.,  7.])

    """
    # 将输入的系数 c 转换为至少一维的 numpy 数组,确保可以进行后续的数学运算
    c = np.array(c, ndmin=1, copy=None)
    # 检查 c 的数据类型的字符是否在 '?bBhHiIlLqQpP' 中
    if c.dtype.char in '?bBhHiIlLqQpP':
        # 如果是,将 c 转换为浮点数类型,避免 astype 在 NA 值时出错
        c = c + 0.0
    
    # 检查 x 是否为元组或列表类型,如果是则转换为 NumPy 数组
    if isinstance(x, (tuple, list)):
        x = np.asarray(x)
    
    # 如果 x 是 NumPy 数组并且 tensor 为真,则将 c 调整为与 x 维度相匹配的形状
    if isinstance(x, np.ndarray) and tensor:
        c = c.reshape(c.shape + (1,)*x.ndim)
    
    # 初始化 c0 为 c 的倒数第一项加上 x 的零乘积
    c0 = c[-1] + x*0
    
    # 从倒数第二项开始迭代计算 c0,每次乘以 x 并加上 c 中的前一个项
    for i in range(2, len(c) + 1):
        c0 = c[-i] + c0*x
    
    # 返回计算得到的 c0
    return c0
# 定义函数 polyvalfromroots,用于基于给定的根在点 x 处评估多项式的值
def polyvalfromroots(x, r, tensor=True):
    """
    Evaluate a polynomial specified by its roots at points x.

    If `r` is of length ``N``, this function returns the value

    .. math:: p(x) = \\prod_{n=1}^{N} (x - r_n)

    The parameter `x` is converted to an array only if it is a tuple or a
    list, otherwise it is treated as a scalar. In either case, either `x`
    or its elements must support multiplication and addition both with
    themselves and with the elements of `r`.

    If `r` is a 1-D array, then ``p(x)`` will have the same shape as `x`.  If `r`
    is multidimensional, then the shape of the result depends on the value of
    `tensor`. If `tensor` is ``True`` the shape will be r.shape[1:] + x.shape;
    that is, each polynomial is evaluated at every value of `x`. If `tensor` is
    ``False``, the shape will be r.shape[1:]; that is, each polynomial is
    evaluated only for the corresponding broadcast value of `x`. Note that
    scalars have shape (,).

    .. versionadded:: 1.12

    Parameters
    ----------
    x : array_like, compatible object
        If `x` is a list or tuple, it is converted to an ndarray, otherwise
        it is left unchanged and treated as a scalar. In either case, `x`
        or its elements must support addition and multiplication with
        with themselves and with the elements of `r`.
    r : array_like
        Array of roots. If `r` is multidimensional the first index is the
        root index, while the remaining indices enumerate multiple
        polynomials. For instance, in the two dimensional case the roots
        of each polynomial may be thought of as stored in the columns of `r`.
    tensor : boolean, optional
        If True, the shape of the roots array is extended with ones on the
        right, one for each dimension of `x`. Scalars have dimension 0 for this
        action. The result is that every column of coefficients in `r` is
        evaluated for every element of `x`. If False, `x` is broadcast over the
        columns of `r` for the evaluation.  This keyword is useful when `r` is
        multidimensional. The default value is True.

    Returns
    -------
    values : ndarray, compatible object
        The shape of the returned array is described above.

    See Also
    --------
    polyroots, polyfromroots, polyval
    """

    # 判断 x 是否为列表或元组,如果是,则转换为 ndarray
    if isinstance(x, (list, tuple)):
        x = np.array(x)

    # 计算多项式在给定 x 处的值,根据 tensor 参数决定是否进行广播
    if tensor:
        # 广播计算,r 的每列系数对应每个 x 的值进行多项式计算
        values = np.prod(x.reshape(-1, 1) - r, axis=-1)
    else:
        # 非广播计算,每个 x 对应一个多项式的计算结果
        values = np.prod(x - r, axis=0)

    # 返回计算结果
    return values
    """
    将输入的数组 r 转换为至少有一维的 numpy 数组,不进行复制
    r = np.array(r, ndmin=1, copy=None)
    
    如果 r 的数据类型在 '?bBhHiIlLqQpP' 中的一种,将其转换为 np.double 类型
    if r.dtype.char in '?bBhHiIlLqQpP':
        r = r.astype(np.double)
    
    如果 x 是 tuple 或者 list 类型,则将其转换为 numpy 数组
    if isinstance(x, (tuple, list)):
        x = np.asarray(x)
    
    如果 x 是 numpy 数组:
        如果 tensor 为 True,则将 r 重塑为其形状加上 x 维度的 1 的形状
        r = r.reshape(r.shape + (1,)*x.ndim)
        否则,如果 x 的维度数 x.ndim 大于等于 r 的维度数 r.ndim,则抛出 ValueError
        elif x.ndim >= r.ndim:
            raise ValueError("x.ndim must be < r.ndim when tensor == False")
    
    计算并返回 x 与 r 之间的元素级乘积,沿着第 0 轴
    return np.prod(x - r, axis=0)
    """
# 定义一个函数,用于在二维空间中评估多项式的值,即 p(x,y) = ∑ c_{i,j} * x^i * y^j
def polyval2d(x, y, c):
    # 调用内部函数 _valnd,用于计算多项式的值
    return pu._valnd(polyval, c, x, y)


# 定义一个函数,用于在 x 和 y 的笛卡尔积上评估二维多项式的值,即 p(a,b) = ∑ c_{i,j} * a^i * b^j
def polygrid2d(x, y, c):
    """
    Evaluate a 2-D polynomial on the Cartesian product of x and y.

    This function returns the values:

    .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * a^i * b^j

    where the points ``(a, b)`` consist of all pairs formed by taking
    `a` from `x` and `b` from `y`. The resulting points form a grid with
    `x` in the first dimension and `y` in the second.

    The parameters `x` and `y` are converted to arrays only if they are
    tuples or a lists, otherwise they are treated as scalars. In either
    case, either `x` and `y` or their elements must support multiplication
    and addition both with themselves and with the elements of `c`.

    If `c` has fewer than two dimensions, ones are implicitly appended to
    its shape to make it 2-D. The shape of the result will be c.shape[2:] +
    x.shape + y.shape.

    Parameters
    ----------
    x, y : array_like, compatible objects
        The two dimensional series is evaluated at the points ``(x, y)``,
        where `x` and `y` must have the same shape. If `x` or `y` is a list
        or tuple, it is first converted to an ndarray, otherwise it is left
        unchanged and, if it isn't an ndarray, it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficient of the term
        of multi-degree i,j is contained in ``c[i,j]``. If `c` has
        dimension greater than two the remaining indices enumerate multiple
        sets of coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the two dimensional polynomial at points formed with
        pairs of corresponding values from `x` and `y`.

    See Also
    --------
    polyval, polygrid2d, polyval3d, polygrid3d

    Notes
    -----

    .. versionadded:: 1.7.0

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = ((1, 2, 3), (4, 5, 6))
    >>> P.polyval2d(1, 1, c) 
    21.0

    """
    x, y : array_like, compatible objects
        两个二维序列,将在`x`和`y`的笛卡尔积点处进行评估。如果`x`或`y`是列表或元组,首先将其转换为ndarray;否则保持不变,如果它不是ndarray,则将其视为标量。
    c : array_like
        按照顺序排列的系数数组,其中i,j次项的系数包含在``c[i,j]``中。如果`c`的维度大于二,则剩余的索引用于列举多组系数。

    Returns
    -------
    values : ndarray, compatible object
        在`x`和`y`的笛卡尔积点处的二维多项式的值。

    See Also
    --------
    polyval, polyval2d, polyval3d, polygrid3d

    Notes
    -----

    .. versionadded:: 1.7.0

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = ((1, 2, 3), (4, 5, 6))
    >>> P.polygrid2d([0, 1], [0, 1], c)
    array([[ 1.,  6.],
           [ 5., 21.]])
    
    """
    return pu._gridnd(polyval, c, x, y)
# 计算三维多项式在点 (x, y, z) 处的值。

# 导入模块,使用 _valnd 函数计算多维多项式的值
def polyval3d(x, y, z, c):
    return pu._valnd(polyval, c, x, y, z)


# 计算三维多项式在 x, y, z 的笛卡尔积上的值。

# 导入模块,使用 _valnd 函数计算三维网格上的多项式值
def polygrid3d(x, y, z, c):
    x, y, z : array_like, compatible objects
        三维系列在笛卡尔积 `x`, `y`, 和 `z` 点处进行评估。如果 `x`, `y`, 或 `z` 是列表或元组,它们首先被转换为 ndarray 数组;否则保持不变,并且如果它不是 ndarray 数组,则被视为标量。
    c : array_like
        系数数组,按照这样的顺序排列:i, j 次项的系数包含在 ``c[i,j]`` 中。如果 `c` 的维度大于两,剩余的索引用来枚举多组系数。

    Returns
    -------
    values : ndarray, compatible object
        二维多项式在 `x` 和 `y` 的笛卡尔积点处的值。

    See Also
    --------
    polyval, polyval2d, polygrid2d, polyval3d

    Notes
    -----

    .. versionadded:: 1.7.0
        添加于版本 1.7.0

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> c = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
    >>> P.polygrid3d([0, 1], [0, 1], [0, 1], c)
    array([[ 1., 13.],
           [ 6., 51.]])

    """
    return pu._gridnd(polyval, c, x, y, z)
def polyvander(x, deg):
    """Vandermonde matrix of given degree.

    Returns the Vandermonde matrix of degree `deg` and sample points
    `x`. The Vandermonde matrix is defined by

    .. math:: V[..., i] = x^i,

    where ``0 <= i <= deg``. The leading indices of `V` index the elements of
    `x` and the last index is the power of `x`.

    If `c` is a 1-D array of coefficients of length ``n + 1`` and `V` is the
    matrix ``V = polyvander(x, n)``, then ``np.dot(V, c)`` and
    ``polyval(x, c)`` are the same up to roundoff. This equivalence is
    useful both for least squares fitting and for the evaluation of a large
    number of polynomials of the same degree and sample points.

    Parameters
    ----------
    x : array_like
        Array of points. The dtype is converted to float64 or complex128
        depending on whether any of the elements are complex. If `x` is
        scalar it is converted to a 1-D array.
    deg : int
        Degree of the resulting matrix.

    Returns
    -------
    vander : ndarray.
        The Vandermonde matrix. The shape of the returned matrix is
        ``x.shape + (deg + 1,)``, where the last index is the power of `x`.
        The dtype will be the same as the converted `x`.

    See Also
    --------
    polyvander2d, polyvander3d

    Examples
    --------
    The Vandermonde matrix of degree ``deg = 5`` and sample points
    ``x = [-1, 2, 3]`` contains the element-wise powers of `x` 
    from 0 to 5 as its columns.

    >>> from numpy.polynomial import polynomial as P
    >>> x, deg = [-1, 2, 3], 5
    >>> P.polyvander(x=x, deg=deg)
    array([[  1.,  -1.,   1.,  -1.,   1.,  -1.],
           [  1.,   2.,   4.,   8.,  16.,  32.],
           [  1.,   3.,   9.,  27.,  81., 243.]])

    """
    # Convert deg to integer if possible, raising ValueError if deg < 0
    ideg = pu._as_int(deg, "deg")
    if ideg < 0:
        raise ValueError("deg must be non-negative")

    # Ensure x is a 1-D array of float64 or complex128 type
    x = np.array(x, copy=None, ndmin=1) + 0.0

    # Prepare dimensions for the Vandermonde matrix
    dims = (ideg + 1,) + x.shape
    dtyp = x.dtype

    # Initialize an empty array v with specified dimensions and dtype
    v = np.empty(dims, dtype=dtyp)

    # Fill the first row of v with 1's
    v[0] = x*0 + 1

    # Fill subsequent rows of v with powers of x up to degree ideg
    if ideg > 0:
        v[1] = x
        for i in range(2, ideg + 1):
            v[i] = v[i-1]*x

    # Rearrange axes of v to have the last axis as the power of x
    return np.moveaxis(v, 0, -1)
    # 返回两个多项式 Vandermonde 矩阵的张量积结果,对应给定的点和最大次数
    # 用于生成多维情况下的伪 Vandermonde 矩阵,用于多项式拟合和评估
    # Parameters 参数
    # ----------
    # x, y : array_like
    #     点的坐标数组,形状相同。元素的数据类型会转换为 float64 或 complex128,取决于是否有复数元素。标量将转换为 1-D 数组。
    # deg : list of ints
    #     最大次数的列表,格式为 [x_deg, y_deg]。

    # Returns 返回值
    # -------
    # vander2d : ndarray
    #     返回矩阵的形状为 ``x.shape + (order,)``,其中 :math:`order = (deg[0]+1)*(deg[1]+1)`。数据类型与转换后的 `x` 和 `y` 相同。

    # See Also 参见
    # --------
    # polyvander, polyvander3d, polyval2d, polyval3d

    # Examples 示例
    # --------
    # 给定样本点 ``x = [-1, 2]`` 和 ``y = [1, 3]``,生成度为 ``[1, 2]`` 的二维伪 Vandermonde 矩阵如下:

    # >>> from numpy.polynomial import polynomial as P
    # >>> x = np.array([-1, 2])
    # >>> y = np.array([1, 3])
    # >>> m, n = 1, 2
    # >>> deg = np.array([m, n])
    # >>> V = P.polyvander2d(x=x, y=y, deg=deg)
    # >>> V
    # array([[ 1.,  1.,  1., -1., -1., -1.],
    #        [ 1.,  3.,  9.,  2.,  6., 18.]])

    # 可以验证任意 ``0 <= i <= m`` 和 ``0 <= j <= n`` 的列:

    # >>> i, j = 0, 1
    # >>> V[:, (deg[1]+1)*i + j] == x**i * y**j
    # array([ True,  True])

    # 当 ``y`` 点全部为零且度为 ``[m, 0]`` 时,样本点 ``x`` 的一维 Vandermonde 矩阵是二维伪 Vandermonde 矩阵的特例。

    # >>> P.polyvander2d(x=x, y=0*x, deg=(m, 0)) == P.polyvander(x=x, deg=m)
    # array([[ True,  True],
    #        [ True,  True]])

    """
    return pu._vander_nd_flat((polyvander, polyvander), (x, y), deg)
# 多项式Vandermonde矩阵生成函数,用于三维情况

def polyvander3d(x, y, z, deg):
    """Pseudo-Vandermonde matrix of given degrees.

    Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
    points ``(x, y, z)``. If `l`, `m`, `n` are the given degrees in `x`, `y`, `z`,
    then The pseudo-Vandermonde matrix is defined by

    .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = x^i * y^j * z^k,

    where ``0 <= i <= l``, ``0 <= j <= m``, and ``0 <= k <= n``.  The leading
    indices of `V` index the points ``(x, y, z)`` and the last index encodes
    the powers of `x`, `y`, and `z`.

    If ``V = polyvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns
    of `V` correspond to the elements of a 3-D coefficient array `c` of
    shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order

    .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...

    and  ``np.dot(V, c.flat)`` and ``polyval3d(x, y, z, c)`` will be the
    same up to roundoff. This equivalence is useful both for least squares
    fitting and for the evaluation of a large number of 3-D polynomials
    of the same degrees and sample points.

    Parameters
    ----------
    x, y, z : array_like
        Arrays of point coordinates, all of the same shape. The dtypes will
        be converted to either float64 or complex128 depending on whether
        any of the elements are complex. Scalars are converted to 1-D
        arrays.
    deg : list of ints
        List of maximum degrees of the form [x_deg, y_deg, z_deg].

    Returns
    -------
    vander3d : ndarray
        The shape of the returned matrix is ``x.shape + (order,)``, where
        :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`.  The dtype will
        be the same as the converted `x`, `y`, and `z`.

    See Also
    --------
    polyvander, polyvander3d, polyval2d, polyval3d

    Notes
    -----

    .. versionadded:: 1.7.0

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> x = np.asarray([-1, 2, 1])
    >>> y = np.asarray([1, -2, -3])
    >>> z = np.asarray([2, 2, 5])
    >>> l, m, n = [2, 2, 1]
    >>> deg = [l, m, n]
    >>> V = P.polyvander3d(x=x, y=y, z=z, deg=deg)
    >>> V
    array([[  1.,   2.,   1.,   2.,   1.,   2.,  -1.,  -2.,  -1.,
             -2.,  -1.,  -2.,   1.,   2.,   1.,   2.,   1.,   2.],
           [  1.,   2.,  -2.,  -4.,   4.,   8.,   2.,   4.,  -4.,
             -8.,   8.,  16.,   4.,   8.,  -8., -16.,  16.,  32.],
           [  1.,   5.,  -3., -15.,   9.,  45.,   1.,   5.,  -3.,
            -15.,   9.,  45.,   1.,   5.,  -3., -15.,   9.,  45.]])

    We can verify the columns for any ``0 <= i <= l``, ``0 <= j <= m``,
    and ``0 <= k <= n``

    >>> i, j, k = 2, 1, 0
    >>> V[:, (m+1)*(n+1)*i + (n+1)*j + k] == x**i * y**j * z**k
    array([ True,  True,  True])

    """
    # 调用私有函数 `_vander_nd_flat` 生成高维Vandermonde矩阵
    return pu._vander_nd_flat((polyvander, polyvander, polyvander), (x, y, z), deg)
    # 返回多项式拟合的系数,该多项式的阶数为 `deg`,通过最小二乘法拟合给定点 `x` 上的数据值 `y`。
    # 如果 `y` 是一维的,则返回的系数也是一维的。如果 `y` 是二维的,则对每一列 `y` 进行多次拟合,
    # 并将结果系数存储在返回的二维数组的相应列中。
    Return the coefficients of a polynomial of degree `deg` that is the
    least squares fit to the data values `y` given at points `x`. If `y` is
    1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple
    fits are done, one for each column of `y`, and the resulting
    coefficients are stored in the corresponding columns of a 2-D return.
    The fitted polynomial(s) are in the form
    
    # 多项式的形式为
    
    .. math::  p(x) = c_0 + c_1 * x + ... + c_n * x^n,
    
    where `n` is `deg`.
    
    Parameters
    ----------
    x : array_like, shape (`M`,)
        x-coordinates of the `M` sample (data) points ``(x[i], y[i])``.
    y : array_like, shape (`M`,) or (`M`, `K`)
        y-coordinates of the sample points.  Several sets of sample points
        sharing the same x-coordinates can be (independently) fit with one
        call to `polyfit` by passing in for `y` a 2-D array that contains
        one data set per column.
    deg : int or 1-D array_like
        Degree(s) of the fitting polynomials. If `deg` is a single integer
        all terms up to and including the `deg`'th term are included in the
        fit. For NumPy versions >= 1.11.0 a list of integers specifying the
        degrees of the terms to include may be used instead.
    rcond : float, optional
        Relative condition number of the fit.  Singular values smaller
        than `rcond`, relative to the largest singular value, will be
        ignored.  The default value is ``len(x)*eps``, where `eps` is the
        relative precision of the platform's float type, about 2e-16 in
        most cases.
    full : bool, optional
        Switch determining the nature of the return value.  When ``False``
        (the default) just the coefficients are returned; when ``True``,
        diagnostic information from the singular value decomposition (used
        to solve the fit's matrix equation) is also returned.
    w : array_like, shape (`M`,), optional
        Weights. If not None, the weight ``w[i]`` applies to the unsquared
        residual ``y[i] - y_hat[i]`` at ``x[i]``. Ideally the weights are
        chosen so that the errors of the products ``w[i]*y[i]`` all have the
        same variance.  When using inverse-variance weighting, use
        ``w[i] = 1/sigma(y[i])``.  The default value is None.
    
        .. versionadded:: 1.5.0
    
    Returns
    -------
    coef : ndarray, shape (`deg` + 1,) or (`deg` + 1, `K`)
        Polynomial coefficients ordered from low to high.  If `y` was 2-D,
        the coefficients in column `k` of `coef` represent the polynomial
        fit to the data in `y`'s `k`-th column.
    [residuals, rank, singular_values, rcond] : list
        # 返回值列表,仅当 `full == True` 时返回以下值:

        - residuals -- 最小二乘拟合的残差平方和
        - rank -- 缩放后的范德蒙德矩阵的数值秩
        - singular_values -- 缩放后的范德蒙德矩阵的奇异值
        - rcond -- `rcond` 的值

        更多细节,请参阅 `numpy.linalg.lstsq`。

    Raises
    ------
    RankWarning
        # 如果最小二乘拟合中的矩阵秩不足,将引发此警告。
        仅当 `full == False` 时才会引发警告。可以通过以下方式关闭警告:

        >>> import warnings
        >>> warnings.simplefilter('ignore', np.exceptions.RankWarning)

    See Also
    --------
    numpy.polynomial.chebyshev.chebfit
    numpy.polynomial.legendre.legfit
    numpy.polynomial.laguerre.lagfit
    numpy.polynomial.hermite.hermfit
    numpy.polynomial.hermite_e.hermefit
    polyval : 计算多项式值。
    polyvander : 用于幂的范德蒙德矩阵。
    numpy.linalg.lstsq : 计算矩阵的最小二乘拟合。
    scipy.interpolate.UnivariateSpline : 计算样条拟合。

    Notes
    -----
    解决方案是多项式 `p` 的系数,该多项式最小化加权平方误差的和

    .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,

    其中 :math:`w_j` 是权重。该问题通过建立(通常为)过度确定的矩阵方程解决:

    .. math:: V(x) * c = w * y,

    其中 `V` 是 `x` 的加权伪范德蒙德矩阵,`c` 是要解的系数,`w` 是权重,`y` 是观察值。然后使用 `V` 的奇异值分解来解决此方程。

    如果 `V` 的某些奇异值很小以至于被忽略(且 `full` == ``False``),将引发 `~exceptions.RankWarning`。这意味着系数值可能确定不好。通常通过拟合较低阶多项式可以消除警告(但这可能不是您想要的;如果您有选择阶数的独立理由不起作用,您可能需要:a)重新考虑这些理由,和/或 b)重新考虑数据质量)。`rcond` 参数也可以设置为小于其默认值的值,但所得拟合可能是虚假的,并且可能会受到舍入误差的大贡献。

    使用双精度进行多项式拟合通常在多项式阶数约为 20 时“失败”。使用Chebyshev或Legendre系列进行拟合通常条件更好,但很大程度上取决于样本点的分布和数据的平滑性。如果拟合质量不够好,样条可能是一个好的选择。

    Examples
    --------
    >>> from numpy.polynomial import polynomial as P
    >>> x = np.linspace(-1,1,51)  # 生成包含51个元素的数组x,范围从-1到1,等间隔分布
    >>> rng = np.random.default_rng()
    >>> err = rng.normal(size=len(x))  # 创建长度与x相同的正态分布误差数组err
    >>> y = x**3 - x + err  # 根据公式y = x^3 - x + Gaussian noise计算y数组
    >>> c, stats = P.polyfit(x,y,3,full=True)  # 对x和y进行3次多项式拟合,返回拟合系数c和统计信息stats
    >>> c # c[0], c[1] 大约为 -1,c[2] 应该接近于0,c[3] 大约为 1
    array([ 0.23111996, -1.02785049, -0.2241444 ,  1.08405657])  # 可能有所变化
    >>> stats # 注意到较大的SSR,解释了拟合结果较差的原因
    [array([48.312088]),  # 可能有所变化
     4,
     array([1.38446749, 1.32119158, 0.50443316, 0.28853036]),
     1.1324274851176597e-14]

    Same thing without the added noise  # 在没有额外噪声的情况下进行相同的操作

    >>> y = x**3 - x  # 根据公式y = x^3 - x 计算y数组
    >>> c, stats = P.polyfit(x,y,3,full=True)  # 对x和y进行3次多项式拟合,返回拟合系数c和统计信息stats
    >>> c # c[0], c[1] 约为 -1,c[2] 应该非常接近于0,c[3] 约为 1
    array([-6.73496154e-17, -1.00000000e+00,  0.00000000e+00,  1.00000000e+00])
    >>> stats # 注意到极小的SSR
    [array([8.79579319e-31]),  # 可能有所变化
     4,
     array([1.38446749, 1.32119158, 0.50443316, 0.28853036]),
     1.1324274851176597e-14]

    """
    return pu._fit(polyvander, x, y, deg, rcond, full, w)


注释:
- `x = np.linspace(-1,1,51)`:生成包含51个元素的数组x,范围从-11,等间隔分布。
- `rng = np.random.default_rng()`:创建一个默认的随机数生成器对象。
- `err = rng.normal(size=len(x))`:创建一个长度与x相同的数组,其中的元素符合标准正态分布。
- `y = x**3 - x + err`:根据公式y = x^3 - x + Gaussian noise 计算y数组,将x的立方、x本身和误差err相加。
- `c, stats = P.polyfit(x,y,3,full=True)`:使用3次多项式拟合函数`P.polyfit`拟合x和y,返回拟合系数c和拟合统计信息stats。
- `c`:拟合系数数组c,其中c[0]、c[1]等分别对应多项式的各阶系数。
- `stats`:拟合的统计信息数组,包含SSR(残差平方和)、拟合自由度、标准误差估计和拟合使用的条件数等。
- `return pu._fit(polyvander, x, y, deg, rcond, full, w)`:返回调用`pu._fit`函数的结果,该函数用于多项式拟合过程中计算内部使用的Vandermonde矩阵和其他相关信息。
# c 是一个修剪后的副本,确保其是一个多项式系数的数组表示
[c] = pu.as_series([c])
# 如果系数数组的长度小于2,则抛出数值错误,因为多项式至少需要二次项
if len(c) < 2:
    raise ValueError('Series must have maximum degree of at least 1.')
# 如果系数数组的长度为2,则直接返回多项式的根,这时候只有一个根
if len(c) == 2:
    return np.array([-c[0]/c[1]])

# 计算多项式的次数
n = len(c) - 1
# 创建一个以系数数据类型为元素的零矩阵,维度为 (n, n)
mat = np.zeros((n, n), dtype=c.dtype)
# 获取矩阵的对角线下方的元素,并设置为1,这是伴随矩阵的特性
bot = mat.reshape(-1)[n::n+1]
bot[...] = 1
# 将矩阵的最后一列设置为系数数组除去最高阶系数后的数组与最高阶系数的比值的负数
mat[:, -1] -= c[:-1] / c[-1]
# 返回计算得到的伴随矩阵
return mat
    # 返回函数内部变量 r 的值作为函数的返回结果
    return r
# 多项式类,继承自ABCPolyBase
class Polynomial(ABCPolyBase):
    """A power series class.

    The Polynomial class provides the standard Python numerical methods
    '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the
    attributes and methods listed below.

    Parameters
    ----------
    coef : array_like
        Polynomial coefficients in order of increasing degree, i.e.,
        ``(1, 2, 3)`` give ``1 + 2*x + 3*x**2``.
    domain : (2,) array_like, optional
        Domain to use. The interval ``[domain[0], domain[1]]`` is mapped
        to the interval ``[window[0], window[1]]`` by shifting and scaling.
        The default value is [-1, 1].
    window : (2,) array_like, optional
        Window, see `domain` for its use. The default value is [-1, 1].

        .. versionadded:: 1.6.0
    symbol : str, optional
        Symbol used to represent the independent variable in string
        representations of the polynomial expression, e.g. for printing.
        The symbol must be a valid Python identifier. Default value is 'x'.

        .. versionadded:: 1.24

    """
    
    # 静态方法:多项式加法
    _add = staticmethod(polyadd)
    # 静态方法:多项式减法
    _sub = staticmethod(polysub)
    # 静态方法:多项式乘法
    _mul = staticmethod(polymul)
    # 静态方法:多项式整除
    _div = staticmethod(polydiv)
    # 静态方法:多项式幂运算
    _pow = staticmethod(polypow)
    # 静态方法:计算多项式在给定点的值
    _val = staticmethod(polyval)
    # 静态方法:多项式积分
    _int = staticmethod(polyint)
    # 静态方法:多项式求导
    _der = staticmethod(polyder)
    # 静态方法:多项式拟合
    _fit = staticmethod(polyfit)
    # 静态方法:生成连接两点的线性多项式
    _line = staticmethod(polyline)
    # 静态方法:计算多项式的根
    _roots = staticmethod(polyroots)
    # 静态方法:根据给定的根生成多项式
    _fromroots = staticmethod(polyfromroots)

    # 虚拟属性:多项式的定义域
    domain = np.array(polydomain)
    # 虚拟属性:多项式的窗口
    window = np.array(polydomain)
    # 虚拟属性:基函数名称,默认为None
    basis_name = None

    @classmethod
    def _str_term_unicode(cls, i, arg_str):
        """Generate a unicode representation of a term in the polynomial.

        Parameters
        ----------
        i : int
            The exponent of the term.
        arg_str : str
            The string representation of the term without exponent.

        Returns
        -------
        str
            Unicode representation of the term.

        """
        if i == '1':
            return f"·{arg_str}"
        else:
            return f"·{arg_str}{i.translate(cls._superscript_mapping)}"

    @staticmethod
    def _str_term_ascii(i, arg_str):
        """Generate an ASCII representation of a term in the polynomial.

        Parameters
        ----------
        i : int
            The exponent of the term.
        arg_str : str
            The string representation of the term without exponent.

        Returns
        -------
        str
            ASCII representation of the term.

        """
        if i == '1':
            return f" {arg_str}"
        else:
            return f" {arg_str}**{i}"

    @staticmethod
    def _repr_latex_term(i, arg_str, needs_parens):
        """Generate a LaTeX representation of a term in the polynomial.

        Parameters
        ----------
        i : int
            The exponent of the term.
        arg_str : str
            The LaTeX string representation of the term without exponent.
        needs_parens : bool
            Whether the term needs to be wrapped in parentheses.

        Returns
        -------
        str
            LaTeX representation of the term.

        """
        if needs_parens:
            arg_str = rf"\left({arg_str}\right)"
        if i == 0:
            return '1'
        elif i == 1:
            return arg_str
        else:
            return f"{arg_str}^{{{i}}}"

.\numpy\numpy\polynomial\polynomial.pyi

# 从 typing 模块导入 Any 类型
from typing import Any

# 从 numpy 中导入 int_ 类型和 NDArray 类型
from numpy import int_
from numpy.typing import NDArray

# 从 numpy.polynomial._polybase 模块导入 ABCPolyBase 类
from numpy.polynomial._polybase import ABCPolyBase

# 从 numpy.polynomial.polyutils 模块导入 trimcoef 函数
from numpy.polynomial.polyutils import trimcoef

# 定义一个包含 __all__ 属性的列表,用于模块的公开接口
__all__: list[str]

# 将 trimcoef 函数赋值给 polytrim 变量,用于多项式的系数修剪
polytrim = trimcoef

# 定义以下四个变量,均为 int_ 类型的一维数组 NDArray[int_]
polydomain: NDArray[int_]
polyzero: NDArray[int_]
polyone: NDArray[int_]
polyx: NDArray[int_]

# 定义以下函数,用于多项式操作,具体实现略去,可能包括多项式创建、加减乘除、求导积分、值计算等
def polyline(off, scl): ...

def polyfromroots(roots): ...

def polyadd(c1, c2): ...

def polysub(c1, c2): ...

def polymulx(c): ...

def polymul(c1, c2): ...

def polydiv(c1, c2): ...

def polypow(c, pow, maxpower=...): ...

def polyder(c, m=..., scl=..., axis=...): ...

def polyint(c, m=..., k=..., lbnd=..., scl=..., axis=...): ...

def polyval(x, c, tensor=...): ...

def polyvalfromroots(x, r, tensor=...): ...

def polyval2d(x, y, c): ...

def polygrid2d(x, y, c): ...

def polyval3d(x, y, z, c): ...

def polygrid3d(x, y, z, c): ...

def polyvander(x, deg): ...

def polyvander2d(x, y, deg): ...

def polyvander3d(x, y, z, deg): ...

def polyfit(x, y, deg, rcond=..., full=..., w=...): ...

def polyroots(c): ...

# 定义一个继承自 ABCPolyBase 的 Polynomial 类,表示多项式
class Polynomial(ABCPolyBase):
    # domain、window 和 basis_name 是该类的成员变量,类型为 Any,用于描述多项式的领域、窗口和基础名称
    domain: Any
    window: Any
    basis_name: Any

.\numpy\numpy\polynomial\polyutils.py

# 导入操作符和函数工具
import operator
# 导入函数工具包装,用于函数操作
import functools
# 导入警告模块
import warnings

# 导入 NumPy 库并重命名为 np
import numpy as np

# 从 NumPy 库中导入 dragon4_positional 和 dragon4_scientific 函数
from numpy._core.multiarray import dragon4_positional, dragon4_scientific
# 从 NumPy 库中导入 RankWarning 异常类
from numpy.exceptions import RankWarning

# 模块中公开的函数和类列表
__all__ = [
    'as_series', 'trimseq', 'trimcoef', 'getdomain', 'mapdomain', 'mapparms',
    'format_float']

# 
# 辅助函数用于将输入转换为 1-D 数组
#

def trimseq(seq):
    """Remove small Poly series coefficients.

    Parameters
    ----------
    seq : sequence
        Sequence of Poly series coefficients.

    Returns
    -------
    series : sequence
        Subsequence with trailing zeros removed. If the resulting sequence
        would be empty, return the first element. The returned sequence may
        or may not be a view.

    Notes
    -----
    Do not lose the type info if the sequence contains unknown objects.

    """
    # 如果序列长度为 0 或者最后一个元素不为 0,则直接返回序列
    if len(seq) == 0 or seq[-1] != 0:
        return seq
    else:
        # 从后向前遍历序列,找到第一个不为 0 的元素的索引
        for i in range(len(seq) - 1, -1, -1):
            if seq[i] != 0:
                break
        # 返回从开头到第一个不为 0 的元素的子序列
        return seq[:i+1]


def as_series(alist, trim=True):
    """
    Return argument as a list of 1-d arrays.

    The returned list contains array(s) of dtype double, complex double, or
    object.  A 1-d argument of shape ``(N,)`` is parsed into ``N`` arrays of
    size one; a 2-d argument of shape ``(M,N)`` is parsed into ``M`` arrays
    of size ``N`` (i.e., is "parsed by row"); and a higher dimensional array
    raises a Value Error if it is not first reshaped into either a 1-d or 2-d
    array.

    Parameters
    ----------
    alist : array_like
        A 1- or 2-d array_like
    trim : boolean, optional
        When True, trailing zeros are removed from the inputs.
        When False, the inputs are passed through intact.

    Returns
    -------
    [a1, a2,...] : list of 1-D arrays
        A copy of the input data as a list of 1-d arrays.

    Raises
    ------
    ValueError
        Raised when `as_series` cannot convert its input to 1-d arrays, or at
        least one of the resulting arrays is empty.

    Examples
    --------
    >>> from numpy.polynomial import polyutils as pu
    >>> a = np.arange(4)
    >>> pu.as_series(a)
    [array([0.]), array([1.]), array([2.]), array([3.])]
    >>> b = np.arange(6).reshape((2,3))
    >>> pu.as_series(b)
    [array([0., 1., 2.]), array([3., 4., 5.])]


    """
    # 如果 trim 参数为 True,则调用 trimseq 函数去除输入序列中的尾部零
    if trim:
        return [trimseq(a) for a in np.atleast_1d(alist)]
    else:
        # 否则直接返回输入的至少为 1-D 的数组列表
        return [np.asarray(a).flatten() for a in np.atleast_1d(alist)]
    """
    将输入的列表转换为 NumPy 数组的列表,每个数组至少有一维,并进行必要的验证和转换操作。

    Parameters:
    - alist: 输入的列表,每个元素将被转换为一个 NumPy 数组
    - trim: 可选参数,默认为 True。如果为 True,则对每个数组进行修剪操作。

    Returns:
    - ret: 转换后的 NumPy 数组的列表

    Raises:
    - ValueError: 如果任何一个数组为空,或者不是一维数组。
    - ValueError: 如果无法找到数组的公共数据类型。
    """
    # 将输入的每个元素转换为 NumPy 数组,确保每个数组至少有一维
    arrays = [np.array(a, ndmin=1, copy=None) for a in alist]
    
    # 检查每个数组是否为空,如果是,则引发异常
    for a in arrays:
        if a.size == 0:
            raise ValueError("Coefficient array is empty")
    
    # 检查每个数组是否为一维数组,如果不是,则引发异常
    if any(a.ndim != 1 for a in arrays):
        raise ValueError("Coefficient array is not 1-d")
    
    # 如果 trim 参数为 True,则对每个数组进行修剪操作
    if trim:
        arrays = [trimseq(a) for a in arrays]

    # 检查是否存在包含对象类型的数组,如果有,则进行特殊处理
    if any(a.dtype == np.dtype(object) for a in arrays):
        ret = []
        for a in arrays:
            if a.dtype != np.dtype(object):
                tmp = np.empty(len(a), dtype=np.dtype(object))
                tmp[:] = a[:]
                ret.append(tmp)
            else:
                ret.append(a.copy())
    else:
        # 尝试找到所有数组的公共数据类型
        try:
            dtype = np.common_type(*arrays)
        except Exception as e:
            raise ValueError("Coefficient arrays have no common type") from e
        
        # 使用公共数据类型创建新的 NumPy 数组列表
        ret = [np.array(a, copy=True, dtype=dtype) for a in arrays]
    
    # 返回转换后的 NumPy 数组列表
    return ret
# 定义函数 trimcoef,用于从多项式中移除末尾的小系数
def trimcoef(c, tol=0):
    """
    Remove "small" "trailing" coefficients from a polynomial.

    "Small" means "small in absolute value" and is controlled by the
    parameter `tol`; "trailing" means highest order coefficient(s), e.g., in
    ``[0, 1, 1, 0, 0]`` (which represents ``0 + x + x**2 + 0*x**3 + 0*x**4``)
    both the 3-rd and 4-th order coefficients would be "trimmed."

    Parameters
    ----------
    c : array_like
        1-d array of coefficients, ordered from lowest order to highest.
    tol : number, optional
        Trailing (i.e., highest order) elements with absolute value less
        than or equal to `tol` (default value is zero) are removed.

    Returns
    -------
    trimmed : ndarray
        1-d array with trailing zeros removed.  If the resulting series
        would be empty, a series containing a single zero is returned.

    Raises
    ------
    ValueError
        If `tol` < 0

    Examples
    --------
    >>> from numpy.polynomial import polyutils as pu
    >>> pu.trimcoef((0,0,3,0,5,0,0))
    array([0.,  0.,  3.,  0.,  5.])
    >>> pu.trimcoef((0,0,1e-3,0,1e-5,0,0),1e-3) # item == tol is trimmed
    array([0.])
    >>> i = complex(0,1) # works for complex
    >>> pu.trimcoef((3e-4,1e-3*(1-i),5e-4,2e-5*(1+i)), 1e-3)
    array([0.0003+0.j   , 0.001 -0.001j])

    """
    # 检查 tol 是否小于 0,若是则抛出 ValueError 异常
    if tol < 0:
        raise ValueError("tol must be non-negative")

    # 将输入系数 c 转换为序列
    [c] = as_series([c])
    # 找到绝对值大于 tol 的系数的索引
    [ind] = np.nonzero(np.abs(c) > tol)
    # 如果没有找到满足条件的索引,则返回一个包含单个零的数组
    if len(ind) == 0:
        return c[:1]*0
    else:
        # 否则,返回从开始到最后一个满足条件的系数的子数组的副本
        return c[:ind[-1] + 1].copy()

# 定义函数 getdomain,用于确定给定横坐标适合的定义域
def getdomain(x):
    """
    Return a domain suitable for given abscissae.

    Find a domain suitable for a polynomial or Chebyshev series
    defined at the values supplied.

    Parameters
    ----------
    x : array_like
        1-d array of abscissae whose domain will be determined.

    Returns
    -------
    domain : ndarray
        1-d array containing two values.  If the inputs are complex, then
        the two returned points are the lower left and upper right corners
        of the smallest rectangle (aligned with the axes) in the complex
        plane containing the points `x`. If the inputs are real, then the
        two points are the ends of the smallest interval containing the
        points `x`.

    See Also
    --------
    mapparms, mapdomain

    Examples
    --------
    >>> from numpy.polynomial import polyutils as pu
    >>> points = np.arange(4)**2 - 5; points
    array([-5, -4, -1,  4])
    >>> pu.getdomain(points)
    array([-5.,  4.])
    >>> c = np.exp(complex(0,1)*np.pi*np.arange(12)/6) # unit circle
    >>> pu.getdomain(c)
    array([-1.-1.j,  1.+1.j])

    """
    # 将输入的 x 转换为序列
    [x] = as_series([x], trim=False)
    # 如果 x 的数据类型为复数,则返回包含 x 所有点的最小矩形的两个角点
    if x.dtype.char in np.typecodes['Complex']:
        rmin, rmax = x.real.min(), x.real.max()
        imin, imax = x.imag.min(), x.imag.max()
        return np.array((complex(rmin, imin), complex(rmax, imax)))
    else:
        # 否则,返回包含 x 所有点的最小区间的两个端点
        return np.array((x.min(), x.max()))

# 定义函数 mapparms,未完待续...
    """
    Linear map parameters between domains.

    Return the parameters of the linear map ``offset + scale*x`` that maps
    `old` to `new` such that ``old[i] -> new[i]``, ``i = 0, 1``.

    Parameters
    ----------
    old, new : array_like
        Domains. Each domain must (successfully) convert to a 1-d array
        containing precisely two values.

    Returns
    -------
    offset, scale : scalars
        The map ``L(x) = offset + scale*x`` maps the first domain to the
        second.

    See Also
    --------
    getdomain, mapdomain

    Notes
    -----
    Also works for complex numbers, and thus can be used to calculate the
    parameters required to map any line in the complex plane to any other
    line therein.

    Examples
    --------
    >>> from numpy.polynomial import polyutils as pu
    >>> pu.mapparms((-1,1),(-1,1))
    (0.0, 1.0)
    >>> pu.mapparms((1,-1),(-1,1))
    (-0.0, -1.0)
    >>> i = complex(0,1)
    >>> pu.mapparms((-i,-1),(1,i))
    ((1+1j), (1-0j))

    """
    # Calculate the length of the old and new domains
    oldlen = old[1] - old[0]
    newlen = new[1] - new[0]
    # Calculate the offset using the formula for linear map parameters
    off = (old[1]*new[0] - old[0]*new[1]) / oldlen
    # Calculate the scale using the ratio of lengths between old and new domains
    scl = newlen / oldlen
    # Return the calculated offset and scale
    return off, scl
def mapdomain(x, old, new):
    """
    Apply linear map to input points.

    The linear map ``offset + scale*x`` that maps the domain `old` to
    the domain `new` is applied to the points `x`.

    Parameters
    ----------
    x : array_like
        Points to be mapped. If `x` is a subtype of ndarray the subtype
        will be preserved.
    old, new : array_like
        The two domains that determine the map.  Each must (successfully)
        convert to 1-d arrays containing precisely two values.

    Returns
    -------
    x_out : ndarray
        Array of points of the same shape as `x`, after application of the
        linear map between the two domains.

    See Also
    --------
    getdomain, mapparms

    Notes
    -----
    Effectively, this implements:

    .. math::
        x\\_out = new[0] + m(x - old[0])

    where

    .. math::
        m = \\frac{new[1]-new[0]}{old[1]-old[0]}

    Examples
    --------
    >>> from numpy.polynomial import polyutils as pu
    >>> old_domain = (-1,1)
    >>> new_domain = (0,2*np.pi)
    >>> x = np.linspace(-1,1,6); x
    array([-1. , -0.6, -0.2,  0.2,  0.6,  1. ])
    >>> x_out = pu.mapdomain(x, old_domain, new_domain); x_out
    array([ 0.        ,  1.25663706,  2.51327412,  3.76991118,  5.02654825, # may vary
            6.28318531])
    >>> x - pu.mapdomain(x_out, new_domain, old_domain)
    array([0., 0., 0., 0., 0., 0.])

    Also works for complex numbers (and thus can be used to map any line in
    the complex plane to any other line therein).

    >>> i = complex(0,1)
    >>> old = (-1 - i, 1 + i)
    >>> new = (-1 + i, 1 - i)
    >>> z = np.linspace(old[0], old[1], 6); z
    array([-1. -1.j , -0.6-0.6j, -0.2-0.2j,  0.2+0.2j,  0.6+0.6j,  1. +1.j ])
    >>> new_z = pu.mapdomain(z, old, new); new_z
    array([-1.0+1.j , -0.6+0.6j, -0.2+0.2j,  0.2-0.2j,  0.6-0.6j,  1.0-1.j ]) # may vary

    """
    x = np.asanyarray(x)  # Convert input `x` to an ndarray if it's not already
    off, scl = mapparms(old, new)  # Calculate offset and scale using mapparms function
    return off + scl*x


def _nth_slice(i, ndim):
    """
    Generate a slice object that selects the i-th index in an array.

    Parameters
    ----------
    i : int
        Index to be selected.
    ndim : int
        Number of dimensions in the array.

    Returns
    -------
    tuple
        Tuple of slice objects where the i-th position is sliced with `slice(None)`.

    """
    sl = [np.newaxis] * ndim  # Create a list of `None` slice objects with length `ndim`
    sl[i] = slice(None)  # Replace the i-th `None` with a full slice (`:`)
    return tuple(sl)  # Return as a tuple of slice objects


def _vander_nd(vander_fs, points, degrees):
    r"""
    A generalization of the Vandermonde matrix for N dimensions

    The result is built by combining the results of 1d Vandermonde matrices,

    .. math::
        W[i_0, \ldots, i_M, j_0, \ldots, j_N] = \prod_{k=0}^N{V_k(x_k)[i_0, \ldots, i_M, j_k]}

    where

    .. math::
        N &= \texttt{len(points)} = \texttt{len(degrees)} = \texttt{len(vander\_fs)} \\
        M &= \texttt{points[k].ndim} \\
        V_k &= \texttt{vander\_fs[k]} \\
        x_k &= \texttt{points[k]} \\
        0 \le j_k &\le \texttt{degrees[k]}

    Expanding the one-dimensional :math:`V_k` functions gives:

    .. math::
        W[i_0, \ldots, i_M, j_0, \ldots, j_N] = \prod_{k=0}^N{B_{k, j_k}(x_k[i_0, \ldots, i_M])}

    where :math:`B_{k,m}` is the m'th basis of the polynomial construction used along
    dimension :math:`k`. For a regular polynomial, :math:`B_{k, m}(x) = P_m(x) = x^m`.

    """
    pass  # Placeholder function, does not perform any operations
    Parameters
    ----------
    vander_fs : Sequence[function(array_like, int) -> ndarray]
        每个轴上要使用的一维范德蒙德函数,例如 `polyvander`
    points : Sequence[array_like]
        点的坐标数组,所有数组的形状必须相同。其元素的数据类型将转换为 float64 或 complex128,具体取决于是否包含复数。标量将转换为一维数组。
        这个参数的长度必须与 `vander_fs` 相同。
    degrees : Sequence[int]
        每个轴要使用的最大阶数(包括在内)。这个参数的长度必须与 `vander_fs` 相同。

    Returns
    -------
    vander_nd : ndarray
        形状为 ``points[0].shape + tuple(d + 1 for d in degrees)`` 的数组。
    """
    # 确定维度数量
    n_dims = len(vander_fs)
    # 检查样本点的维度数量是否与给定的函数数量相同
    if n_dims != len(points):
        raise ValueError(
            f"Expected {n_dims} dimensions of sample points, got {len(points)}")
    # 检查阶数的维度数量是否与给定的函数数量相同
    if n_dims != len(degrees):
        raise ValueError(
            f"Expected {n_dims} dimensions of degrees, got {len(degrees)}")
    # 如果没有提供样本点,则无法猜测 dtype 或形状
    if n_dims == 0:
        raise ValueError("Unable to guess a dtype or shape when no points are given")

    # 将所有点转换为相同的形状和类型
    points = tuple(np.asarray(tuple(points)) + 0.0)

    # 为每个维度生成范德蒙德矩阵,将每个维度的最后一个轴放置在输出的独立尾随轴中
    vander_arrays = (
        vander_fs[i](points[i], degrees[i])[(...,) + _nth_slice(i, n_dims)]
        for i in range(n_dims)
    )

    # 我们已经检查过这不是空的,因此不需要 `initial`
    return functools.reduce(operator.mul, vander_arrays)
def _vander_nd_flat(vander_fs, points, degrees):
    """
    Like `_vander_nd`, but flattens the last ``len(degrees)`` axes into a single axis

    Used to implement the public ``<type>vander<n>d`` functions.
    """
    # 调用 `_vander_nd` 函数,获取多维 Vandermonde 矩阵
    v = _vander_nd(vander_fs, points, degrees)
    # 将多维矩阵展平为最后 ``len(degrees)`` 个轴合并到一个轴
    return v.reshape(v.shape[:-len(degrees)] + (-1,))


def _fromroots(line_f, mul_f, roots):
    """
    Helper function used to implement the ``<type>fromroots`` functions.

    Parameters
    ----------
    line_f : function(float, float) -> ndarray
        The ``<type>line`` function, such as ``polyline``
    mul_f : function(array_like, array_like) -> ndarray
        The ``<type>mul`` function, such as ``polymul``
    roots
        See the ``<type>fromroots`` functions for more detail
    """
    # 如果 roots 为空,则返回一个包含一个元素的数组
    if len(roots) == 0:
        return np.ones(1)
    else:
        # 将 roots 转换为系列,并进行排序
        [roots] = as_series([roots], trim=False)
        roots.sort()
        # 生成关于每个根的线性函数的列表
        p = [line_f(-r, 1) for r in roots]
        n = len(p)
        while n > 1:
            m, r = divmod(n, 2)
            # 对每对线性函数进行乘法运算
            tmp = [mul_f(p[i], p[i+m]) for i in range(m)]
            if r:
                tmp[0] = mul_f(tmp[0], p[-1])
            p = tmp
            n = m
        # 返回最终的多项式系数数组
        return p[0]


def _valnd(val_f, c, *args):
    """
    Helper function used to implement the ``<type>val<n>d`` functions.

    Parameters
    ----------
    val_f : function(array_like, array_like, tensor: bool) -> array_like
        The ``<type>val`` function, such as ``polyval``
    c, args
        See the ``<type>val<n>d`` functions for more detail
    """
    # 将所有参数转换为 NumPy 数组
    args = [np.asanyarray(a) for a in args]
    shape0 = args[0].shape
    # 检查所有参数的形状是否与第一个参数相同
    if not all((a.shape == shape0 for a in args[1:])):
        if len(args) == 3:
            raise ValueError('x, y, z are incompatible')
        elif len(args) == 2:
            raise ValueError('x, y are incompatible')
        else:
            raise ValueError('ordinates are incompatible')
    it = iter(args)
    x0 = next(it)

    # 对第一个参数使用 val_f 函数
    c = val_f(x0, c)
    # 对剩余的参数依次使用 val_f 函数
    for xi in it:
        c = val_f(xi, c, tensor=False)
    # 返回计算结果
    return c


def _gridnd(val_f, c, *args):
    """
    Helper function used to implement the ``<type>grid<n>d`` functions.

    Parameters
    ----------
    val_f : function(array_like, array_like, tensor: bool) -> array_like
        The ``<type>val`` function, such as ``polyval``
    c, args
        See the ``<type>grid<n>d`` functions for more detail
    """
    # 对所有参数依次使用 val_f 函数
    for xi in args:
        c = val_f(xi, c)
    # 返回计算结果
    return c


def _div(mul_f, c1, c2):
    """
    Helper function used to implement the ``<type>div`` functions.

    Implementation uses repeated subtraction of c2 multiplied by the nth basis.
    For some polynomial types, a more efficient approach may be possible.

    Parameters
    ----------
    mul_f : function(array_like, array_like) -> array_like
        The ``<type>mul`` function, such as ``polymul``
    c1, c2
        See the ``<type>div`` functions for more detail
    """
    # c1, c2 are trimmed copies
    # 此处是对 ``<type>div`` 函数的简要描述和提示
    # 将输入的两个参数 c1 和 c2 转换为序列(数组或类似结构),分别存储到 c1 和 c2 中
    [c1, c2] = as_series([c1, c2])
    # 检查 c2 数组的最后一个元素是否为 0,如果是则抛出 ZeroDivisionError 异常
    if c2[-1] == 0:
        raise ZeroDivisionError()

    # 计算 c1 和 c2 的长度,分别存储到 lc1 和 lc2 中
    lc1 = len(c1)
    lc2 = len(c2)
    
    # 如果 c1 的长度小于 c2 的长度,返回一个以 c1[0] 为元素、长度为 0 的数组,并返回 c1
    if lc1 < lc2:
        return c1[:1]*0, c1
    # 如果 c2 的长度为 1,返回 c1 除以 c2 的最后一个元素,以及一个以 c1[0] 为元素、长度为 0 的数组
    elif lc2 == 1:
        return c1/c2[-1], c1[:1]*0
    else:
        # 创建一个类型与 c1 相同的空数组 quo,长度为 lc1 - lc2 + 1
        quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype)
        # 将 rem 初始化为 c1
        rem = c1
        # 从 lc1 - lc2 循环到 0(包括 0)
        for i in range(lc1 - lc2, - 1, -1):
            # 创建一个多项式 p,其中 i 个 0 后接 1,然后与 c2 相乘
            p = mul_f([0]*i + [1], c2)
            # 计算余数 rem 的最后一个元素与 p 的最后一个元素的除法商 q
            q = rem[-1]/p[-1]
            # 更新 rem 为 rem 去除最后一个元素减去 q 乘以 p 去除最后一个元素
            rem = rem[:-1] - q*p[:-1]
            # 将 q 存储到 quo 的第 i 个位置
            quo[i] = q
        # 返回商 quo 和修剪后的余数 trimseq(rem)
        return quo, trimseq(rem)
def _add(c1, c2):
    """ Helper function used to implement the ``<type>add`` functions. """
    # c1, c2 are trimmed copies
    [c1, c2] = as_series([c1, c2])  # 调用as_series函数,将c1和c2转换为Series类型,并进行必要的修剪
    if len(c1) > len(c2):
        c1[:c2.size] += c2  # 如果c1长度大于c2,则将c2加到c1的前c2.size部分
        ret = c1
    else:
        c2[:c1.size] += c1  # 否则,将c1加到c2的前c1.size部分
        ret = c2
    return trimseq(ret)  # 返回修剪过的结果序列


def _sub(c1, c2):
    """ Helper function used to implement the ``<type>sub`` functions. """
    # c1, c2 are trimmed copies
    [c1, c2] = as_series([c1, c2])  # 调用as_series函数,将c1和c2转换为Series类型,并进行必要的修剪
    if len(c1) > len(c2):
        c1[:c2.size] -= c2  # 如果c1长度大于c2,则从c1的前c2.size部分减去c2
        ret = c1
    else:
        c2 = -c2  # 否则,将c2取反
        c2[:c1.size] += c1  # 然后将c1加到c2的前c1.size部分
        ret = c2
    return trimseq(ret)  # 返回修剪过的结果序列


def _fit(vander_f, x, y, deg, rcond=None, full=False, w=None):
    """
    Helper function used to implement the ``<type>fit`` functions.

    Parameters
    ----------
    vander_f : function(array_like, int) -> ndarray
        The 1d vander function, such as ``polyvander``
    x, y, deg
        See the ``<type>fit`` functions for more detail
    """
    x = np.asarray(x) + 0.0  # 将x转换为NumPy数组,并确保是浮点型
    y = np.asarray(y) + 0.0  # 将y转换为NumPy数组,并确保是浮点型
    deg = np.asarray(deg)  # 将deg转换为NumPy数组

    # check arguments.
    if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0:
        raise TypeError("deg must be an int or non-empty 1-D array of int")  # 检查deg的类型和形状是否符合要求
    if deg.min() < 0:
        raise ValueError("expected deg >= 0")  # 检查deg是否都大于等于0
    if x.ndim != 1:
        raise TypeError("expected 1D vector for x")  # 检查x是否是一维数组
    if x.size == 0:
        raise TypeError("expected non-empty vector for x")  # 检查x是否为空
    if y.ndim < 1 or y.ndim > 2:
        raise TypeError("expected 1D or 2D array for y")  # 检查y是否是一维或二维数组
    if len(x) != len(y):
        raise TypeError("expected x and y to have same length")  # 检查x和y的长度是否相同

    if deg.ndim == 0:
        lmax = deg
        order = lmax + 1
        van = vander_f(x, lmax)  # 调用vander_f函数生成Vandermonde矩阵
    else:
        deg = np.sort(deg)
        lmax = deg[-1]
        order = len(deg)
        van = vander_f(x, lmax)[:, deg]  # 对于多项式阶数按deg给出的顺序进行排序,并生成对应的Vandermonde矩阵

    # set up the least squares matrices in transposed form
    lhs = van.T  # 左侧矩阵为Vandermonde矩阵的转置
    rhs = y.T  # 右侧矩阵为y的转置
    if w is not None:
        w = np.asarray(w) + 0.0  # 将权重w转换为NumPy数组,并确保是浮点型
        if w.ndim != 1:
            raise TypeError("expected 1D vector for w")  # 检查w是否是一维数组
        if len(x) != len(w):
            raise TypeError("expected x and w to have same length")  # 检查x和w的长度是否相同
        # apply weights. Don't use inplace operations as they
        # can cause problems with NA.
        lhs = lhs * w  # 对左侧矩阵应用权重w
        rhs = rhs * w  # 对右侧矩阵应用权重w

    # set rcond
    if rcond is None:
        rcond = len(x) * np.finfo(x.dtype).eps  # 如果rcond未指定,则设为x数组中元素类型的机器精度的倍数

    # Determine the norms of the design matrix columns.
    if issubclass(lhs.dtype.type, np.complexfloating):
        scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1))  # 计算复数类型左侧矩阵各列的范数
    else:
        scl = np.sqrt(np.square(lhs).sum(1))  # 计算实数类型左侧矩阵各列的范数
    scl[scl == 0] = 1  # 将范数为0的元素设为1,避免除以0

    # Solve the least squares problem.
    c, resids, rank, s = np.linalg.lstsq(lhs.T / scl, rhs.T, rcond)  # 解最小二乘问题,得到系数c
    c = (c.T / scl).T  # 将系数c按照左侧矩阵列的范数进行归一化

    # Expand c to include non-fitted coefficients which are set to zero
    # 检查 deg 的维度是否大于 0
    if deg.ndim > 0:
        # 如果 c 的维度为 2,则创建一个零矩阵 cc,形状为 (lmax+1, c.shape[1]),数据类型与 c 相同
        if c.ndim == 2:
            cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype)
        else:
            # 否则,创建一个零数组 cc,形状为 (lmax+1),数据类型与 c 相同
            cc = np.zeros(lmax+1, dtype=c.dtype)
        # 将 cc 中索引为 deg 的位置赋值为 c
        cc[deg] = c
        # 将 c 更新为 cc
        c = cc

    # 在秩降低时发出警告
    if rank != order and not full:
        # 创建警告信息字符串
        msg = "The fit may be poorly conditioned"
        # 发出警告,使用 RankWarning 类,设置堆栈深度为 2
        warnings.warn(msg, RankWarning, stacklevel=2)

    # 如果设置为返回完整结果
    if full:
        # 返回 c 和包含剩余项、秩、奇异值、rcond 值的列表
        return c, [resids, rank, s, rcond]
    else:
        # 否则,只返回 c
        return c
# 实现 ``<type>pow`` 函数的辅助函数,用于计算给定系列的幂次方
def _pow(mul_f, c, pow, maxpower):
    """
    Helper function used to implement the ``<type>pow`` functions.

    Parameters
    ----------
    mul_f : function(array_like, array_like) -> ndarray
        用于乘法操作的函数,如 ``polymul``
    c : array_like
        系列系数的一维数组
    pow, maxpower
        ``<type>pow`` 函数的参数,详见其具体说明
    """
    # c 是裁剪后的副本
    [c] = as_series([c])
    power = int(pow)
    # 检查幂次必须为非负整数
    if power != pow or power < 0:
        raise ValueError("Power must be a non-negative integer.")
    # 如果 maxpower 不为 None,则检查幂次不能超过 maxpower
    elif maxpower is not None and power > maxpower:
        raise ValueError("Power is too large")
    elif power == 0:
        # 幂次为 0 时,返回系数为 1 的数组
        return np.array([1], dtype=c.dtype)
    elif power == 1:
        # 幂次为 1 时,直接返回系列 c
        return c
    else:
        # 否则,通过循环计算幂次的结果
        # 可以通过使用二进制的幂次计算来提高效率
        prd = c
        for i in range(2, power + 1):
            prd = mul_f(prd, c)
        return prd


# 类似于 `operator.index`,但当传入不正确类型时会抛出自定义异常的函数
def _as_int(x, desc):
    """
    Like `operator.index`, but emits a custom exception when passed an 
    incorrect type

    Parameters
    ----------
    x : int-like
        要解释为整数的值
    desc : str
        错误消息中包含的描述信息

    Raises
    ------
    TypeError : 若 x 是浮点数或非数值类型
    """
    try:
        return operator.index(x)
    except TypeError as e:
        raise TypeError(f"{desc} must be an integer, received {x}") from e


# 格式化浮点数 x,可选择是否使用括号包裹
def format_float(x, parens=False):
    if not np.issubdtype(type(x), np.floating):
        # 若 x 不是浮点数类型,则直接返回其字符串表示
        return str(x)

    opts = np.get_printoptions()

    if np.isnan(x):
        # 若 x 是 NaN,则返回指定的 NaN 字符串
        return opts['nanstr']
    elif np.isinf(x):
        # 若 x 是无穷大,则返回指定的无穷大字符串
        return opts['infstr']

    exp_format = False
    if x != 0:
        a = np.abs(x)
        # 根据浮点数的大小和精度设置,决定是否使用科学计数法
        if a >= 1.e8 or a < 10**min(0, -(opts['precision']-1)//2):
            exp_format = True

    trim, unique = '0', True
    if opts['floatmode'] == 'fixed':
        trim, unique = 'k', False

    if exp_format:
        # 若使用科学计数法,则调用 dragon4_scientific 函数进行格式化
        s = dragon4_scientific(x, precision=opts['precision'],
                               unique=unique, trim=trim, 
                               sign=opts['sign'] == '+')
        if parens:
            # 若需要用括号包裹,则添加括号
            s = '(' + s + ')'
    else:
        # 若使用定点表示法,则调用 dragon4_positional 函数进行格式化
        s = dragon4_positional(x, precision=opts['precision'],
                               fractional=True,
                               unique=unique, trim=trim,
                               sign=opts['sign'] == '+')
    return s

.\numpy\numpy\polynomial\polyutils.pyi

# 定义全局变量 __all__,表示在使用 from module import * 时应该导入的符号列表
__all__: list[str]

# 定义函数 trimseq,用于修剪序列,返回一个修剪后的序列
def trimseq(seq):
    ...

# 定义函数 as_series,将列表转换为序列(可能是 pandas.Series),可选地修剪元素
def as_series(alist, trim=...):
    ...

# 定义函数 trimcoef,用于修剪系数,返回修剪后的系数
def trimcoef(c, tol=...):
    ...

# 定义函数 getdomain,获取变量 x 的定义域
def getdomain(x):
    ...

# 定义函数 mapparms,将旧参数映射到新参数,返回映射后的结果
def mapparms(old, new):
    ...

# 定义函数 mapdomain,将变量 x 从旧域映射到新域,返回映射后的结果
def mapdomain(x, old, new):
    ...

# 定义函数 format_float,格式化浮点数 x 的字符串表示,可选地加括号
def format_float(x, parens=...):
    ...

.\numpy\numpy\polynomial\tests\test_chebyshev.py

"""Tests for chebyshev module.

"""
# 导入 reduce 函数
from functools import reduce

# 导入 numpy 库,并使用别名 np
import numpy as np
# 导入 numpy.polynomial.chebyshev 模块,并使用别名 cheb
import numpy.polynomial.chebyshev as cheb
# 导入 numpy.polynomial.polynomial 模块中的 polyval 函数
from numpy.polynomial.polynomial import polyval
# 导入 numpy.testing 模块中的断言函数
from numpy.testing import (
    assert_almost_equal, assert_raises, assert_equal, assert_,
    )

# 定义函数 trim,用于裁剪 Chebyshev 系数
def trim(x):
    return cheb.chebtrim(x, tol=1e-6)

# 定义一系列 Chebyshev 多项式的系数列表
T0 = [1]
T1 = [0, 1]
T2 = [-1, 0, 2]
T3 = [0, -3, 0, 4]
T4 = [1, 0, -8, 0, 8]
T5 = [0, 5, 0, -20, 0, 16]
T6 = [-1, 0, 18, 0, -48, 0, 32]
T7 = [0, -7, 0, 56, 0, -112, 0, 64]
T8 = [1, 0, -32, 0, 160, 0, -256, 0, 128]
T9 = [0, 9, 0, -120, 0, 432, 0, -576, 0, 256]

# 将所有 Chebyshev 多项式的系数列表放入一个列表中
Tlist = [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]

# 定义一个名为 TestPrivate 的测试类
class TestPrivate:

    # 定义测试方法 test__cseries_to_zseries,测试 _cseries_to_zseries 函数
    def test__cseries_to_zseries(self):
        # 循环测试多次
        for i in range(5):
            # 创建输入数组 inp 和目标数组 tgt
            inp = np.array([2] + [1]*i, np.double)
            tgt = np.array([.5]*i + [2] + [.5]*i, np.double)
            # 调用 _cseries_to_zseries 函数并断言结果是否与目标数组相等
            res = cheb._cseries_to_zseries(inp)
            assert_equal(res, tgt)

    # 定义测试方法 test__zseries_to_cseries,测试 _zseries_to_cseries 函数
    def test__zseries_to_cseries(self):
        # 循环测试多次
        for i in range(5):
            # 创建输入数组 inp 和目标数组 tgt
            inp = np.array([.5]*i + [2] + [.5]*i, np.double)
            tgt = np.array([2] + [1]*i, np.double)
            # 调用 _zseries_to_cseries 函数并断言结果是否与目标数组相等
            res = cheb._zseries_to_cseries(inp)
            assert_equal(res, tgt)


# 定义一个名为 TestConstants 的测试类
class TestConstants:

    # 定义测试方法 test_chebdomain,测试 chebdomain 常量
    def test_chebdomain(self):
        assert_equal(cheb.chebdomain, [-1, 1])

    # 定义测试方法 test_chebzero,测试 chebzero 常量
    def test_chebzero(self):
        assert_equal(cheb.chebzero, [0])

    # 定义测试方法 test_chebone,测试 chebone 常量
    def test_chebone(self):
        assert_equal(cheb.chebone, [1])

    # 定义测试方法 test_chebx,测试 chebx 常量
    def test_chebx(self):
        assert_equal(cheb.chebx, [0, 1])


# 定义一个名为 TestArithmetic 的测试类
class TestArithmetic:

    # 定义测试方法 test_chebadd,测试 chebadd 函数
    def test_chebadd(self):
        # 循环测试多次
        for i in range(5):
            for j in range(5):
                msg = f"At i={i}, j={j}"
                # 创建目标数组 tgt 和调用 chebadd 函数得到的结果数组 res
                tgt = np.zeros(max(i, j) + 1)
                tgt[i] += 1
                tgt[j] += 1
                res = cheb.chebadd([0]*i + [1], [0]*j + [1])
                # 断言修剪后的 res 是否与 tgt 相等
                assert_equal(trim(res), trim(tgt), err_msg=msg)

    # 定义测试方法 test_chebsub,测试 chebsub 函数
    def test_chebsub(self):
        # 循环测试多次
        for i in range(5):
            for j in range(5):
                msg = f"At i={i}, j={j}"
                # 创建目标数组 tgt 和调用 chebsub 函数得到的结果数组 res
                tgt = np.zeros(max(i, j) + 1)
                tgt[i] += 1
                tgt[j] -= 1
                res = cheb.chebsub([0]*i + [1], [0]*j + [1])
                # 断言修剪后的 res 是否与 tgt 相等
                assert_equal(trim(res), trim(tgt), err_msg=msg)

    # 定义测试方法 test_chebmulx,测试 chebmulx 函数
    def test_chebmulx(self):
        assert_equal(cheb.chebmulx([0]), [0])
        assert_equal(cheb.chebmulx([1]), [0, 1])
        # 循环测试多次
        for i in range(1, 5):
            ser = [0]*i + [1]
            tgt = [0]*(i - 1) + [.5, 0, .5]
            # 断言 chebmulx 函数的结果是否与目标数组 tgt 相等
            assert_equal(cheb.chebmulx(ser), tgt)

    # 定义测试方法 test_chebmul,测试 chebmul 函数
    def test_chebmul(self):
        # 循环测试多次
        for i in range(5):
            for j in range(5):
                msg = f"At i={i}, j={j}"
                # 创建目标数组 tgt 和调用 chebmul 函数得到的结果数组 res
                tgt = np.zeros(i + j + 1)
                tgt[i + j] += .5
                tgt[abs(i - j)] += .5
                res = cheb.chebmul([0]*i + [1], [0]*j + [1])
                # 断言修剪后的 res 是否与 tgt 相等
                assert_equal(trim(res), trim(tgt), err_msg=msg)
    # 测试 chebdiv 函数的功能
    def test_chebdiv(self):
        # 循环遍历 i 的范围为 0 到 4
        for i in range(5):
            # 循环遍历 j 的范围为 0 到 4
            for j in range(5):
                # 创建格式化消息,指示当前循环的 i 和 j 值
                msg = f"At i={i}, j={j}"
                # 创建长度为 i+1 的列表 ci,最后一个元素为 1,其余为 0
                ci = [0]*i + [1]
                # 创建长度为 j+1 的列表 cj,最后一个元素为 1,其余为 0
                cj = [0]*j + [1]
                # 调用 chebadd 函数计算 ci 和 cj 的和,存储在 tgt 中
                tgt = cheb.chebadd(ci, cj)
                # 调用 chebdiv 函数计算 tgt 除以 ci 的商 quo 和余数 rem
                quo, rem = cheb.chebdiv(tgt, ci)
                # 调用 chebadd 函数计算 quo 乘以 ci 加上 rem 的结果 res
                res = cheb.chebadd(cheb.chebmul(quo, ci), rem)
                # 使用 assert_equal 函数验证 trim(res) 是否等于 trim(tgt),否则输出错误消息 msg
                assert_equal(trim(res), trim(tgt), err_msg=msg)
    
    # 测试 chebpow 函数的功能
    def test_chebpow(self):
        # 循环遍历 i 的范围为 0 到 4
        for i in range(5):
            # 循环遍历 j 的范围为 0 到 4
            for j in range(5):
                # 创建格式化消息,指示当前循环的 i 和 j 值
                msg = f"At i={i}, j={j}"
                # 创建长度为 i+1 的 numpy 数组 c,包含从 0 到 i 的整数
                c = np.arange(i + 1)
                # 使用 reduce 函数和 chebmul 函数计算 c 的 j 次乘方,存储在 tgt 中
                tgt = reduce(cheb.chebmul, [c]*j, np.array([1]))
                # 调用 chebpow 函数计算 c 的 j 次幂,存储在 res 中
                res = cheb.chebpow(c, j)
                # 使用 assert_equal 函数验证 trim(res) 是否等于 trim(tgt),否则输出错误消息 msg
                assert_equal(trim(res), trim(tgt), err_msg=msg)
class TestEvaluation:
    # 定义一维多项式系数 [1, 2, 3]
    c1d = np.array([2.5, 2., 1.5])
    # 计算二维系数矩阵
    c2d = np.einsum('i,j->ij', c1d, c1d)
    # 计算三维系数张量
    c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)

    # 生成范围在 [-1, 1) 内的随机数
    x = np.random.random((3, 5))*2 - 1
    # 计算多项式在 x 上的值
    y = polyval(x, [1., 2., 3.])

    def test_chebval(self):
        # 检查空输入的情况
        assert_equal(cheb.chebval([], [1]).size, 0)

        # 检查正常输入的情况
        x = np.linspace(-1, 1)
        y = [polyval(x, c) for c in Tlist]
        for i in range(10):
            msg = f"At i={i}"
            tgt = y[i]
            # 检查结果与目标值的近似程度
            res = cheb.chebval(x, [0]*i + [1])
            assert_almost_equal(res, tgt, err_msg=msg)

        # 检查形状是否保持不变
        for i in range(3):
            dims = [2]*i
            x = np.zeros(dims)
            # 检查输出的形状
            assert_equal(cheb.chebval(x, [1]).shape, dims)
            assert_equal(cheb.chebval(x, [1, 0]).shape, dims)
            assert_equal(cheb.chebval(x, [1, 0, 0]).shape, dims)

    def test_chebval2d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        # 测试异常情况
        assert_raises(ValueError, cheb.chebval2d, x1, x2[:2], self.c2d)

        # 测试数值
        tgt = y1*y2
        res = cheb.chebval2d(x1, x2, self.c2d)
        assert_almost_equal(res, tgt)

        # 检查输出的形状
        z = np.ones((2, 3))
        res = cheb.chebval2d(z, z, self.c2d)
        assert_(res.shape == (2, 3))

    def test_chebval3d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        # 测试异常情况
        assert_raises(ValueError, cheb.chebval3d, x1, x2, x3[:2], self.c3d)

        # 测试数值
        tgt = y1*y2*y3
        res = cheb.chebval3d(x1, x2, x3, self.c3d)
        assert_almost_equal(res, tgt)

        # 检查输出的形状
        z = np.ones((2, 3))
        res = cheb.chebval3d(z, z, z, self.c3d)
        assert_(res.shape == (2, 3))

    def test_chebgrid2d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        # 测试数值
        tgt = np.einsum('i,j->ij', y1, y2)
        res = cheb.chebgrid2d(x1, x2, self.c2d)
        assert_almost_equal(res, tgt)

        # 检查输出的形状
        z = np.ones((2, 3))
        res = cheb.chebgrid2d(z, z, self.c2d)
        assert_(res.shape == (2, 3)*2)

    def test_chebgrid3d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        # 测试数值
        tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
        res = cheb.chebgrid3d(x1, x2, x3, self.c3d)
        assert_almost_equal(res, tgt)

        # 检查输出的形状
        z = np.ones((2, 3))
        res = cheb.chebgrid3d(z, z, z, self.c3d)
        assert_(res.shape == (2, 3)*3)


class TestIntegral:
    # 定义一个测试方法,用于验证 chebint 函数的 axis 参数是否正常工作
    def test_chebint_axis(self):
        # 创建一个 3x4 的随机数数组
        c2d = np.random.random((3, 4))

        # 对 c2d 的每一列应用 cheb.chebint 函数,并竖直堆叠得到目标数组 tgt
        tgt = np.vstack([cheb.chebint(c) for c in c2d.T]).T
        # 调用 cheb.chebint 函数,指定 axis=0,计算结果存入 res
        res = cheb.chebint(c2d, axis=0)
        # 断言 res 与 tgt 的值几乎相等
        assert_almost_equal(res, tgt)

        # 对 c2d 的每一行应用 cheb.chebint 函数,并竖直堆叠得到目标数组 tgt
        tgt = np.vstack([cheb.chebint(c) for c in c2d])
        # 调用 cheb.chebint 函数,指定 axis=1,计算结果存入 res
        res = cheb.chebint(c2d, axis=1)
        # 断言 res 与 tgt 的值几乎相等
        assert_almost_equal(res, tgt)

        # 对 c2d 的每一行应用 cheb.chebint 函数,并竖直堆叠得到目标数组 tgt,同时指定 k=3
        tgt = np.vstack([cheb.chebint(c, k=3) for c in c2d])
        # 调用 cheb.chebint 函数,指定 axis=1 和 k=3,计算结果存入 res
        res = cheb.chebint(c2d, k=3, axis=1)
        # 断言 res 与 tgt 的值几乎相等
        assert_almost_equal(res, tgt)
class TestDerivative:

    def test_chebder(self):
        # 检查异常情况
        assert_raises(TypeError, cheb.chebder, [0], .5)
        assert_raises(ValueError, cheb.chebder, [0], -1)

        # 检查零阶导数不产生变化
        for i in range(5):
            tgt = [0]*i + [1]
            res = cheb.chebder(tgt, m=0)
            assert_equal(trim(res), trim(tgt))

        # 检查导数与积分的逆过程
        for i in range(5):
            for j in range(2, 5):
                tgt = [0]*i + [1]
                res = cheb.chebder(cheb.chebint(tgt, m=j), m=j)
                assert_almost_equal(trim(res), trim(tgt))

        # 检查带有缩放的导数
        for i in range(5):
            for j in range(2, 5):
                tgt = [0]*i + [1]
                res = cheb.chebder(cheb.chebint(tgt, m=j, scl=2), m=j, scl=.5)
                assert_almost_equal(trim(res), trim(tgt))

    def test_chebder_axis(self):
        # 检查轴关键字的工作情况
        c2d = np.random.random((3, 4))

        tgt = np.vstack([cheb.chebder(c) for c in c2d.T]).T
        res = cheb.chebder(c2d, axis=0)
        assert_almost_equal(res, tgt)

        tgt = np.vstack([cheb.chebder(c) for c in c2d])
        res = cheb.chebder(c2d, axis=1)
        assert_almost_equal(res, tgt)


class TestVander:
    # 在 [-1, 1) 范围内随机生成一些值
    x = np.random.random((3, 5))*2 - 1

    def test_chebvander(self):
        # 检查 1 维 x 的情况
        x = np.arange(3)
        v = cheb.chebvander(x, 3)
        assert_(v.shape == (3, 4))
        for i in range(4):
            coef = [0]*i + [1]
            assert_almost_equal(v[..., i], cheb.chebval(x, coef))

        # 检查 2 维 x 的情况
        x = np.array([[1, 2], [3, 4], [5, 6]])
        v = cheb.chebvander(x, 3)
        assert_(v.shape == (3, 2, 4))
        for i in range(4):
            coef = [0]*i + [1]
            assert_almost_equal(v[..., i], cheb.chebval(x, coef))

    def test_chebvander2d(self):
        # 同时测试非方形系数数组的情况,也测试 chebval2d
        x1, x2, x3 = self.x
        c = np.random.random((2, 3))
        van = cheb.chebvander2d(x1, x2, [1, 2])
        tgt = cheb.chebval2d(x1, x2, c)
        res = np.dot(van, c.flat)
        assert_almost_equal(res, tgt)

        # 检查形状
        van = cheb.chebvander2d([x1], [x2], [1, 2])
        assert_(van.shape == (1, 5, 6))

    def test_chebvander3d(self):
        # 同时测试非方形系数数组的情况,也测试 chebval3d
        x1, x2, x3 = self.x
        c = np.random.random((2, 3, 4))
        van = cheb.chebvander3d(x1, x2, x3, [1, 2, 3])
        tgt = cheb.chebval3d(x1, x2, x3, c)
        res = np.dot(van, c.flat)
        assert_almost_equal(res, tgt)

        # 检查形状
        van = cheb.chebvander3d([x1], [x2], [x3], [1, 2, 3])
        assert_(van.shape == (1, 5, 24))


class TestFitting:

class TestInterpolate:

    def f(self, x):
        return x * (x - 1) * (x - 2)
    # 定义测试函数,用于检查是否引发特定异常
    def test_raises(self):
        # 断言调用 cheb.chebinterpolate(self.f, -1) 会引发 ValueError 异常
        assert_raises(ValueError, cheb.chebinterpolate, self.f, -1)
        # 断言调用 cheb.chebinterpolate(self.f, 10.) 会引发 TypeError 异常
        assert_raises(TypeError, cheb.chebinterpolate, self.f, 10.)

    # 定义测试函数,用于检查插值结果的维度是否符合预期
    def test_dimensions(self):
        # 遍历多个插值的阶数
        for deg in range(1, 5):
            # 断言 cheb.chebinterpolate(self.f, deg) 的形状为 (deg + 1,)
            assert_(cheb.chebinterpolate(self.f, deg).shape == (deg + 1,))

    # 定义测试函数,用于检查插值的逼近精度
    def test_approximation(self):

        # 定义一个函数 powx,用于计算 x 的 p 次幂
        def powx(x, p):
            return x**p

        # 生成一个包含 10 个均匀分布点的数组 x
        x = np.linspace(-1, 1, 10)
        
        # 遍历不同的插值阶数 deg
        for deg in range(0, 10):
            # 遍历每个阶数下的指数 p
            for p in range(0, deg + 1):
                # 调用 cheb.chebinterpolate(powx, deg, (p,)) 进行 Chebyshev 插值
                c = cheb.chebinterpolate(powx, deg, (p,))
                # 断言 Chebyshev 插值结果 cheb.chebval(x, c) 与真实值 powx(x, p) 的近似精度在小数点后 12 位
                assert_almost_equal(cheb.chebval(x, c), powx(x, p), decimal=12)
class TestCompanion:

    # 检查在调用 cheb.chebcompanion 函数时是否会引发 ValueError 异常
    def test_raises(self):
        assert_raises(ValueError, cheb.chebcompanion, [])
        assert_raises(ValueError, cheb.chebcompanion, [1])

    # 检查 cheb.chebcompanion 函数返回的矩阵形状是否符合预期
    def test_dimensions(self):
        for i in range(1, 5):
            coef = [0]*i + [1]
            assert_(cheb.chebcompanion(coef).shape == (i, i))

    # 检查对于线性多项式,cheb.chebcompanion 函数返回的首个元素是否正确
    def test_linear_root(self):
        assert_(cheb.chebcompanion([1, 2])[0, 0] == -.5)


class TestGauss:

    # 测试 cheb.chebgauss 函数计算结果的正交性
    def test_100(self):
        x, w = cheb.chebgauss(100)

        # 测试正交性。注意需要对结果进行归一化,以避免由于类似 Laguerre 函数的快速增长而导致的混淆
        v = cheb.chebvander(x, 99)
        vv = np.dot(v.T * w, v)
        vd = 1/np.sqrt(vv.diagonal())
        vv = vd[:, None] * vv * vd
        assert_almost_equal(vv, np.eye(100))

        # 检查单位函数的积分是否正确
        tgt = np.pi
        assert_almost_equal(w.sum(), tgt)


class TestMisc:

    # 测试 cheb.chebfromroots 函数对于空列表输入的情况
    def test_chebfromroots(self):
        res = cheb.chebfromroots([])
        assert_almost_equal(trim(res), [1])

        # 测试 cheb.chebfromroots 函数对于不同根数的情况
        for i in range(1, 5):
            roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
            tgt = [0]*i + [1]
            res = cheb.chebfromroots(roots)*2**(i-1)
            assert_almost_equal(trim(res), trim(tgt))

    # 测试 cheb.chebroots 函数对于不同情况下的根的计算
    def test_chebroots(self):
        assert_almost_equal(cheb.chebroots([1]), [])
        assert_almost_equal(cheb.chebroots([1, 2]), [-.5])
        for i in range(2, 5):
            tgt = np.linspace(-1, 1, i)
            res = cheb.chebroots(cheb.chebfromroots(tgt))
            assert_almost_equal(trim(res), trim(tgt))

    # 测试 cheb.chebtrim 函数对于多项式系数的截断
    def test_chebtrim(self):
        coef = [2, -1, 1, 0]

        # 测试异常情况
        assert_raises(ValueError, cheb.chebtrim, coef, -1)

        # 测试结果
        assert_equal(cheb.chebtrim(coef), coef[:-1])
        assert_equal(cheb.chebtrim(coef, 1), coef[:-3])
        assert_equal(cheb.chebtrim(coef, 2), [0])

    # 测试 cheb.chebline 函数的行为
    def test_chebline(self):
        assert_equal(cheb.chebline(3, 4), [3, 4])

    # 测试 cheb.cheb2poly 函数的行为
    def test_cheb2poly(self):
        for i in range(10):
            assert_almost_equal(cheb.cheb2poly([0]*i + [1]), Tlist[i])

    # 测试 cheb.poly2cheb 函数的行为
    def test_poly2cheb(self):
        for i in range(10):
            assert_almost_equal(cheb.poly2cheb(Tlist[i]), [0]*i + [1])

    # 测试 cheb.chebweight 函数的行为
    def test_weight(self):
        x = np.linspace(-1, 1, 11)[1:-1]
        tgt = 1./(np.sqrt(1 + x) * np.sqrt(1 - x))
        res = cheb.chebweight(x)
        assert_almost_equal(res, tgt)
    # 定义测试函数 test_chebpts1,用于测试 cheb.chebpts1 函数的不同输入情况
    def test_chebpts1(self):
        # 测试异常情况:当输入为浮点数 1.5 时,应抛出 ValueError 异常
        assert_raises(ValueError, cheb.chebpts1, 1.5)
        # 测试异常情况:当输入为整数 0 时,应抛出 ValueError 异常
        assert_raises(ValueError, cheb.chebpts1, 0)

        # 测试函数的输出结果是否与预期目标 tgt 相近
        tgt = [0]
        assert_almost_equal(cheb.chebpts1(1), tgt)
        tgt = [-0.70710678118654746, 0.70710678118654746]
        assert_almost_equal(cheb.chebpts1(2), tgt)
        tgt = [-0.86602540378443871, 0, 0.86602540378443871]
        assert_almost_equal(cheb.chebpts1(3), tgt)
        tgt = [-0.9238795325, -0.3826834323, 0.3826834323, 0.9238795325]
        assert_almost_equal(cheb.chebpts1(4), tgt)

    # 定义测试函数 test_chebpts2,用于测试 cheb.chebpts2 函数的不同输入情况
    def test_chebpts2(self):
        # 测试异常情况:当输入为浮点数 1.5 时,应抛出 ValueError 异常
        assert_raises(ValueError, cheb.chebpts2, 1.5)
        # 测试异常情况:当输入为整数 1 时,应抛出 ValueError 异常
        assert_raises(ValueError, cheb.chebpts2, 1)

        # 测试函数的输出结果是否与预期目标 tgt 相近
        tgt = [-1, 1]
        assert_almost_equal(cheb.chebpts2(2), tgt)
        tgt = [-1, 0, 1]
        assert_almost_equal(cheb.chebpts2(3), tgt)
        tgt = [-1, -0.5, .5, 1]
        assert_almost_equal(cheb.chebpts2(4), tgt)
        tgt = [-1.0, -0.707106781187, 0, 0.707106781187, 1.0]
        assert_almost_equal(cheb.chebpts2(5), tgt)

.\numpy\numpy\polynomial\tests\test_classes.py

"""Test inter-conversion of different polynomial classes.

This tests the convert and cast methods of all the polynomial classes.

"""
# 导入所需模块和库
import operator as op
from numbers import Number

import pytest  # 导入 pytest 测试框架
import numpy as np  # 导入 NumPy 库
from numpy.polynomial import (  # 导入 NumPy 中的多项式类
    Polynomial, Legendre, Chebyshev, Laguerre, Hermite, HermiteE)
from numpy.testing import (  # 导入 NumPy 测试工具
    assert_almost_equal, assert_raises, assert_equal, assert_,
    )
from numpy.exceptions import RankWarning  # 导入 NumPy 异常处理模块

#
# fixtures
#

# 定义测试用的多项式类和对应的名称
classes = (
    Polynomial, Legendre, Chebyshev, Laguerre,
    Hermite, HermiteE
    )
classids = tuple(cls.__name__ for cls in classes)

@pytest.fixture(params=classes, ids=classids)
def Poly(request):
    return request.param

#
# helper functions
#

# 定义辅助函数 assert_poly_almost_equal,用于比较两个多项式几乎相等
random = np.random.random


def assert_poly_almost_equal(p1, p2, msg=""):
    try:
        # 检查域和窗口是否相同
        assert_(np.all(p1.domain == p2.domain))
        assert_(np.all(p1.window == p2.window))
        # 检查系数是否几乎相等
        assert_almost_equal(p1.coef, p2.coef)
    except AssertionError:
        msg = f"Result: {p1}\nTarget: {p2}"
        raise AssertionError(msg)


#
# Test conversion methods that depend on combinations of two classes.
#

# 设置两个多项式类 Poly1 和 Poly2 用于测试转换
Poly1 = Poly
Poly2 = Poly


def test_conversion(Poly1, Poly2):
    x = np.linspace(0, 1, 10)
    coef = random((3,))

    d1 = Poly1.domain + random((2,))*.25
    w1 = Poly1.window + random((2,))*.25
    p1 = Poly1(coef, domain=d1, window=w1)

    d2 = Poly2.domain + random((2,))*.25
    w2 = Poly2.window + random((2,))*.25
    p2 = p1.convert(kind=Poly2, domain=d2, window=w2)

    # 断言转换后的多项式与预期的域和窗口几乎相等,并且在给定的点上几乎相等
    assert_almost_equal(p2.domain, d2)
    assert_almost_equal(p2.window, w2)
    assert_almost_equal(p2(x), p1(x))


def test_cast(Poly1, Poly2):
    x = np.linspace(0, 1, 10)
    coef = random((3,))

    d1 = Poly1.domain + random((2,))*.25
    w1 = Poly1.window + random((2,))*.25
    p1 = Poly1(coef, domain=d1, window=w1)

    d2 = Poly2.domain + random((2,))*.25
    w2 = Poly2.window + random((2,))*.25
    p2 = Poly2.cast(p1, domain=d2, window=w2)

    # 断言转换后的多项式与预期的域和窗口几乎相等,并且在给定的点上几乎相等
    assert_almost_equal(p2.domain, d2)
    assert_almost_equal(p2.window, w2)
    assert_almost_equal(p2(x), p1(x))


#
# test methods that depend on one class
#


def test_identity(Poly):
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    x = np.linspace(d[0], d[1], 11)
    p = Poly.identity(domain=d, window=w)
    # 断言身份多项式的域和窗口与预期相等,并且在给定的点上几乎相等
    assert_equal(p.domain, d)
    assert_equal(p.window, w)
    assert_almost_equal(p(x), x)


def test_basis(Poly):
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    p = Poly.basis(5, domain=d, window=w)
    # 断言基函数多项式的域和窗口与预期相等,并且系数为预期的基函数系数
    assert_equal(p.domain, d)
    assert_equal(p.window, w)
    assert_equal(p.coef, [0]*5 + [1])


def test_fromroots(Poly):
    # 检查通过给定根来生成多项式,确保多项式的次数、域和窗口正确
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    r = random((5,))
    p1 = Poly.fromroots(r, domain=d, window=w)
    assert_equal(p1.degree(), len(r))
    assert_equal(p1.domain, d)
    # 断言:验证对象 p1 的 window 属性是否与预期值 w 相等
    assert_equal(p1.window, w)
    # 断言:验证对象 p1 在输入 r 处的计算结果是否接近 0
    assert_almost_equal(p1(r), 0)

    # 检查多项式是否为首一多项式(最高次数项系数为 1)
    # 获取当前多项式类的域和窗口设置
    pdom = Polynomial.domain
    pwin = Polynomial.window
    # 将 p1 转换为指定域和窗口的多项式对象 p2
    p2 = Polynomial.cast(p1, domain=pdom, window=pwin)
    # 断言:验证 p2 的最高次数项系数是否接近于 1
    assert_almost_equal(p2.coef[-1], 1)
def test_bad_conditioned_fit(Poly):

    x = [0., 0., 1.]
    y = [1., 2., 3.]

    # 检查是否引发了 RankWarning 警告
    with pytest.warns(RankWarning) as record:
        # 对 Poly 对象进行拟合,预期引发 RankWarning 警告
        Poly.fit(x, y, 2)
    # 断言第一个记录的警告消息是 "The fit may be poorly conditioned"
    assert record[0].message.args[0] == "The fit may be poorly conditioned"


def test_fit(Poly):

    def f(x):
        return x*(x - 1)*(x - 2)
    x = np.linspace(0, 3)
    y = f(x)

    # 检查默认的 domain 和 window 值
    p = Poly.fit(x, y, 3)
    assert_almost_equal(p.domain, [0, 3])
    assert_almost_equal(p(x), y)
    assert_equal(p.degree(), 3)

    # 检查使用给定的 domain 和 window 值
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    p = Poly.fit(x, y, 3, domain=d, window=w)
    assert_almost_equal(p(x), y)
    assert_almost_equal(p.domain, d)
    assert_almost_equal(p.window, w)
    p = Poly.fit(x, y, [0, 1, 2, 3], domain=d, window=w)
    assert_almost_equal(p(x), y)
    assert_almost_equal(p.domain, d)
    assert_almost_equal(p.window, w)

    # 检查使用类的 domain 默认值
    p = Poly.fit(x, y, 3, [])
    assert_equal(p.domain, Poly.domain)
    assert_equal(p.window, Poly.window)
    p = Poly.fit(x, y, [0, 1, 2, 3], [])
    assert_equal(p.domain, Poly.domain)
    assert_equal(p.window, Poly.window)

    # 检查 fit 方法是否接受权重
    w = np.zeros_like(x)
    z = y + random(y.shape)*.25
    w[::2] = 1
    p1 = Poly.fit(x[::2], z[::2], 3)
    p2 = Poly.fit(x, z, 3, w=w)
    p3 = Poly.fit(x, z, [0, 1, 2, 3], w=w)
    assert_almost_equal(p1(x), p2(x))
    assert_almost_equal(p2(x), p3(x))


def test_equal(Poly):
    p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3])
    p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3])
    p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3])
    p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2])
    assert_(p1 == p1)
    assert_(not p1 == p2)
    assert_(not p1 == p3)
    assert_(not p1 == p4)


def test_not_equal(Poly):
    p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3])
    p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3])
    p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3])
    p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2])
    assert_(not p1 != p1)
    assert_(p1 != p2)
    assert_(p1 != p3)
    assert_(p1 != p4)


def test_add(Poly):
    # 检查加法的交换性,而非数值正确性
    c1 = list(random((4,)) + .5)
    c2 = list(random((3,)) + .5)
    p1 = Poly(c1)
    p2 = Poly(c2)
    p3 = p1 + p2
    assert_poly_almost_equal(p2 + p1, p3)
    assert_poly_almost_equal(p1 + c2, p3)
    assert_poly_almost_equal(c2 + p1, p3)
    assert_poly_almost_equal(p1 + tuple(c2), p3)
    assert_poly_almost_equal(tuple(c2) + p1, p3)
    assert_poly_almost_equal(p1 + np.array(c2), p3)
    assert_poly_almost_equal(np.array(c2) + p1, p3)
    assert_raises(TypeError, op.add, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(TypeError, op.add, p1, Poly([0], window=Poly.window + 1))
    # 如果 Poly 类型是 Polynomial 类型的话,执行以下语句块
    if Poly is Polynomial:
        # 断言应该会抛出 TypeError 异常,使用 op.add 对象试图将 p1 与 Chebyshev([0]) 相加
        assert_raises(TypeError, op.add, p1, Chebyshev([0]))
    # 如果 Poly 类型不是 Polynomial 类型的话,执行以下语句块
    else:
        # 断言应该会抛出 TypeError 异常,使用 op.add 对象试图将 p1 与 Polynomial([0]) 相加
        assert_raises(TypeError, op.add, p1, Polynomial([0]))
def test_sub(Poly):
    # 定义一个测试函数,用于测试多项式对象的减法操作
    # 这里的测试侧重于检查交换性,而不是数值上的正确性

    # 生成随机系数数组,并创建两个多项式对象
    c1 = list(random((4,)) + .5)
    c2 = list(random((3,)) + .5)
    p1 = Poly(c1)
    p2 = Poly(c2)

    # 计算两个多项式的差,并进行断言验证
    p3 = p1 - p2
    assert_poly_almost_equal(p2 - p1, -p3)  # 断言交换性质
    assert_poly_almost_equal(p1 - c2, p3)
    assert_poly_almost_equal(c2 - p1, -p3)
    assert_poly_almost_equal(p1 - tuple(c2), p3)
    assert_poly_almost_equal(tuple(c2) - p1, -p3)
    assert_poly_almost_equal(p1 - np.array(c2), p3)
    assert_poly_almost_equal(np.array(c2) - p1, -p3)

    # 测试异常情况:类型错误
    assert_raises(TypeError, op.sub, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(TypeError, op.sub, p1, Poly([0], window=Poly.window + 1))
    if Poly is Polynomial:
        assert_raises(TypeError, op.sub, p1, Chebyshev([0]))
    else:
        assert_raises(TypeError, op.sub, p1, Polynomial([0]))


def test_mul(Poly):
    # 定义一个测试函数,用于测试多项式对象的乘法操作

    # 生成随机系数数组,并创建两个多项式对象
    c1 = list(random((4,)) + .5)
    c2 = list(random((3,)) + .5)
    p1 = Poly(c1)
    p2 = Poly(c2)

    # 计算两个多项式的乘积,并进行断言验证
    p3 = p1 * p2
    assert_poly_almost_equal(p2 * p1, p3)  # 断言交换性质
    assert_poly_almost_equal(p1 * c2, p3)
    assert_poly_almost_equal(c2 * p1, p3)
    assert_poly_almost_equal(p1 * tuple(c2), p3)
    assert_poly_almost_equal(tuple(c2) * p1, p3)
    assert_poly_almost_equal(p1 * np.array(c2), p3)
    assert_poly_almost_equal(np.array(c2) * p1, p3)

    # 测试乘以标量的情况
    assert_poly_almost_equal(p1 * 2, p1 * Poly([2]))
    assert_poly_almost_equal(2 * p1, p1 * Poly([2]))

    # 测试异常情况:类型错误
    assert_raises(TypeError, op.mul, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(TypeError, op.mul, p1, Poly([0], window=Poly.window + 1))
    if Poly is Polynomial:
        assert_raises(TypeError, op.mul, p1, Chebyshev([0]))
    else:
        assert_raises(TypeError, op.mul, p1, Polynomial([0]))


def test_floordiv(Poly):
    # 定义一个测试函数,用于测试多项式对象的整除操作

    # 生成随机系数数组,并创建三个多项式对象
    c1 = list(random((4,)) + .5)
    c2 = list(random((3,)) + .5)
    c3 = list(random((2,)) + .5)
    p1 = Poly(c1)
    p2 = Poly(c2)
    p3 = Poly(c3)

    # 计算一个复合多项式,并从中提取系数作为数组
    p4 = p1 * p2 + p3
    c4 = list(p4.coef)

    # 断言整除操作的结果
    assert_poly_almost_equal(p4 // p2, p1)
    assert_poly_almost_equal(p4 // c2, p1)
    assert_poly_almost_equal(c4 // p2, p1)
    assert_poly_almost_equal(p4 // tuple(c2), p1)
    assert_poly_almost_equal(tuple(c4) // p2, p1)
    assert_poly_almost_equal(p4 // np.array(c2), p1)
    assert_poly_almost_equal(np.array(c4) // p2, p1)

    # 测试整除以标量的情况
    assert_poly_almost_equal(2 // p2, Poly([0]))
    assert_poly_almost_equal(p2 // 2, 0.5 * p2)

    # 测试异常情况:类型错误
    assert_raises(
        TypeError, op.floordiv, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(
        TypeError, op.floordiv, p1, Poly([0], window=Poly.window + 1))
    if Poly is Polynomial:
        assert_raises(TypeError, op.floordiv, p1, Chebyshev([0]))
    else:
        assert_raises(TypeError, op.floordiv, p1, Polynomial([0]))


def test_truediv(Poly):
    # 定义一个测试函数,用于测试多项式对象的真除操作

    # 创建一个简单的多项式对象和它的倍数
    p1 = Poly([1, 2, 3])
    p2 = p1 * 5

    # 这里没有具体的测试动作,仅提供了注释说明
    # 真除法仅在分母是数字且不是 Python 布尔值时有效
    # 遍历 numpy 中定义的标量类型
    for stype in np.ScalarType:
        # 如果当前类型不是 Number 的子类,或者是 bool 类型的子类,则跳过当前循环
        if not issubclass(stype, Number) or issubclass(stype, bool):
            continue
        # 使用当前标量类型 stype 创建一个值为 5 的实例 s
        s = stype(5)
        # 断言通过 op.truediv 计算 p2 除以 s 的结果与 p1 几乎相等
        assert_poly_almost_equal(op.truediv(p2, s), p1)
        # 断言调用 op.truediv 计算 s 除以 p2 会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, s, p2)
    
    # 遍历特定的标量类型 int 和 float
    for stype in (int, float):
        # 使用当前类型 stype 创建一个值为 5 的实例 s
        s = stype(5)
        # 断言通过 op.truediv 计算 p2 除以 s 的结果与 p1 几乎相等
        assert_poly_almost_equal(op.truediv(p2, s), p1)
        # 断言调用 op.truediv 计算 s 除以 p2 会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, s, p2)
    
    # 遍历特定的标量类型 complex(复数)
    for stype in [complex]:
        # 使用当前类型 stype 创建一个实部为 5、虚部为 0 的复数实例 s
        s = stype(5, 0)
        # 断言通过 op.truediv 计算 p2 除以 s 的结果与 p1 几乎相等
        assert_poly_almost_equal(op.truediv(p2, s), p1)
        # 断言调用 op.truediv 计算 s 除以 p2 会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, s, p2)
    
    # 遍历非标量类型 tuple、list、dict、bool、numpy array
    for s in [tuple(), list(), dict(), bool(), np.array([1])]:
        # 断言调用 op.truediv 计算 p2 除以当前类型 s 会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, p2, s)
        # 断言调用 op.truediv 计算当前类型 s 除以 p2 会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, s, p2)
    
    # 遍历类列表 classes 中的每一个类类型 ptype
    for ptype in classes:
        # 断言调用 op.truediv 计算 p2 除以 ptype 类型的实例会引发 TypeError 异常
        assert_raises(TypeError, op.truediv, p2, ptype(1))
# 测试多项式类的模运算功能
def test_mod(Poly):
    # 检查交换性,不验证数值正确性
    c1 = list(random((4,)) + .5)   # 创建包含4个随机数的列表c1
    c2 = list(random((3,)) + .5)   # 创建包含3个随机数的列表c2
    c3 = list(random((2,)) + .5)   # 创建包含2个随机数的列表c3
    p1 = Poly(c1)                  # 使用列表c1创建多项式对象p1
    p2 = Poly(c2)                  # 使用列表c2创建多项式对象p2
    p3 = Poly(c3)                  # 使用列表c3创建多项式对象p3
    p4 = p1 * p2 + p3              # 计算多项式运算 p1 * p2 + p3,得到新的多项式对象p4
    c4 = list(p4.coef)             # 获取p4的系数并存储在列表c4中
    # 断言多项式模运算结果与p3几乎相等
    assert_poly_almost_equal(p4 % p2, p3)
    assert_poly_almost_equal(p4 % c2, p3)
    assert_poly_almost_equal(c4 % p2, p3)
    assert_poly_almost_equal(p4 % tuple(c2), p3)
    assert_poly_almost_equal(tuple(c4) % p2, p3)
    assert_poly_almost_equal(p4 % np.array(c2), p3)
    assert_poly_almost_equal(np.array(c4) % p2, p3)
    assert_poly_almost_equal(2 % p2, Poly([2]))
    assert_poly_almost_equal(p2 % 2, Poly([0]))
    # 检查是否引发TypeError异常,如果多项式的域或窗口不匹配
    assert_raises(TypeError, op.mod, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(TypeError, op.mod, p1, Poly([0], window=Poly.window + 1))
    # 如果Poly是Polynomial类,则继续检查是否引发TypeError异常
    if Poly is Polynomial:
        assert_raises(TypeError, op.mod, p1, Chebyshev([0]))
    else:
        assert_raises(TypeError, op.mod, p1, Polynomial([0]))


# 测试多项式类的整除取余功能
def test_divmod(Poly):
    # 检查交换性,不验证数值正确性
    c1 = list(random((4,)) + .5)   # 创建包含4个随机数的列表c1
    c2 = list(random((3,)) + .5)   # 创建包含3个随机数的列表c2
    c3 = list(random((2,)) + .5)   # 创建包含2个随机数的列表c3
    p1 = Poly(c1)                  # 使用列表c1创建多项式对象p1
    p2 = Poly(c2)                  # 使用列表c2创建多项式对象p2
    p3 = Poly(c3)                  # 使用列表c3创建多项式对象p3
    p4 = p1 * p2 + p3              # 计算多项式运算 p1 * p2 + p3,得到新的多项式对象p4
    c4 = list(p4.coef)             # 获取p4的系数并存储在列表c4中
    # 使用divmod函数计算p4除以p2的商和余数
    quo, rem = divmod(p4, p2)
    assert_poly_almost_equal(quo, p1)  # 断言商几乎等于p1
    assert_poly_almost_equal(rem, p3)  # 断言余数几乎等于p3
    quo, rem = divmod(p4, c2)
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(c4, p2)
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(p4, tuple(c2))
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(tuple(c4), p2)
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(p4, np.array(c2))
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(np.array(c4), p2)
    assert_poly_almost_equal(quo, p1)
    assert_poly_almost_equal(rem, p3)
    quo, rem = divmod(p2, 2)
    assert_poly_almost_equal(quo, 0.5*p2)
    assert_poly_almost_equal(rem, Poly([0]))
    quo, rem = divmod(2, p2)
    assert_poly_almost_equal(quo, Poly([0]))
    assert_poly_almost_equal(rem, Poly([2]))
    # 检查是否引发TypeError异常,如果多项式的域或窗口不匹配
    assert_raises(TypeError, divmod, p1, Poly([0], domain=Poly.domain + 1))
    assert_raises(TypeError, divmod, p1, Poly([0], window=Poly.window + 1))
    # 如果Poly是Polynomial类,则继续检查是否引发TypeError异常
    if Poly is Polynomial:
        assert_raises(TypeError, divmod, p1, Chebyshev([0]))
    else:
        assert_raises(TypeError, divmod, p1, Polynomial([0]))


# 测试多项式类的根功能
def test_roots(Poly):
    d = Poly.domain * 1.25 + .25   # 计算新的域范围d
    w = Poly.window                # 获取窗口w
    tgt = np.linspace(d[0], d[1], 5)   # 创建一个包含5个均匀分布数值的数组tgt
    # 使用给定的根、域和窗口创建多项式,然后计算其根并排序
    res = np.sort(Poly.fromroots(tgt, domain=d, window=w).roots())
    assert_almost_equal(res, tgt)   # 断言计算出的根几乎等于tgt
    # 使用默认的域和窗口创建多项式,并计算其根并排序
    res = np.sort(Poly.fromroots(tgt).roots())
    assert_almost_equal(res, tgt)   # 断言计算出的根几乎等于tgt


# 测试多项式类的次数功能
def test_degree(Poly):
    p = Poly.basis(5)   # 创建一个次数为5的多项式对象p
    # 使用断言检查对象 p 的度数是否等于 5
    assert_equal(p.degree(), 5)
def test_copy(Poly):
    # 使用 Poly 类的 basis 方法创建一个多项式 p1
    p1 = Poly.basis(5)
    # 使用 p1 的 copy 方法复制出一个新的多项式 p2
    p2 = p1.copy()
    # 断言 p1 和 p2 的值相等
    assert_(p1 == p2)
    # 断言 p1 和 p2 不是同一个对象
    assert_(p1 is not p2)
    # 断言 p1 和 p2 的 coef 属性不是同一个对象
    assert_(p1.coef is not p2.coef)
    # 断言 p1 和 p2 的 domain 属性不是同一个对象
    assert_(p1.domain is not p2.domain)
    # 断言 p1 和 p2 的 window 属性不是同一个对象
    assert_(p1.window is not p2.window)


def test_integ(Poly):
    P = Polynomial
    # 检查默认情况
    p0 = Poly.cast(P([1*2, 2*3, 3*4]))
    # 对 p0 进行积分,并将结果转换为多项式 p1
    p1 = P.cast(p0.integ())
    # 对 p0 进行带参数的积分,并将结果转换为多项式 p2
    p2 = P.cast(p0.integ(2))
    # 断言 p1 和 P([0, 2, 3, 4]) 几乎相等
    assert_poly_almost_equal(p1, P([0, 2, 3, 4]))
    # 断言 p2 和 P([0, 0, 1, 1, 1]) 几乎相等
    assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1]))
    # 检查带 k 参数的积分
    p0 = Poly.cast(P([1*2, 2*3, 3*4]))
    p1 = P.cast(p0.integ(k=1))
    p2 = P.cast(p0.integ(2, k=[1, 1]))
    assert_poly_almost_equal(p1, P([1, 2, 3, 4]))
    assert_poly_almost_equal(p2, P([1, 1, 1, 1, 1]))
    # 检查带 lbnd 参数的积分
    p0 = Poly.cast(P([1*2, 2*3, 3*4]))
    p1 = P.cast(p0.integ(lbnd=1))
    p2 = P.cast(p0.integ(2, lbnd=1))
    assert_poly_almost_equal(p1, P([-9, 2, 3, 4]))
    assert_poly_almost_equal(p2, P([6, -9, 1, 1, 1]))
    # 检查缩放
    d = 2*Poly.domain
    p0 = Poly.cast(P([1*2, 2*3, 3*4]), domain=d)
    p1 = P.cast(p0.integ())
    p2 = P.cast(p0.integ(2))
    assert_poly_almost_equal(p1, P([0, 2, 3, 4]))
    assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1]))


def test_deriv(Poly):
    # 检查导数是否是积分的逆操作,假设积分在其他地方已经检查过。
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    p1 = Poly([1, 2, 3], domain=d, window=w)
    p2 = p1.integ(2, k=[1, 2])
    p3 = p1.integ(1, k=[1])
    assert_almost_equal(p2.deriv(1).coef, p3.coef)
    assert_almost_equal(p2.deriv(2).coef, p1.coef)
    # 默认的 domain 和 window
    p1 = Poly([1, 2, 3])
    p2 = p1.integ(2, k=[1, 2])
    p3 = p1.integ(1, k=[1])
    assert_almost_equal(p2.deriv(1).coef, p3.coef)
    assert_almost_equal(p2.deriv(2).coef, p1.coef)


def test_linspace(Poly):
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    p = Poly([1, 2, 3], domain=d, window=w)
    # 检查默认 domain
    xtgt = np.linspace(d[0], d[1], 20)
    ytgt = p(xtgt)
    xres, yres = p.linspace(20)
    assert_almost_equal(xres, xtgt)
    assert_almost_equal(yres, ytgt)
    # 检查指定 domain
    xtgt = np.linspace(0, 2, 20)
    ytgt = p(xtgt)
    xres, yres = p.linspace(20, domain=[0, 2])
    assert_almost_equal(xres, xtgt)
    assert_almost_equal(yres, ytgt)


def test_pow(Poly):
    d = Poly.domain + random((2,))*.25
    w = Poly.window + random((2,))*.25
    tgt = Poly([1], domain=d, window=w)
    tst = Poly([1, 2, 3], domain=d, window=w)
    for i in range(5):
        assert_poly_almost_equal(tst**i, tgt)
        tgt = tgt * tst
    # 默认 domain 和 window
    tgt = Poly([1])
    tst = Poly([1, 2, 3])
    for i in range(5):
        assert_poly_almost_equal(tst**i, tgt)
        tgt = tgt * tst
    # 检查无效指数的错误
    assert_raises(ValueError, op.pow, tgt, 1.5)
    assert_raises(ValueError, op.pow, tgt, -1)
# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_call(Poly):
    # 将 Polynomial 类赋值给 P
    P = Polynomial
    # 获取 Poly 的域范围
    d = Poly.domain
    # 生成一个包含 11 个元素的 numpy 数组,元素均匀分布在 d[0] 到 d[1] 之间
    x = np.linspace(d[0], d[1], 11)

    # 检查默认情况
    p = Poly.cast(P([1, 2, 3]))  # 将 [1, 2, 3] 转换成 Poly 类型的多项式 p
    tgt = 1 + x*(2 + 3*x)  # 计算目标值,即 1 + x*(2 + 3*x)
    res = p(x)  # 计算多项式 p 在 x 上的取值
    assert_almost_equal(res, tgt)  # 断言 res 与 tgt 几乎相等


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_call_with_list(Poly):
    # 使用列表 [1, 2, 3] 创建 Poly 类型的多项式 p
    p = Poly([1, 2, 3])
    # 给定 x 值列表 [-1, 0, 2]
    x = [-1, 0, 2]
    # 计算多项式 p 在 x 上的取值
    res = p(x)
    # 断言 res 等于 p 在 numpy 数组 x 上的取值
    assert_equal(res, p(np.array(x)))


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_cutdeg(Poly):
    # 使用系数 [1, 2, 3] 创建 Poly 类型的多项式 p
    p = Poly([1, 2, 3])
    # 断言 cutdeg 方法对小数值抛出 ValueError 异常
    assert_raises(ValueError, p.cutdeg, .5)
    # 断言 cutdeg 方法对负数抛出 ValueError 异常
    assert_raises(ValueError, p.cutdeg, -1)
    # 断言 cutdeg 方法在阶数为 3 时返回的多项式长度为 3
    assert_equal(len(p.cutdeg(3)), 3)
    # 断言 cutdeg 方法在阶数为 2 时返回的多项式长度为 3
    assert_equal(len(p.cutdeg(2)), 3)
    # 断言 cutdeg 方法在阶数为 1 时返回的多项式长度为 2
    assert_equal(len(p.cutdeg(1)), 2)
    # 断言 cutdeg 方法在阶数为 0 时返回的多项式长度为 1
    assert_equal(len(p.cutdeg(0)), 1)


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_truncate(Poly):
    # 使用系数 [1, 2, 3] 创建 Poly 类型的多项式 p
    p = Poly([1, 2, 3])
    # 断言 truncate 方法对小数值抛出 ValueError 异常
    assert_raises(ValueError, p.truncate, .5)
    # 断言 truncate 方法对零抛出 ValueError 异常
    assert_raises(ValueError, p.truncate, 0)
    # 断言 truncate 方法在阶数为 4 时返回的多项式长度为 3
    assert_equal(len(p.truncate(4)), 3)
    # 断言 truncate 方法在阶数为 3 时返回的多项式长度为 3
    assert_equal(len(p.truncate(3)), 3)
    # 断言 truncate 方法在阶数为 2 时返回的多项式长度为 2
    assert_equal(len(p.truncate(2)), 2)
    # 断言 truncate 方法在阶数为 1 时返回的多项式长度为 1
    assert_equal(len(p.truncate(1)), 1)


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_trim(Poly):
    # 创建系数列表 [1, 1e-6, 1e-12, 0] 的 Poly 类型多项式 p
    c = [1, 1e-6, 1e-12, 0]
    p = Poly(c)
    # 断言 trim 方法后多项式的系数与预期相符,保留有效数字至第三项
    assert_equal(p.trim().coef, c[:3])
    # 断言 trim 方法保留小于给定阈值 1e-10 的系数,应返回前两项系数
    assert_equal(p.trim(1e-10).coef, c[:2])
    # 断言 trim 方法保留小于给定阈值 1e-5 的系数,应返回第一项系数
    assert_equal(p.trim(1e-5).coef, c[:1])


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_mapparms(Poly):
    # 检查默认情况下的参数映射,应返回标识映射 [0, 1]
    d = Poly.domain
    w = Poly.window
    p = Poly([1], domain=d, window=w)
    assert_almost_equal([0, 1], p.mapparms())
    #
    # 将窗口设置为 2*d + 1
    w = 2*d + 1
    p = Poly([1], domain=d, window=w)
    # 断言参数映射为 [1, 2]
    assert_almost_equal([1, 2], p.mapparms())


# 定义一个测试函数,接受一个多项式类 Poly 作为参数
def test_ufunc_override(Poly):
    # 使用系数 [1, 2, 3] 创建 Poly 类型的多项式 p
    p = Poly([1, 2, 3])
    # 创建一个全为 1 的 numpy 数组 x
    x = np.ones(3)
    # 断言使用 np.add 函数将多项式 p 与 x 相加抛出 TypeError 异常
    assert_raises(TypeError, np.add, p, x)
    # 断言使用 np.add 函数将 x 与多项式 p 相加抛出 TypeError 异常
    assert_raises(TypeError, np.add, x, p)


#
# 仅适用于某些类的测试类方法
#


class TestInterpolate:

    # 定义一个测试函数 f,接受 x 参数并返回 x*(x-1)*(x-2) 的结果
    def f(self, x):
        return x * (x - 1) * (x - 2)

    # 测试函数,断言 Chebyshev.interpolate 方法对于给定的参数抛出 ValueError 异常
    def test_raises(self):
        assert_raises(ValueError, Chebyshev.interpolate, self.f, -1)
        assert_raises(TypeError, Chebyshev.interpolate, self.f, 10.)

    # 测试函数,断言 Chebyshev.interpolate 方法返回的多项式阶数与预期相符
    def test_dimensions(self):
        for deg in range(1, 5):
            assert_(Chebyshev.interpolate(self.f, deg).degree() == deg)

    # 测试函数,断言 Chebyshev.interpolate 方法返回的多项式与原函数 powx 在给定区间上的近似程度
    def test_approximation(self):

        # 定义函数 powx,接受 x 和 p 参数,返回 x 的 p 次幂
        def powx(x, p):
            return x**p

        # 创建一个包含 10 个元素的 numpy 数组 x,均匀分布在 [0, 2] 区间上
        x = np.linspace(0, 2, 10)
        # 遍历不同的多项式阶数 deg
        for deg in range(0, 10):
            # 遍历不同的次幂 t
            for t in range(0, deg + 1):
                # 使用 Chebyshev.interpolate 方法创建多项式 p,近似函数 powx 的结果
                p = Chebyshev.interpolate(powx, deg, domain=[0, 2], args=(t,))
                # 断言多项式 p 在数组 x 上的取值与 powx(x, t) 的近似程度在 11 位小数上相等