NumPy 源码解析(三十九)
.\numpy\numpy\random\tests\test_randomstate_regression.py
# 导入系统模块 sys
import sys
# 导入 pytest 测试框架
import pytest
# 从 numpy.testing 模块中导入断言函数和异常函数
from numpy.testing import (
assert_, assert_array_equal, assert_raises,
)
# 导入 numpy 模块,并使用 np 别名
import numpy as np
# 从 numpy 模块中导入 random 子模块
from numpy import random
# 定义测试类 TestRegression
class TestRegression:
# 定义测试方法 test_VonMises_range
def test_VonMises_range(self):
# 确保生成的随机变量在 [-pi, pi] 范围内
# 这是针对票号 #986 的回归测试
for mu in np.linspace(-7., 7., 5):
r = random.vonmises(mu, 1, 50)
assert_(np.all(r > -np.pi) and np.all(r <= np.pi))
# 定义测试方法 test_hypergeometric_range
def test_hypergeometric_range(self):
# 针对票号 #921 进行测试
assert_(np.all(random.hypergeometric(3, 18, 11, size=10) < 4))
assert_(np.all(random.hypergeometric(18, 3, 11, size=10) > 0))
# 针对票号 #5623 进行测试
args = [
(2**20 - 2, 2**20 - 2, 2**20 - 2), # 检查 32 位系统
]
is_64bits = sys.maxsize > 2**32
if is_64bits and sys.platform != 'win32':
# 检查 64 位系统
args.append((2**40 - 2, 2**40 - 2, 2**40 - 2))
for arg in args:
assert_(random.hypergeometric(*arg) > 0)
# 定义测试方法 test_logseries_convergence
def test_logseries_convergence(self):
# 针对票号 #923 进行测试
N = 1000
random.seed(0)
rvsn = random.logseries(0.8, size=N)
# 这两个频率计数应该接近理论值,在这么大的样本中
# 对于大 N,理论值约为 0.49706795
freq = np.sum(rvsn == 1) / N
msg = f'Frequency was {freq:f}, should be > 0.45'
assert_(freq > 0.45, msg)
# 对于大 N,理论值约为 0.19882718
freq = np.sum(rvsn == 2) / N
msg = f'Frequency was {freq:f}, should be < 0.23'
assert_(freq < 0.23, msg)
# 定义测试方法 test_shuffle_mixed_dimension
def test_shuffle_mixed_dimension(self):
# 针对 trac 票号 #2074 进行测试
for t in [[1, 2, 3, None],
[(1, 1), (2, 2), (3, 3), None],
[1, (2, 2), (3, 3), None],
[(1, 1), 2, 3, None]]:
random.seed(12345)
shuffled = list(t)
random.shuffle(shuffled)
expected = np.array([t[0], t[3], t[1], t[2]], dtype=object)
assert_array_equal(np.array(shuffled, dtype=object), expected)
# 定义测试方法 test_call_within_randomstate
def test_call_within_randomstate(self):
# 检查自定义的 RandomState 不会调用全局状态
m = random.RandomState()
res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3])
for i in range(3):
random.seed(i)
m.seed(4321)
# 如果 m.state 没有被尊重,结果会发生变化
assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res)
def test_multivariate_normal_size_types(self):
# 测试多变量正态分布函数的 'size' 参数问题
# 检查 multivariate_normal 函数的 size 参数能否接受 numpy 的整数类型
random.multivariate_normal([0], [[0]], size=1)
random.multivariate_normal([0], [[0]], size=np.int_(1))
random.multivariate_normal([0], [[0]], size=np.int64(1))
def test_beta_small_parameters(self):
# 测试 beta 分布在参数 a 和 b 较小时不会因舍入误差导致 NaN
# 问题来源于舍入误差导致 0 / 0,见 GitHub 问题 gh-5851
random.seed(1234567890)
x = random.beta(0.0001, 0.0001, size=100)
assert_(not np.any(np.isnan(x)), 'Nans in random.beta')
def test_choice_sum_of_probs_tolerance(self):
# 检查概率和应该为 1.0,允许一定的容差
# 对于低精度数据类型,容差设置过紧,见 numpy GitHub 问题 6123
random.seed(1234)
a = [1, 2, 3]
counts = [4, 4, 2]
for dt in np.float16, np.float32, np.float64:
probs = np.array(counts, dtype=dt) / sum(counts)
c = random.choice(a, p=probs)
assert_(c in a)
assert_raises(ValueError, random.choice, a, p=probs*0.9)
def test_shuffle_of_array_of_different_length_strings(self):
# 测试对不同长度字符串数组进行洗牌操作
# 确保在垃圾回收时不会导致段错误
# 测试 GitHub 问题 gh-7710
random.seed(1234)
a = np.array(['a', 'a' * 1000])
for _ in range(100):
random.shuffle(a)
# 强制进行垃圾回收,不应该导致段错误
import gc
gc.collect()
def test_shuffle_of_array_of_objects(self):
# 测试对对象数组进行洗牌操作
# 确保在垃圾回收时不会导致段错误
# 见 GitHub 问题 gh-7719
random.seed(1234)
a = np.array([np.arange(1), np.arange(4)], dtype=object)
for _ in range(1000):
random.shuffle(a)
# 强制进行垃圾回收,不应该导致段错误
import gc
gc.collect()
def test_permutation_subclass(self):
class N(np.ndarray):
pass
random.seed(1)
orig = np.arange(3).view(N)
perm = random.permutation(orig)
assert_array_equal(perm, np.array([0, 2, 1]))
assert_array_equal(orig, np.arange(3).view(N))
class M:
a = np.arange(5)
def __array__(self, dtype=None, copy=None):
return self.a
random.seed(1)
m = M()
perm = random.permutation(m)
assert_array_equal(perm, np.array([2, 1, 4, 0, 3]))
assert_array_equal(m.__array__(), np.arange(5))
def test_warns_byteorder(self):
# GH 13159
# 根据系统字节顺序选择相应的数据类型格式
other_byteord_dt = '<i4' if sys.byteorder == 'big' else '>i4'
# 使用 pytest 检查是否发出了弃用警告
with pytest.deprecated_call(match='non-native byteorder is not'):
random.randint(0, 200, size=10, dtype=other_byteord_dt)
def test_named_argument_initialization(self):
# GH 13669
# 使用特定的种子创建两个随机状态对象
rs1 = np.random.RandomState(123456789)
rs2 = np.random.RandomState(seed=123456789)
# 检查两个随机状态对象生成的随机整数是否相等
assert rs1.randint(0, 100) == rs2.randint(0, 100)
def test_choice_retun_dtype(self):
# GH 9867, now long since the NumPy default changed.
# 使用给定概率分布选择随机数,验证返回值的数据类型是否为 np.long
c = np.random.choice(10, p=[.1]*10, size=2)
assert c.dtype == np.dtype(np.long)
c = np.random.choice(10, p=[.1]*10, replace=False, size=2)
assert c.dtype == np.dtype(np.long)
c = np.random.choice(10, size=2)
assert c.dtype == np.dtype(np.long)
c = np.random.choice(10, replace=False, size=2)
assert c.dtype == np.dtype(np.long)
@pytest.mark.skipif(np.iinfo('l').max < 2**32,
reason='Cannot test with 32-bit C long')
def test_randint_117(self):
# GH 14189
# 使用种子初始化随机数生成器,生成指定范围内的随机整数数组,验证结果是否符合预期
random.seed(0)
expected = np.array([2357136044, 2546248239, 3071714933, 3626093760,
2588848963, 3684848379, 2340255427, 3638918503,
1819583497, 2678185683], dtype='int64')
actual = random.randint(2**32, size=10)
assert_array_equal(actual, expected)
def test_p_zero_stream(self):
# Regression test for gh-14522. Ensure that future versions
# generate the same variates as version 1.16.
# 使用种子初始化随机数生成器,验证二项分布生成的结果是否与预期一致
np.random.seed(12345)
assert_array_equal(random.binomial(1, [0, 0.25, 0.5, 0.75, 1]),
[0, 0, 0, 1, 1])
def test_n_zero_stream(self):
# Regression test for gh-14522. Ensure that future versions
# generate the same variates as version 1.16.
# 使用种子初始化随机数生成器,验证二项分布生成的结果是否与预期一致
np.random.seed(8675309)
expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 4, 2, 3, 3, 1, 5, 3, 1, 3]])
assert_array_equal(random.binomial([[0], [10]], 0.25, size=(2, 10)),
expected)
# 定义一个测试函数,用于测试 random.multinomial 函数处理空概率值的情况
def test_multinomial_empty():
# gh-20483
# 确保空的概率值被正确处理
assert random.multinomial(10, []).shape == (0,)
# 确保在指定大小的情况下,空的概率值被正确处理
assert random.multinomial(3, [], size=(7, 5, 3)).shape == (7, 5, 3, 0)
# 定义一个测试函数,用于测试 random.multinomial 函数对一维概率值的处理
def test_multinomial_1d_pval():
# gh-20483
# 使用 pytest 检查是否会引发 TypeError 异常,且异常信息应匹配 "pvals must be a 1-d"
with pytest.raises(TypeError, match="pvals must be a 1-d"):
random.multinomial(10, 0.3)
.\numpy\numpy\random\tests\test_regression.py
# 导入必要的模块和函数
import sys
from numpy.testing import (
assert_, assert_array_equal, assert_raises,
)
from numpy import random
import numpy as np
# 定义测试类 TestRegression,用于测试回归功能
class TestRegression:
# 定义测试方法 test_VonMises_range,测试 Von Mises 分布的范围
def test_VonMises_range(self):
# 确保生成的随机变量落在 [-pi, pi] 范围内
# 这是对问题 #986 的回归测试
for mu in np.linspace(-7., 7., 5):
r = random.mtrand.vonmises(mu, 1, 50)
assert_(np.all(r > -np.pi) and np.all(r <= np.pi))
# 定义测试方法 test_hypergeometric_range,测试超几何分布的范围
def test_hypergeometric_range(self):
# 这是对问题 #921 的测试
assert_(np.all(np.random.hypergeometric(3, 18, 11, size=10) < 4))
assert_(np.all(np.random.hypergeometric(18, 3, 11, size=10) > 0))
# 这是对问题 #5623 的测试
args = [
(2**20 - 2, 2**20 - 2, 2**20 - 2), # 检查 32 位系统
]
is_64bits = sys.maxsize > 2**32
if is_64bits and sys.platform != 'win32':
# 检查 64 位系统
args.append((2**40 - 2, 2**40 - 2, 2**40 - 2))
for arg in args:
assert_(np.random.hypergeometric(*arg) > 0)
# 定义测试方法 test_logseries_convergence,测试对数级数分布的收敛性
def test_logseries_convergence(self):
# 这是对问题 #923 的测试
N = 1000
np.random.seed(0)
rvsn = np.random.logseries(0.8, size=N)
# 下面两个频率计数应该接近理论值,对于这么大的样本
# 理论上对于大 N 结果是 0.49706795
freq = np.sum(rvsn == 1) / N
msg = f'Frequency was {freq:f}, should be > 0.45'
assert_(freq > 0.45, msg)
# 理论上对于大 N 结果是 0.19882718
freq = np.sum(rvsn == 2) / N
msg = f'Frequency was {freq:f}, should be < 0.23'
assert_(freq < 0.23, msg)
# 定义测试方法 test_shuffle_mixed_dimension,测试混合维度的洗牌功能
def test_shuffle_mixed_dimension(self):
# 这是对 trac 问题 #2074 的测试
for t in [[1, 2, 3, None],
[(1, 1), (2, 2), (3, 3), None],
[1, (2, 2), (3, 3), None],
[(1, 1), 2, 3, None]]:
np.random.seed(12345)
shuffled = list(t)
random.shuffle(shuffled)
expected = np.array([t[0], t[3], t[1], t[2]], dtype=object)
assert_array_equal(np.array(shuffled, dtype=object), expected)
# 定义测试方法 test_call_within_randomstate,测试在自定义 RandomState 中调用
def test_call_within_randomstate(self):
# 检查自定义的 RandomState 是否影响全局状态
m = np.random.RandomState()
res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3])
for i in range(3):
np.random.seed(i)
m.seed(4321)
# 如果 m.state 没有被遵循,结果将会改变
assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res)
def test_multivariate_normal_size_types(self):
# 测试多元正态分布中 'size' 参数的问题。
# 检查 multivariate_normal 函数的 size 参数是否可以是 numpy 的整数类型。
np.random.multivariate_normal([0], [[0]], size=1)
np.random.multivariate_normal([0], [[0]], size=np.int_(1))
np.random.multivariate_normal([0], [[0]], size=np.int64(1))
def test_beta_small_parameters(self):
# 测试 beta 分布在小的 a 和 b 参数下不会因为舍入误差导致 NaN,详情见 gh-5851
np.random.seed(1234567890)
x = np.random.beta(0.0001, 0.0001, size=100)
assert_(not np.any(np.isnan(x)), 'Nans in np.random.beta')
def test_choice_sum_of_probs_tolerance(self):
# 确保概率的总和为 1.0,允许一定的误差范围。
# 对于低精度的数据类型,之前的容差过于严格,参见 numpy GitHub 问题 6123。
np.random.seed(1234)
a = [1, 2, 3]
counts = [4, 4, 2]
for dt in np.float16, np.float32, np.float64:
probs = np.array(counts, dtype=dt) / sum(counts)
c = np.random.choice(a, p=probs)
assert_(c in a)
assert_raises(ValueError, np.random.choice, a, p=probs*0.9)
def test_shuffle_of_array_of_different_length_strings(self):
# 测试对一个包含不同长度字符串的数组进行洗牌不会在垃圾回收时导致段错误。
# 测试 gh-7710
np.random.seed(1234)
a = np.array(['a', 'a' * 1000])
for _ in range(100):
np.random.shuffle(a)
# 强制进行垃圾回收,不应该导致段错误。
import gc
gc.collect()
def test_shuffle_of_array_of_objects(self):
# 测试对一个包含对象的数组进行洗牌不会在垃圾回收时导致段错误。
# 参见 gh-7719
np.random.seed(1234)
a = np.array([np.arange(1), np.arange(4)], dtype=object)
for _ in range(1000):
np.random.shuffle(a)
# 强制进行垃圾回收,不应该导致段错误。
import gc
gc.collect()
def test_permutation_subclass(self):
class N(np.ndarray):
pass
np.random.seed(1)
orig = np.arange(3).view(N)
perm = np.random.permutation(orig)
assert_array_equal(perm, np.array([0, 2, 1]))
assert_array_equal(orig, np.arange(3).view(N))
class M:
a = np.arange(5)
def __array__(self, dtype=None, copy=None):
return self.a
np.random.seed(1)
m = M()
perm = np.random.permutation(m)
assert_array_equal(perm, np.array([2, 1, 4, 0, 3]))
assert_array_equal(m.__array__(), np.arange(5))
.\numpy\numpy\random\tests\test_seed_sequence.py
# 导入必要的库
import numpy as np
from numpy.testing import assert_array_equal, assert_array_compare
from numpy.random import SeedSequence
# 测试 SeedSequence 是否生成和 C++ 参考代码相同的数据
def test_reference_data():
""" Check that SeedSequence generates data the same as the C++ reference.
https://gist.github.com/imneme/540829265469e673d045
"""
# 输入数据列表
inputs = [
[3735928559, 195939070, 229505742, 305419896],
...
]
# 期望的输出数据列表
outputs = [
[3914649087, 576849849, 3593928901, 2229911004],
...
]
# 期望的输出数据列表(64位)
outputs64 = [
[2477551240072187391, 9577394838764454085],
...
]
# 遍历输入、期望输出和期望输出(64位),对每个种子进行测试
for seed, expected, expected64 in zip(inputs, outputs, outputs64):
# 将期望输出转换为 numpy 数组,数据类型为 uint32
expected = np.array(expected, dtype=np.uint32)
# 使用种子创建 SeedSequence 对象
ss = SeedSequence(seed)
# 生成具有期望长度的状态,并进行断言
state = ss.generate_state(len(expected))
assert_array_equal(state, expected)
# 生成具有期望长度的状态(64位),数据类型为 uint64,并进行断言
state64 = ss.generate_state(len(expected64), dtype=np.uint64)
assert_array_equal(state64, expected64)
# 测试零填充是否有问题
def test_zero_padding():
""" Ensure that the implicit zero-padding does not cause problems.
"""
# 确保大整数以小尾格式插入,避免结尾为0
ss0 = SeedSequence(42)
ss1 = SeedSequence(42 << 32)
assert_array_compare(
np.not_equal,
ss0.generate_state(4),
ss1.generate_state(4))
# 确保与原始0.17版本兼容,对于小整数和没有派生密钥
# 创建一个预期的 NumPy 数组,包含无符号 32 位整数,用于后续的断言比较
expected42 = np.array([3444837047, 2669555309, 2046530742, 3581440988],
dtype=np.uint32)
# 使用种子数 42 初始化 SeedSequence,并生成长度为 4 的状态数组,然后与预期的数组进行断言比较
assert_array_equal(SeedSequence(42).generate_state(4), expected42)
# 回归测试 gh-16539,确保隐式的 0 值不会与生成的种子键冲突
# 使用种子数 42 和生成的 spawn key (0,) 初始化 SeedSequence,并生成长度为 4 的状态数组,然后与预期的数组进行比较
assert_array_compare(
np.not_equal,
SeedSequence(42, spawn_key=(0,)).generate_state(4),
expected42)
.\numpy\numpy\random\tests\test_smoke.py
# 导入pickle模块,用于对象序列化和反序列化
import pickle
# 导入functools模块的partial函数,用于创建偏函数
from functools import partial
# 导入numpy库并重命名为np,用于科学计算
import numpy as np
# 导入pytest测试框架相关的断言函数和装饰器
import pytest
# 导入numpy.testing模块中的断言函数,用于数组断言
from numpy.testing import assert_equal, assert_, assert_array_equal
# 导入numpy.random模块中的随机数生成器相关类
from numpy.random import (Generator, MT19937, PCG64, PCG64DXSM, Philox, SFC64)
# 定义pytest的fixture,用于参数化测试,返回各种数据类型
@pytest.fixture(scope='module',
params=(np.bool, np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64))
def dtype(request):
return request.param
# 定义函数params_0,测试随机数生成器的输出是否为标量及其形状
def params_0(f):
val = f()
assert_(np.isscalar(val))
val = f(10)
assert_(val.shape == (10,))
val = f((10, 10))
assert_(val.shape == (10, 10))
val = f((10, 10, 10))
assert_(val.shape == (10, 10, 10))
val = f(size=(5, 5))
assert_(val.shape == (5, 5))
# 定义函数params_1,测试随机数生成器在不同输入条件下的输出
def params_1(f, bounded=False):
a = 5.0
b = np.arange(2.0, 12.0)
c = np.arange(2.0, 102.0).reshape((10, 10))
d = np.arange(2.0, 1002.0).reshape((10, 10, 10))
e = np.array([2.0, 3.0])
g = np.arange(2.0, 12.0).reshape((1, 10, 1))
if bounded:
a = 0.5
b = b / (1.5 * b.max())
c = c / (1.5 * c.max())
d = d / (1.5 * d.max())
e = e / (1.5 * e.max())
g = g / (1.5 * g.max())
# 标量
f(a)
# 标量 - 指定大小
f(a, size=(10, 10))
# 1维数组
f(b)
# 2维数组
f(c)
# 3维数组
f(d)
# 1维数组 - 指定大小
f(b, size=10)
# 2维数组 - 指定大小 - 广播
f(e, size=(10, 2))
# 3维数组 - 指定大小
f(g, size=(10, 10, 10))
# 定义函数comp_state,比较两个状态是否相同
def comp_state(state1, state2):
identical = True
if isinstance(state1, dict):
for key in state1:
identical &= comp_state(state1[key], state2[key])
elif type(state1) != type(state2):
identical &= type(state1) == type(state2)
else:
if (isinstance(state1, (list, tuple, np.ndarray)) and isinstance(
state2, (list, tuple, np.ndarray))):
for s1, s2 in zip(state1, state2):
identical &= comp_state(s1, s2)
else:
identical &= state1 == state2
return identical
# 定义函数warmup,对随机数生成器进行预热
def warmup(rg, n=None):
if n is None:
n = 11 + np.random.randint(0, 20)
rg.standard_normal(n)
rg.standard_normal(n)
rg.standard_normal(n, dtype=np.float32)
rg.standard_normal(n, dtype=np.float32)
rg.integers(0, 2 ** 24, n, dtype=np.uint64)
rg.integers(0, 2 ** 48, n, dtype=np.uint64)
rg.standard_gamma(11.0, n)
rg.standard_gamma(11.0, n, dtype=np.float32)
rg.random(n, dtype=np.float64)
rg.random(n, dtype=np.float32)
# 定义RNG类,用于随机数生成器的设置和状态管理
class RNG:
@classmethod
def setup_class(cls):
# 在测试类中被覆盖。用于静音IDE中的噪声
cls.bit_generator = PCG64
cls.advance = None
cls.seed = [12345]
cls.rg = Generator(cls.bit_generator(*cls.seed))
cls.initial_state = cls.rg.bit_generator.state
cls.seed_vector_bits = 64
cls._extra_setup()
@classmethod
# 设置额外的类变量和初始状态,包括一个一维向量、二维向量、矩阵和错误类型
def _extra_setup(cls):
cls.vec_1d = np.arange(2.0, 102.0)
cls.vec_2d = np.arange(2.0, 102.0)[None, :]
cls.mat = np.arange(2.0, 102.0, 0.01).reshape((100, 100))
cls.seed_error = TypeError
# 重置对象的状态为初始状态
def _reset_state(self):
self.rg.bit_generator.state = self.initial_state
# 测试随机数生成器初始化是否正确
def test_init(self):
rg = Generator(self.bit_generator())
state = rg.bit_generator.state
rg.standard_normal(1) # 生成一个标准正态分布的随机数
rg.standard_normal(1) # 再生成一个标准正态分布的随机数
rg.bit_generator.state = state # 恢复到初始状态
new_state = rg.bit_generator.state
assert_(comp_state(state, new_state)) # 断言新状态与初始状态相同
# 测试随机数生成器的状态推进功能
def test_advance(self):
state = self.rg.bit_generator.state
if hasattr(self.rg.bit_generator, 'advance'):
self.rg.bit_generator.advance(self.advance) # 推进随机数生成器状态
assert_(not comp_state(state, self.rg.bit_generator.state)) # 断言状态不同
else:
bitgen_name = self.rg.bit_generator.__class__.__name__
pytest.skip(f'Advance is not supported by {bitgen_name}') # 如果不支持推进功能,则跳过测试
# 测试随机数生成器的跳跃功能
def test_jump(self):
state = self.rg.bit_generator.state
if hasattr(self.rg.bit_generator, 'jumped'):
bit_gen2 = self.rg.bit_generator.jumped() # 执行跳跃操作
jumped_state = bit_gen2.state
assert_(not comp_state(state, jumped_state)) # 断言状态不同
self.rg.random(2 * 3 * 5 * 7 * 11 * 13 * 17) # 生成一组随机数
self.rg.bit_generator.state = state # 恢复初始状态
bit_gen3 = self.rg.bit_generator.jumped() # 再次执行跳跃操作
rejumped_state = bit_gen3.state
assert_(comp_state(jumped_state, rejumped_state)) # 断言再次跳跃后状态与第一次相同
else:
bitgen_name = self.rg.bit_generator.__class__.__name__
if bitgen_name not in ('SFC64',):
raise AttributeError(f'no "jumped" in {bitgen_name}')
pytest.skip(f'Jump is not supported by {bitgen_name}') # 如果不支持跳跃功能,则跳过测试
# 测试生成均匀分布随机数
def test_uniform(self):
r = self.rg.uniform(-1.0, 0.0, size=10) # 生成均匀分布的随机数
assert_(len(r) == 10) # 断言生成的随机数数量为10
assert_((r > -1).all()) # 断言所有生成的随机数大于-1
assert_((r <= 0).all()) # 断言所有生成的随机数小于等于0
# 测试生成均匀分布随机数组
def test_uniform_array(self):
r = self.rg.uniform(np.array([-1.0] * 10), 0.0, size=10) # 生成均匀分布的随机数数组
assert_(len(r) == 10) # 断言生成的随机数数量为10
assert_((r > -1).all()) # 断言所有生成的随机数大于-1
assert_((r <= 0).all()) # 断言所有生成的随机数小于等于0
r = self.rg.uniform(np.array([-1.0] * 10),
np.array([0.0] * 10), size=10) # 生成均匀分布的随机数数组
assert_(len(r) == 10) # 断言生成的随机数数量为10
assert_((r > -1).all()) # 断言所有生成的随机数大于-1
assert_((r <= 0).all()) # 断言所有生成的随机数小于等于0
r = self.rg.uniform(-1.0, np.array([0.0] * 10), size=10) # 生成均匀分布的随机数数组
assert_(len(r) == 10) # 断言生成的随机数数量为10
assert_((r > -1).all()) # 断言所有生成的随机数大于-1
assert_((r <= 0).all()) # 断言所有生成的随机数小于等于0
# 测试生成随机数
def test_random(self):
assert_(len(self.rg.random(10)) == 10) # 断言生成的随机数数量为10
params_0(self.rg.random) # 调用函数 params_0 进行进一步测试
# 测试生成标准正态分布随机数(使用 Zig 方法)
def test_standard_normal_zig(self):
assert_(len(self.rg.standard_normal(10)) == 10) # 断言生成的随机数数量为10
# 测试生成标准正态分布随机数
def test_standard_normal(self):
assert_(len(self.rg.standard_normal(10)) == 10) # 断言生成的随机数数量为10
params_0(self.rg.standard_normal) # 调用函数 params_0 进行进一步测试
# 测试标准 Gamma 分布生成器函数
def test_standard_gamma(self):
# 断言生成的 Gamma 分布样本长度为 10
assert_(len(self.rg.standard_gamma(10, 10)) == 10)
# 断言生成的 Gamma 分布样本数组长度为 10
assert_(len(self.rg.standard_gamma(np.array([10] * 10), 10)) == 10)
# 使用 params_1 函数验证标准 Gamma 分布生成器函数
params_1(self.rg.standard_gamma)
# 测试标准指数分布生成器函数
def test_standard_exponential(self):
# 断言生成的指数分布样本长度为 10
assert_(len(self.rg.standard_exponential(10)) == 10)
# 使用 params_0 函数验证标准指数分布生成器函数
params_0(self.rg.standard_exponential)
# 测试生成浮点数标准指数分布的生成器函数
def test_standard_exponential_float(self):
# 生成浮点数标准指数分布样本,验证长度为 10
randoms = self.rg.standard_exponential(10, dtype='float32')
assert_(len(randoms) == 10)
# 断言生成的浮点数标准指数分布样本数据类型为 np.float32
assert randoms.dtype == np.float32
# 使用 params_0 函数验证生成浮点数标准指数分布的生成器函数
params_0(partial(self.rg.standard_exponential, dtype='float32'))
# 测试生成浮点数标准指数分布并应用对数变换的生成器函数
def test_standard_exponential_float_log(self):
# 生成浮点数标准指数分布并应用对数变换,验证长度为 10
randoms = self.rg.standard_exponential(10, dtype='float32', method='inv')
assert_(len(randoms) == 10)
# 断言生成的浮点数标准指数分布样本数据类型为 np.float32
assert randoms.dtype == np.float32
# 使用 params_0 函数验证生成浮点数标准指数分布并应用对数变换的生成器函数
params_0(partial(self.rg.standard_exponential, dtype='float32', method='inv'))
# 测试标准柯西分布生成器函数
def test_standard_cauchy(self):
# 断言生成的柯西分布样本长度为 10
assert_(len(self.rg.standard_cauchy(10)) == 10)
# 使用 params_0 函数验证标准柯西分布生成器函数
params_0(self.rg.standard_cauchy)
# 测试标准 t 分布生成器函数
def test_standard_t(self):
# 断言生成的 t 分布样本长度为 10
assert_(len(self.rg.standard_t(10, 10)) == 10)
# 使用 params_1 函数验证标准 t 分布生成器函数
params_1(self.rg.standard_t)
# 测试二项分布生成器函数
def test_binomial(self):
# 断言生成的二项分布样本大于等于 0
assert_(self.rg.binomial(10, .5) >= 0)
# 断言生成的二项分布样本大于等于 0
assert_(self.rg.binomial(1000, .5) >= 0)
# 测试随机数生成器状态重置函数
def test_reset_state(self):
# 保存当前随机数生成器状态
state = self.rg.bit_generator.state
# 生成一个整数
int_1 = self.rg.integers(2**31)
# 恢复之前保存的随机数生成器状态
self.rg.bit_generator.state = state
# 再次生成一个整数
int_2 = self.rg.integers(2**31)
# 断言两次生成的整数相等
assert_(int_1 == int_2)
# 测试随机数生成器初始化熵的函数
def test_entropy_init(self):
# 使用自定义比较函数验证随机数生成器的状态不同
rg = Generator(self.bit_generator())
rg2 = Generator(self.bit_generator())
assert_(not comp_state(rg.bit_generator.state,
rg2.bit_generator.state))
# 测试随机数生成器种子设定函数
def test_seed(self):
# 使用指定种子初始化两个随机数生成器对象
rg = Generator(self.bit_generator(*self.seed))
rg2 = Generator(self.bit_generator(*self.seed))
# 生成随机数
rg.random()
rg2.random()
# 断言两个随机数生成器的状态相同
assert_(comp_state(rg.bit_generator.state, rg2.bit_generator.state))
# 测试重置随机数生成器状态后生成正态分布的函数
def test_reset_state_gauss(self):
# 使用指定种子初始化随机数生成器对象
rg = Generator(self.bit_generator(*self.seed))
# 生成标准正态分布样本
rg.standard_normal()
# 保存当前随机数生成器状态
state = rg.bit_generator.state
# 生成标准正态分布的样本数组
n1 = rg.standard_normal(size=10)
# 使用默认种子初始化新的随机数生成器对象
rg2 = Generator(self.bit_generator())
# 恢复之前保存的随机数生成器状态
rg2.bit_generator.state = state
# 生成标准正态分布的样本数组
n2 = rg2.standard_normal(size=10)
# 断言两次生成的正态分布样本数组相等
assert_array_equal(n1, n2)
# 测试重置随机数生成器状态后生成无符号 32 位整数的函数
def test_reset_state_uint32(self):
# 使用指定种子初始化随机数生成器对象
rg = Generator(self.bit_generator(*self.seed))
# 生成指定范围内的无符号 32 位整数样本数组
rg.integers(0, 2 ** 24, 120, dtype=np.uint32)
# 保存当前随机数生成器状态
state = rg.bit_generator.state
# 生成无符号 32 位整数样本数组
n1 = rg.integers(0, 2 ** 24, 10, dtype=np.uint32)
# 使用默认种子初始化新的随机数生成器对象
rg2 = Generator(self.bit_generator())
# 恢复之前保存的随机数生成器状态
rg2.bit_generator.state = state
# 生成无符号 32 位整数样本数组
n2 = rg2.integers(0, 2 ** 24, 10, dtype=np.uint32)
# 断言两次生成的无符号 32 位整数样本数组相等
assert_array_equal(n1, n2)
def test_reset_state_float(self):
# 创建一个生成器对象,使用给定的位生成器和种子初始化
rg = Generator(self.bit_generator(*self.seed))
# 生成浮点数随机数,改变生成器状态
rg.random(dtype='float32')
# 获取当前生成器的状态
state = rg.bit_generator.state
# 再次生成浮点数随机数,获得不同的随机数序列
n1 = rg.random(size=10, dtype='float32')
# 创建另一个生成器对象,使用默认的位生成器初始化
rg2 = Generator(self.bit_generator())
# 将第一个生成器的状态应用于第二个生成器
rg2.bit_generator.state = state
# 使用第二个生成器生成与第一个相同的随机数序列
n2 = rg2.random(size=10, dtype='float32')
# 断言两个随机数序列完全相同
assert_((n1 == n2).all())
def test_shuffle(self):
# 创建一个包含200到1的整数数组
original = np.arange(200, 0, -1)
# 对数组进行随机排列
permuted = self.rg.permutation(original)
# 断言原始数组与排列后数组有不同的元素
assert_((original != permuted).any())
def test_permutation(self):
# 创建一个包含200到1的整数数组
original = np.arange(200, 0, -1)
# 对数组进行随机排列
permuted = self.rg.permutation(original)
# 断言原始数组与排列后数组有不同的元素
assert_((original != permuted).any())
def test_beta(self):
# 生成 beta 分布的随机数,形状为(10,)
vals = self.rg.beta(2.0, 2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 使用数组作为参数生成 beta 分布的随机数,形状为(10,)
vals = self.rg.beta(np.array([2.0] * 10), 2.0)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 使用数组作为参数生成 beta 分布的随机数,形状为(10,)
vals = self.rg.beta(2.0, np.array([2.0] * 10))
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 使用数组作为参数生成 beta 分布的随机数,形状为(10,)
vals = self.rg.beta(np.array([2.0] * 10), np.array([2.0] * 10))
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 使用二维数组作为参数生成 beta 分布的随机数,形状为(10, 10)
vals = self.rg.beta(np.array([2.0] * 10), np.array([[2.0]] * 10))
# 断言生成的随机数数组形状为(10, 10)
assert_(vals.shape == (10, 10))
def test_bytes(self):
# 生成包含10个字节的随机字节数组
vals = self.rg.bytes(10)
# 断言生成的字节数组长度为10
assert_(len(vals) == 10)
def test_chisquare(self):
# 生成自由度为2的卡方分布的随机数,形状为(10,)
vals = self.rg.chisquare(2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 调用特定的参数检查函数
params_1(self.rg.chisquare)
def test_exponential(self):
# 生成参数为2的指数分布的随机数,形状为(10,)
vals = self.rg.exponential(2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 调用特定的参数检查函数
params_1(self.rg.exponential)
def test_f(self):
# 生成自由度为(3, 1000)的 F 分布的随机数,形状为(10,)
vals = self.rg.f(3, 1000, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_gamma(self):
# 生成形状参数为3,尺度参数为2的 Gamma 分布的随机数,形状为(10,)
vals = self.rg.gamma(3, 2, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_geometric(self):
# 生成几何分布的随机数,成功概率为0.5,形状为(10,)
vals = self.rg.geometric(0.5, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 调用特定的参数检查函数
params_1(self.rg.exponential, bounded=True)
def test_gumbel(self):
# 生成 Gumbel 分布的随机数,位置参数为2.0,尺度参数为2.0,形状为(10,)
vals = self.rg.gumbel(2.0, 2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_laplace(self):
# 生成 Laplace 分布的随机数,位置参数为2.0,尺度参数为2.0,形状为(10,)
vals = self.rg.laplace(2.0, 2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_logitic(self):
# 生成 Logistic 分布的随机数,位置参数为2.0,尺度参数为2.0,形状为(10,)
vals = self.rg.logistic(2.0, 2.0, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_logseries(self):
# 生成 Logseries 分布的随机数,概率参数为0.5,形状为(10,)
vals = self.rg.logseries(0.5, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_negative_binomial(self):
# 生成负二项分布的随机数,参数为(10, 0.2),形状为(10,)
vals = self.rg.negative_binomial(10, 0.2, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
def test_noncentral_chisquare(self):
# 生成非中心卡方分布的随机数,参数为(10, 2),形状为(10,)
vals = self.rg.noncentral_chisquare(10, 2, 10)
# 断言生成的随机数数组长度为10
assert_(len(vals) == 10)
# 测试非中心 F 分布生成器
def test_noncentral_f(self):
# 生成指定参数的非中心 F 分布样本
vals = self.rg.noncentral_f(3, 1000, 2, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 使用数组参数生成非中心 F 分布样本
vals = self.rg.noncentral_f(np.array([3] * 10), 1000, 2)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 使用数组参数生成非中心 F 分布样本
vals = self.rg.noncentral_f(3, np.array([1000] * 10), 2)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 使用数组参数生成非中心 F 分布样本
vals = self.rg.noncentral_f(3, 1000, np.array([2] * 10))
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试正态分布生成器
def test_normal(self):
# 生成指定参数的正态分布样本
vals = self.rg.normal(10, 0.2, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试帕累托分布生成器
def test_pareto(self):
# 生成指定参数的帕累托分布样本
vals = self.rg.pareto(3.0, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试泊松分布生成器
def test_poisson(self):
# 生成指定参数的泊松分布样本
vals = self.rg.poisson(10, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 使用数组参数生成泊松分布样本
vals = self.rg.poisson(np.array([10] * 10))
# 断言样本长度为 10
assert_(len(vals) == 10)
# 对泊松分布生成器应用参数检查函数
params_1(self.rg.poisson)
# 测试幂分布生成器
def test_power(self):
# 生成指定参数的幂分布样本
vals = self.rg.power(0.2, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试整数分布生成器
def test_integers(self):
# 生成指定参数的整数分布样本
vals = self.rg.integers(10, 20, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试瑞利分布生成器
def test_rayleigh(self):
# 生成指定参数的瑞利分布样本
vals = self.rg.rayleigh(0.2, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 对瑞利分布生成器应用参数检查函数,设定边界为真
params_1(self.rg.rayleigh, bounded=True)
# 测试冯·米塞斯分布生成器
def test_vonmises(self):
# 生成指定参数的冯·米塞斯分布样本
vals = self.rg.vonmises(10, 0.2, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试瓦尔德分布生成器
def test_wald(self):
# 生成指定参数的瓦尔德分布样本
vals = self.rg.wald(1.0, 1.0, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试威布尔分布生成器
def test_weibull(self):
# 生成指定参数的威布尔分布样本
vals = self.rg.weibull(1.0, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 测试齐普夫分布生成器
def test_zipf(self):
# 生成指定参数的齐普夫分布样本
vals = self.rg.zipf(10, 10)
# 断言样本长度为 10
assert_(len(vals) == 10)
# 使用一维向量参数生成齐普夫分布样本
vals = self.rg.zipf(self.vec_1d)
# 断言样本长度为 100
assert_(len(vals) == 100)
# 使用二维向量参数生成齐普夫分布样本
vals = self.rg.zipf(self.vec_2d)
# 断言样本形状为 (1, 100)
assert_(vals.shape == (1, 100))
# 使用矩阵参数生成齐普夫分布样本
vals = self.rg.zipf(self.mat)
# 断言样本形状为 (100, 100)
assert_(vals.shape == (100, 100))
# 测试超几何分布生成器
def test_hypergeometric(self):
# 生成指定参数的超几何分布样本
vals = self.rg.hypergeometric(25, 25, 20)
# 断言返回值为标量
assert_(np.isscalar(vals))
# 使用数组参数生成超几何分布样本
vals = self.rg.hypergeometric(np.array([25] * 10), 25, 20)
# 断言返回值形状为 (10,)
assert_(vals.shape == (10,))
# 测试三角分布生成器
def test_triangular(self):
# 生成指定参数的三角分布样本
vals = self.rg.triangular(-5, 0, 5)
# 断言返回值为标量
assert_(np.isscalar(vals))
# 使用数组参数生成三角分布样本
vals = self.rg.triangular(-5, np.array([0] * 10), 5)
# 断言返回值形状为 (10, )
assert_(vals.shape == (10,))
# 测试多变量正态分布生成器
def test_multivariate_normal(self):
# 设定均值和协方差矩阵
mean = [0, 0]
cov = [[1, 0], [0, 100]] # 对角协方差
# 生成指定参数的多变量正态分布样本
x = self.rg.multivariate_normal(mean, cov, 5000)
# 断言返回值形状为 (5000, 2)
assert_(x.shape == (5000, 2))
# 生成另一组多变量正态分布样本
x_zig = self.rg.multivariate_normal(mean, cov, 5000)
# 断言返回值形状为 (5000, 2)
assert_(x.shape == (5000, 2))
# 生成另一组多变量正态分布样本
x_inv = self.rg.multivariate_normal(mean, cov, 5000)
# 断言返回值形状为 (5000, 2)
assert_(x.shape == (5000, 2))
# 断言生成的两组样本不完全相同
assert_((x_zig != x_inv).any())
# 测试多项分布生成器
def test_multinomial(self):
# 生成指定参数的多项分布样本
vals = self.rg.multinomial(100, [1.0 / 3, 2.0 / 3])
# 断言返回值形状为 (2,)
assert_(vals.shape == (2,))
# 生成多组指定参数的多项分布样本
vals = self.rg.multin
# 测试 Dirichlet 分布生成器的功能
def test_dirichlet(self):
# 生成一个 Dirichlet 分布样本
s = self.rg.dirichlet((10, 5, 3), 20)
# 断言返回的样本形状是否符合预期
assert_(s.shape == (20, 3))
# 测试对象的序列化和反序列化功能
def test_pickle(self):
# 序列化对象 self.rg 并获取 pickle 字节流
pick = pickle.dumps(self.rg)
# 反序列化 pickle 字节流并获取反序列化后的对象 unpick
unpick = pickle.loads(pick)
# 断言序列化前后的对象类型相同
assert_((type(self.rg) == type(unpick)))
# 断言序列化前后对象的状态是否一致
assert_(comp_state(self.rg.bit_generator.state,
unpick.bit_generator.state))
# 再次进行相同的序列化和反序列化操作,进行二次验证
pick = pickle.dumps(self.rg)
unpick = pickle.loads(pick)
assert_((type(self.rg) == type(unpick)))
assert_(comp_state(self.rg.bit_generator.state,
unpick.bit_generator.state))
# 测试随机数生成器的种子数组初始化功能
def test_seed_array(self):
# 如果不支持向量种子,则跳过此测试
if self.seed_vector_bits is None:
bitgen_name = self.bit_generator.__name__
pytest.skip(f'Vector seeding is not supported by {bitgen_name}')
# 根据种子位数选择正确的数据类型
if self.seed_vector_bits == 32:
dtype = np.uint32
else:
dtype = np.uint64
# 使用单个元素的数组作为种子初始化生成器,并比较状态是否一致
seed = np.array([1], dtype=dtype)
bg = self.bit_generator(seed)
state1 = bg.state
bg = self.bit_generator(1)
state2 = bg.state
assert_(comp_state(state1, state2))
# 使用长度为 4 的数组作为种子初始化生成器,并比较状态是否一致
seed = np.arange(4, dtype=dtype)
bg = self.bit_generator(seed)
state1 = bg.state
bg = self.bit_generator(seed[0])
state2 = bg.state
assert_(not comp_state(state1, state2))
# 使用长度为 1500 的数组作为种子初始化生成器,并比较状态是否一致
seed = np.arange(1500, dtype=dtype)
bg = self.bit_generator(seed)
state1 = bg.state
bg = self.bit_generator(seed[0])
state2 = bg.state
assert_(not comp_state(state1, state2))
# 使用特定算法生成长度为 1500 的种子数组,并比较状态是否一致
seed = 2 ** np.mod(np.arange(1500, dtype=dtype),
self.seed_vector_bits - 1) + 1
bg = self.bit_generator(seed)
state1 = bg.state
bg = self.bit_generator(seed[0])
state2 = bg.state
assert_(not comp_state(state1, state2))
# 测试生成均匀分布的随机浮点数功能
def test_uniform_float(self):
# 创建随机数生成器 rg,并进行初始化和预热
rg = Generator(self.bit_generator(12345))
warmup(rg)
state = rg.bit_generator.state
# 生成一组随机浮点数 r1
r1 = rg.random(11, dtype=np.float32)
# 创建另一个随机数生成器 rg2,并初始化和预热,并恢复状态
rg2 = Generator(self.bit_generator())
warmup(rg2)
rg2.bit_generator.state = state
# 使用相同状态生成另一组随机浮点数 r2
r2 = rg2.random(11, dtype=np.float32)
# 断言两组随机数数组是否相等
assert_array_equal(r1, r2)
# 断言生成的浮点数类型是否为 np.float32
assert_equal(r1.dtype, np.float32)
# 断言两个随机数生成器的状态是否一致
assert_(comp_state(rg.bit_generator.state, rg2.bit_generator.state))
# 测试生成 Gamma 分布的随机浮点数功能
def test_gamma_floats(self):
# 创建随机数生成器 rg,并进行初始化和预热
rg = Generator(self.bit_generator())
warmup(rg)
state = rg.bit_generator.state
# 生成一组 Gamma 分布的随机浮点数 r1
r1 = rg.standard_gamma(4.0, 11, dtype=np.float32)
# 创建另一个随机数生成器 rg2,并初始化和预热,并恢复状态
rg2 = Generator(self.bit_generator())
warmup(rg2)
rg2.bit_generator.state = state
# 使用相同状态生成另一组 Gamma 分布的随机浮点数 r2
r2 = rg2.standard_gamma(4.0, 11, dtype=np.float32)
# 断言两组随机数数组是否相等
assert_array_equal(r1, r2)
# 断言生成的浮点数类型是否为 np.float32
assert_equal(r1.dtype, np.float32)
# 断言两个随机数生成器的状态是否一致
assert_(comp_state(rg.bit_generator.state, rg2.bit_generator.state))
# 测试标准正态分布生成器的功能,验证两个独立生成的随机数数组是否相等
def test_normal_floats(self):
# 使用指定的比特生成器创建随机数生成器对象
rg = Generator(self.bit_generator())
# 对生成器进行预热,确保生成的随机数稳定
warmup(rg)
# 获取当前比特生成器的状态
state = rg.bit_generator.state
# 生成长度为 11 的 np.float32 类型的标准正态分布随机数数组
r1 = rg.standard_normal(11, dtype=np.float32)
# 使用同一个比特生成器对象创建另一个随机数生成器对象
rg2 = Generator(self.bit_generator())
# 对第二个生成器进行预热
warmup(rg2)
# 将第二个生成器的状态设置为之前保存的状态,确保两次生成的随机数相同
rg2.bit_generator.state = state
# 生成另一个长度为 11 的 np.float32 类型的标准正态分布随机数数组
r2 = rg2.standard_normal(11, dtype=np.float32)
# 断言两个随机数数组相等
assert_array_equal(r1, r2)
# 断言随机数数组的数据类型为 np.float32
assert_equal(r1.dtype, np.float32)
# 比较两个比特生成器的状态是否相同
assert_(comp_state(rg.bit_generator.state, rg2.bit_generator.state))
# 测试标准正态分布生成器的功能,验证两个独立生成的随机数数组是否相等
def test_normal_zig_floats(self):
# 使用指定的比特生成器创建随机数生成器对象
rg = Generator(self.bit_generator())
# 对生成器进行预热,确保生成的随机数稳定
warmup(rg)
# 获取当前比特生成器的状态
state = rg.bit_generator.state
# 生成长度为 11 的 np.float32 类型的标准正态分布随机数数组
r1 = rg.standard_normal(11, dtype=np.float32)
# 使用同一个比特生成器对象创建另一个随机数生成器对象
rg2 = Generator(self.bit_generator())
# 对第二个生成器进行预热
warmup(rg2)
# 将第二个生成器的状态设置为之前保存的状态,确保两次生成的随机数相同
rg2.bit_generator.state = state
# 生成另一个长度为 11 的 np.float32 类型的标准正态分布随机数数组
r2 = rg2.standard_normal(11, dtype=np.float32)
# 断言两个随机数数组相等
assert_array_equal(r1, r2)
# 断言随机数数组的数据类型为 np.float32
assert_equal(r1.dtype, np.float32)
# 比较两个比特生成器的状态是否相同
assert_(comp_state(rg.bit_generator.state, rg2.bit_generator.state))
# 测试随机数填充功能,验证使用现有数组作为输出时是否正确生成随机数
def test_output_fill(self):
# 使用预设的随机数生成器对象
rg = self.rg
# 获取当前比特生成器的状态
state = rg.bit_generator.state
# 创建一个形状为 (31, 7, 97) 的空 np.ndarray 数组
size = (31, 7, 97)
existing = np.empty(size)
# 将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 使用现有数组 existing 作为输出,生成标准正态分布的随机数填充该数组
rg.standard_normal(out=existing)
# 再次将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 直接生成一个与 existing 相同形状的标准正态分布的随机数数组
direct = rg.standard_normal(size=size)
# 断言直接生成的数组与使用现有数组生成的数组相等
assert_equal(direct, existing)
# 创建一个形状为 (31, 7, 97) 的空 np.ndarray 数组
sized = np.empty(size)
# 将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 使用现有数组 sized 作为输出,生成标准正态分布的随机数填充该数组
rg.standard_normal(out=sized, size=sized.shape)
# 创建一个形状为 (31, 7, 97) 的空 np.ndarray 数组,指定数据类型为 np.float32
existing = np.empty(size, dtype=np.float32)
# 将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 使用现有数组 existing 作为输出,生成标准正态分布的随机数填充该数组,指定数据类型为 np.float32
rg.standard_normal(out=existing, dtype=np.float32)
# 再次将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 直接生成一个与 existing 相同形状的标准正态分布的随机数数组,指定数据类型为 np.float32
direct = rg.standard_normal(size=size, dtype=np.float32)
# 断言直接生成的数组与使用现有数组生成的数组相等
assert_equal(direct, existing)
# 测试随机数填充功能,验证使用现有数组作为输出时是否正确生成均匀分布的随机数
def test_output_filling_uniform(self):
# 使用预设的随机数生成器对象
rg = self.rg
# 获取当前比特生成器的状态
state = rg.bit_generator.state
# 创建一个形状为 (31, 7, 97) 的空 np.ndarray 数组
size = (31, 7, 97)
existing = np.empty(size)
# 将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 使用现有数组 existing 作为输出,生成均匀分布的随机数填充该数组
rg.random(out=existing)
# 再次将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 直接生成一个与 existing 相同形状的均匀分布的随机数数组
direct = rg.random(size=size)
# 断言直接生成的数组与使用现有数组生成的数组相等
assert_equal(direct, existing)
# 创建一个形状为 (31, 7, 97) 的空 np.ndarray 数组,指定数据类型为 np.float32
existing = np.empty(size, dtype=np.float32)
# 将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 使用现有数组 existing 作为输出,生成均匀分布的随机数填充该数组,指定数据类型为 np.float32
rg.random(out=existing, dtype=np.float32)
# 再次将比特生成器的状态恢复到之前保存的状态
rg.bit_generator.state = state
# 直接生成一个与 existing 相同形状的均匀分布的随机数数组,指定数据类型为 np.float32
direct = rg.random(size=size, dtype=np.float32)
# 断言直接生成的数组与使用现有数组生成的数组相等
assert_equal(direct, existing)
# 测试填充指数分布的输出数组
def test_output_filling_exponential(self):
# 获取随机数生成器实例
rg = self.rg
# 保存随机数生成器的状态
state = rg.bit_generator.state
# 指定数组的大小
size = (31, 7, 97)
# 创建一个空数组用于存储生成的随机数
existing = np.empty(size)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 使用已存在的数组填充指数分布的随机数
rg.standard_exponential(out=existing)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的指数分布随机数并存储在数组中
direct = rg.standard_exponential(size=size)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 创建一个空数组用于存储生成的随机数,指定数据类型为 float32
existing = np.empty(size, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 使用已存在的数组填充指数分布的随机数,指定数据类型为 float32
rg.standard_exponential(out=existing, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的指数分布随机数并存储在数组中,指定数据类型为 float32
direct = rg.standard_exponential(size=size, dtype=np.float32)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 测试填充 Gamma 分布的输出数组
def test_output_filling_gamma(self):
# 获取随机数生成器实例
rg = self.rg
# 保存随机数生成器的状态
state = rg.bit_generator.state
# 指定数组的大小
size = (31, 7, 97)
# 创建一个全零数组用于存储生成的随机数
existing = np.zeros(size)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 使用已存在的数组填充 Gamma 分布的随机数,参数为 1.0
rg.standard_gamma(1.0, out=existing)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的 Gamma 分布随机数并存储在数组中,参数为 1.0
direct = rg.standard_gamma(1.0, size=size)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 创建一个全零数组用于存储生成的随机数,指定数据类型为 float32
existing = np.zeros(size, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 使用已存在的数组填充 Gamma 分布的随机数,参数为 1.0,指定数据类型为 float32
rg.standard_gamma(1.0, out=existing, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的 Gamma 分布随机数并存储在数组中,参数为 1.0,指定数据类型为 float32
direct = rg.standard_gamma(1.0, size=size, dtype=np.float32)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 测试广播填充 Gamma 分布的输出数组
def test_output_filling_gamma_broadcast(self):
# 获取随机数生成器实例
rg = self.rg
# 保存随机数生成器的状态
state = rg.bit_generator.state
# 指定数组的大小
size = (31, 7, 97)
# 创建一个全零数组用于存储生成的随机数
existing = np.zeros(size)
# 使用广播方式填充 Gamma 分布的随机数,参数为从 1.0 到 97.0 的数组
rg.standard_gamma(np.arange(97.0) + 1.0, out=existing)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的 Gamma 分布随机数并存储在数组中,参数为从 1.0 到 97.0 的数组
direct = rg.standard_gamma(np.arange(97.0) + 1.0, size=size)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 创建一个全零数组用于存储生成的随机数,指定数据类型为 float32
existing = np.zeros(size, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 使用广播方式填充 Gamma 分布的随机数,参数为从 1.0 到 97.0 的数组,指定数据类型为 float32
rg.standard_gamma(np.arange(97.0) + 1.0, out=existing, dtype=np.float32)
# 恢复随机数生成器的状态
rg.bit_generator.state = state
# 直接生成指定大小的 Gamma 分布随机数并存储在数组中,参数为从 1.0 到 97.0 的数组,指定数据类型为 float32
direct = rg.standard_gamma(np.arange(97.0) + 1.0, size=size, dtype=np.float32)
# 断言两种方式生成的结果数组应当相等
assert_equal(direct, existing)
# 测试函数,用于验证生成器方法在特定条件下的输出是否会触发异常
def test_output_fill_error(self):
# 从测试类中获取生成器对象
rg = self.rg
# 定义一个元组表示数组大小
size = (31, 7, 97)
# 创建一个空数组,用于存储生成的随机数
existing = np.empty(size)
# 测试:确保在指定类型错误时会引发异常
with pytest.raises(TypeError):
rg.standard_normal(out=existing, dtype=np.float32)
# 测试:确保在指定值错误时会引发异常
with pytest.raises(ValueError):
rg.standard_normal(out=existing[::3])
# 重新定义数组类型和测试异常
existing = np.empty(size, dtype=np.float32)
with pytest.raises(TypeError):
rg.standard_normal(out=existing, dtype=np.float64)
existing = np.zeros(size, dtype=np.float32)
with pytest.raises(TypeError):
rg.standard_gamma(1.0, out=existing, dtype=np.float64)
with pytest.raises(ValueError):
rg.standard_gamma(1.0, out=existing[::3])
# 重新定义数组类型和测试异常
existing = np.zeros(size, dtype=np.float64)
with pytest.raises(TypeError):
rg.standard_gamma(1.0, out=existing, dtype=np.float32)
with pytest.raises(ValueError):
rg.standard_gamma(1.0, out=existing[::3])
# 测试函数,用于验证整数生成器在不同情况下的输出是否正确
def test_integers_broadcast(self, dtype):
# 根据数据类型设置上下界
if dtype == np.bool:
upper = 2
lower = 0
else:
info = np.iinfo(dtype)
upper = int(info.max) + 1
lower = info.min
# 重置生成器状态
self._reset_state()
# 测试生成器方法:lower为标量,upper为列表
a = self.rg.integers(lower, [upper] * 10, dtype=dtype)
self._reset_state()
# 测试生成器方法:lower为列表,upper为标量
b = self.rg.integers([lower] * 10, upper, dtype=dtype)
# 确保两次生成的结果相等
assert_equal(a, b)
self._reset_state()
# 测试生成器方法:lower和upper均为标量
c = self.rg.integers(lower, upper, size=10, dtype=dtype)
# 确保生成的结果与a相等
assert_equal(a, c)
self._reset_state()
# 测试生成器方法:lower和upper均为数组对象
d = self.rg.integers(np.array(
[lower] * 10), np.array([upper], dtype=object), size=10,
dtype=dtype)
# 确保生成的结果与a相等
assert_equal(a, d)
self._reset_state()
# 测试生成器方法:lower和upper均为数组对象
e = self.rg.integers(
np.array([lower] * 10), np.array([upper] * 10), size=10,
dtype=dtype)
# 确保生成的结果与a相等
assert_equal(a, e)
# 重置生成器状态
self._reset_state()
# 测试生成器方法:lower为标量,upper为标量
a = self.rg.integers(0, upper, size=10, dtype=dtype)
self._reset_state()
# 测试生成器方法:lower为列表,upper为标量
b = self.rg.integers([upper] * 10, dtype=dtype)
# 确保两次生成的结果相等
assert_equal(a, b)
# 测试函数,用于验证整数生成器对NumPy数组的处理是否正确
def test_integers_numpy(self, dtype):
# 定义高和低的NumPy数组
high = np.array([1])
low = np.array([0])
# 测试生成器方法:使用NumPy数组作为输入
out = self.rg.integers(low, high, dtype=dtype)
# 确保输出形状符合预期
assert out.shape == (1,)
# 测试生成器方法:使用NumPy数组作为输入,低位为标量
out = self.rg.integers(low[0], high, dtype=dtype)
# 确保输出形状符合预期
assert out.shape == (1,)
# 测试生成器方法:使用NumPy数组作为输入,高位为标量
out = self.rg.integers(low, high[0], dtype=dtype)
# 确保输出形状符合预期
assert out.shape == (1,)
# 测试整数生成函数在广播错误处理方面的行为
def test_integers_broadcast_errors(self, dtype):
# 如果数据类型是布尔型
if dtype == np.bool:
# 设置上界为2,下界为0
upper = 2
lower = 0
else:
# 获取数据类型的信息对象
info = np.iinfo(dtype)
# 计算上界为最大值加1后的整数值
upper = int(info.max) + 1
# 下界为数据类型的最小值
lower = info.min
# 断言调用生成整数函数时,超出上界抛出值错误
with pytest.raises(ValueError):
self.rg.integers(lower, [upper + 1] * 10, dtype=dtype)
# 断言调用生成整数函数时,超出下界抛出值错误
with pytest.raises(ValueError):
self.rg.integers(lower - 1, [upper] * 10, dtype=dtype)
# 断言调用生成整数函数时,下界参数不是标量抛出值错误
with pytest.raises(ValueError):
self.rg.integers([lower - 1], [upper] * 10, dtype=dtype)
# 断言调用生成整数函数时,上下界参数都不是标量抛出值错误
with pytest.raises(ValueError):
self.rg.integers([0], [0], dtype=dtype)
class TestMT19937(RNG):
@classmethod
def setup_class(cls):
# 设置比特生成器为MT19937
cls.bit_generator = MT19937
# 设置 advance 为None,表示没有预定义的状态前进量
cls.advance = None
# 设置种子为一个列表,包含一个整数值
cls.seed = [2 ** 21 + 2 ** 16 + 2 ** 5 + 1]
# 使用给定的比特生成器和种子创建一个生成器对象
cls.rg = Generator(cls.bit_generator(*cls.seed))
# 记录生成器的初始状态
cls.initial_state = cls.rg.bit_generator.state
# 设置种子向量的比特数为32
cls.seed_vector_bits = 32
# 调用额外的设置方法
cls._extra_setup()
# 设置种子错误为 ValueError
cls.seed_error = ValueError
def test_numpy_state(self):
# 创建一个numpy的随机状态对象
nprg = np.random.RandomState()
# 生成99个标准正态分布的随机数
nprg.standard_normal(99)
# 获取当前的状态
state = nprg.get_state()
# 将获取到的状态设置为当前生成器的比特生成器状态
self.rg.bit_generator.state = state
# 再次获取当前的比特生成器状态
state2 = self.rg.bit_generator.state
# 断言两个状态的第一个元素相等
assert_((state[1] == state2['state']['key']).all())
# 断言两个状态的第二个元素相等
assert_((state[2] == state2['state']['pos']))
class TestPhilox(RNG): @classmethod def setup_class(cls): # 设置比特生成器为Philox cls.bit_generator = Philox # 设置 advance 为一个大整数,表示预定义的状态前进量 cls.advance = 263 + 231 + 2**15 + 1 # 设置种子为一个列表,包含一个整数值 cls.seed = [12345] # 使用给定的比特生成器和种子创建一个生成器对象 cls.rg = Generator(cls.bit_generator(*cls.seed)) # 记录生成器的初始状态 cls.initial_state = cls.rg.bit_generator.state # 设置种子向量的比特数为64 cls.seed_vector_bits = 64 # 调用额外的设置方法 cls._extra_setup()
class TestSFC64(RNG): @classmethod def setup_class(cls): # 设置比特生成器为SFC64 cls.bit_generator = SFC64 # 设置 advance 为None,表示没有预定义的状态前进量 cls.advance = None # 设置种子为一个列表,包含一个整数值 cls.seed = [12345] # 使用给定的比特生成器和种子创建一个生成器对象 cls.rg = Generator(cls.bit_generator(*cls.seed)) # 记录生成器的初始状态 cls.initial_state = cls.rg.bit_generator.state # 设置种子向量的比特数为192 cls.seed_vector_bits = 192 # 调用额外的设置方法 cls._extra_setup()
class TestPCG64(RNG): @classmethod def setup_class(cls): # 设置比特生成器为PCG64 cls.bit_generator = PCG64 # 设置 advance 为一个大整数,表示预定义的状态前进量 cls.advance = 263 + 231 + 2**15 + 1 # 设置种子为一个列表,包含一个整数值 cls.seed = [12345] # 使用给定的比特生成器和种子创建一个生成器对象 cls.rg = Generator(cls.bit_generator(*cls.seed)) # 记录生成器的初始状态 cls.initial_state = cls.rg.bit_generator.state # 设置种子向量的比特数为64 cls.seed_vector_bits = 64 # 调用额外的设置方法 cls._extra_setup()
class TestPCG64DXSM(RNG): @classmethod def setup_class(cls): # 设置比特生成器为PCG64DXSM cls.bit_generator = PCG64DXSM # 设置 advance 为一个大整数,表示预定义的状态前进量 cls.advance = 263 + 231 + 2**15 + 1 # 设置种子为一个列表,包含一个整数值 cls.seed = [12345] # 使用给定的比特生成器和种子创建一个生成器对象 cls.rg = Generator(cls.bit_generator(*cls.seed)) # 记录生成器的初始状态 cls.initial_state = cls.rg.bit_generator.state # 设置种子向量的比特数为64 cls.seed_vector_bits = 64 # 调用额外的设置方法 cls._extra_setup()
class TestDefaultRNG(RNG): @classmethod def setup_class(cls): # 这将重复一些直接实例化新生成器对象的测试,但没关系。 # 设置比特生成器为PCG64 cls.bit_generator = PCG64 # 设置 advance 为一个大整数,表示预定义的状态前进量 cls.advance = 263 + 231 + 2**15 + 1 # 设置种子为一个列表,包含一个整数值 cls.seed = [12345] # 使用给定的种子创建一个numpy的随机生成器对象 cls.rg = np.random.default_rng(*cls.seed) # 记录生成器的初始状态 cls.initial_state = cls.rg.bit_generator.state # 设置种子向量的比特数为64 cls.seed_vector_bits = 64 # 调用额外的设置方法 cls._extra_setup()
def test_default_is_pcg64(self):
# 为了改变默认的比特生成器,我们会通过一个弃用周期来迁移到一个不同的函数。
# 断言当前生成器的比特生成器是PCG64的实例
assert_(isinstance(self.rg.bit_generator, PCG64))
# 定义单元测试方法 test_seed,用于测试 np.random.default_rng 函数的不同参数情况
def test_seed(self):
# 使用默认种子创建一个随机数生成器对象
np.random.default_rng()
# 使用 None 作为种子创建一个随机数生成器对象
np.random.default_rng(None)
# 使用整数 12345 作为种子创建一个随机数生成器对象
np.random.default_rng(12345)
# 使用整数 0 作为种子创建一个随机数生成器对象
np.random.default_rng(0)
# 使用一个非常大的整数作为种子创建一个随机数生成器对象
np.random.default_rng(43660444402423911716352051725018508569)
# 使用包含两个整数的列表作为种子创建一个随机数生成器对象
np.random.default_rng([43660444402423911716352051725018508569,
279705150948142787361475340226491943209])
# 测试使用负数作为种子是否会引发 ValueError 异常
with pytest.raises(ValueError):
np.random.default_rng(-1)
# 测试使用包含负数的列表作为种子是否会引发 ValueError 异常
with pytest.raises(ValueError):
np.random.default_rng([12345, -1])
# `.\numpy\numpy\random\tests\__init__.py`
```py
# 定义一个函数 `calculate_circle_area`,用于计算圆的面积
def calculate_circle_area(radius):
# 导入数学库,以便使用其中的圆周率常量 PI
import math
# 计算圆的面积,公式为 PI * r^2,其中 r 是圆的半径
area = math.pi * radius**2
# 返回计算得到的圆的面积
return area
.\numpy\numpy\random\_common.pxd
# 设置 Cython 语言级别为 Python 3
# 从 libc.stdint 中导入特定类型的整数
from libc.stdint cimport uint32_t, uint64_t, int32_t, int64_t
# 导入 NumPy 库,并且使用 Cython 语法导入它
import numpy as np
cimport numpy as np
# 定义 C 语言的双精度浮点数变量
cdef double POISSON_LAM_MAX
cdef double LEGACY_POISSON_LAM_MAX
cdef uint64_t MAXSIZE
# 定义枚举类型 ConstraintType,并给出每个类型的值
cdef enum ConstraintType:
CONS_NONE
CONS_NON_NEGATIVE
CONS_POSITIVE
CONS_POSITIVE_NOT_NAN
CONS_BOUNDED_0_1
CONS_BOUNDED_GT_0_1
CONS_BOUNDED_LT_0_1
CONS_GT_1
CONS_GTE_1
CONS_POISSON
LEGACY_CONS_POISSON
LEGACY_CONS_NON_NEGATIVE_INBOUNDS_LONG
# 将 ConstraintType 定义为 constraint_type 类型别名
ctypedef ConstraintType constraint_type
# 声明一些 C 函数的原型,这些函数将在后续的代码中实现
cdef object benchmark(bitgen_t *bitgen, object lock, Py_ssize_t cnt, object method)
cdef object random_raw(bitgen_t *bitgen, object lock, object size, object output)
cdef object prepare_cffi(bitgen_t *bitgen)
cdef object prepare_ctypes(bitgen_t *bitgen)
cdef int check_constraint(double val, object name, constraint_type cons) except -1
cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1
# 从外部头文件 "include/aligned_malloc.h" 中导入一些 C 函数的原型
cdef extern from "include/aligned_malloc.h":
cdef void *PyArray_realloc_aligned(void *p, size_t n)
cdef void *PyArray_malloc_aligned(size_t n)
cdef void *PyArray_calloc_aligned(size_t n, size_t s)
cdef void PyArray_free_aligned(void *p)
# 定义几种函数指针类型,这些指针将指向后续定义的函数
ctypedef void (*random_double_fill)(bitgen_t *state, np.npy_intp count, double* out) noexcept nogil
ctypedef double (*random_double_0)(void *state) noexcept nogil
ctypedef double (*random_double_1)(void *state, double a) noexcept nogil
ctypedef double (*random_double_2)(void *state, double a, double b) noexcept nogil
ctypedef double (*random_double_3)(void *state, double a, double b, double c) noexcept nogil
ctypedef void (*random_float_fill)(bitgen_t *state, np.npy_intp count, float* out) noexcept nogil
ctypedef float (*random_float_0)(bitgen_t *state) noexcept nogil
ctypedef float (*random_float_1)(bitgen_t *state, float a) noexcept nogil
ctypedef int64_t (*random_uint_0)(void *state) noexcept nogil
ctypedef int64_t (*random_uint_d)(void *state, double a) noexcept nogil
ctypedef int64_t (*random_uint_dd)(void *state, double a, double b) noexcept nogil
ctypedef int64_t (*random_uint_di)(void *state, double a, uint64_t b) noexcept nogil
ctypedef int64_t (*random_uint_i)(void *state, int64_t a) noexcept nogil
ctypedef int64_t (*random_uint_iii)(void *state, int64_t a, int64_t b, int64_t c) noexcept nogil
ctypedef uint32_t (*random_uint_0_32)(bitgen_t *state) noexcept nogil
ctypedef uint32_t (*random_uint_1_i_32)(bitgen_t *state, uint32_t a) noexcept nogil
ctypedef int32_t (*random_int_2_i_32)(bitgen_t *state, int32_t a, int32_t b) noexcept nogil
ctypedef int64_t (*random_int_2_i)(bitgen_t *state, int64_t a, int64_t b) noexcept nogil
# 声明一个 C 函数的原型,这个函数在后续代码中实现
cdef double kahan_sum(double *darr, np.npy_intp n) noexcept
# 定义一个内联函数,将 uint64_t 类型的整数转换为 double 类型的浮点数
cdef inline double uint64_to_double(uint64_t rnd) noexcept nogil:
return (rnd >> 11) * (1.0 / 9007199254740992.0)
# 定义 C 语言扩展函数 double_fill,接受指针 func、bitgen_t 类型的 state,以及 size、lock 和 out 作为参数,返回一个 Python 对象
cdef object double_fill(void *func, bitgen_t *state, object size, object lock, object out)
# 定义 C 语言扩展函数 float_fill,接受指针 func、bitgen_t 类型的 state,以及 size、lock 和 out 作为参数,返回一个 Python 对象
cdef object float_fill(void *func, bitgen_t *state, object size, object lock, object out)
# 定义 C 语言扩展函数 float_fill_from_double,接受指针 func、bitgen_t 类型的 state,以及 size、lock 和 out 作为参数,返回一个 Python 对象
cdef object float_fill_from_double(void *func, bitgen_t *state, object size, object lock, object out)
# 定义 C 语言扩展函数 wrap_int,接受 val 和 bits 作为参数,返回一个 Python 对象
cdef object wrap_int(object val, object bits)
# 定义 C 语言扩展函数 int_to_array,接受 value、name、bits 和 uint_size 作为参数,返回一个 NumPy 数组对象
cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size)
# 定义 C 语言扩展函数 validate_output_shape,接受 iter_shape 和 output 作为参数,无返回值
cdef validate_output_shape(iter_shape, np.ndarray output)
# 定义 C 语言扩展函数 cont,接受指针 func、state、size、lock、narg 和多个参数(a、a_name、a_constraint、b、b_name、b_constraint、c、c_name、c_constraint)作为参数,返回一个 Python 对象
cdef object cont(void *func, void *state, object size, object lock, int narg,
object a, object a_name, constraint_type a_constraint,
object b, object b_name, constraint_type b_constraint,
object c, object c_name, constraint_type c_constraint,
object out)
# 定义 C 语言扩展函数 disc,接受指针 func、state、size、lock、narg_double、narg_int64 和多个参数(a、a_name、a_constraint、b、b_name、b_constraint、c、c_name、c_constraint)作为参数,返回一个 Python 对象
cdef object disc(void *func, void *state, object size, object lock,
int narg_double, int narg_int64,
object a, object a_name, constraint_type a_constraint,
object b, object b_name, constraint_type b_constraint,
object c, object c_name, constraint_type c_constraint)
# 定义 C 语言扩展函数 cont_f,接受指针 func、bitgen_t 类型的 state、size、lock 和多个参数(a、a_name、a_constraint)作为参数,返回一个 Python 对象
cdef object cont_f(void *func, bitgen_t *state, object size, object lock,
object a, object a_name, constraint_type a_constraint,
object out)
# 定义 C 语言扩展函数 cont_broadcast_3,接受指针 func、state、size、lock、多个 NumPy 数组参数(a_arr、a_name、a_constraint、b_arr、b_name、b_constraint、c_arr、c_name、c_constraint)作为参数,返回一个 Python 对象
cdef object cont_broadcast_3(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint,
np.ndarray c_arr, object c_name, constraint_type c_constraint)
# 定义 C 语言扩展函数 discrete_broadcast_iii,接受指针 func、state、size、lock、多个 NumPy 数组参数(a_arr、a_name、a_constraint、b_arr、b_name、b_constraint、c_arr、c_name、c_constraint)作为参数,返回一个 Python 对象
cdef object discrete_broadcast_iii(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint,
np.ndarray c_arr, object c_name, constraint_type c_constraint)
.\numpy\numpy\random\_common.pyx
# 导入必要的模块和函数
# 设置 Cython 编译器的参数,关闭部分安全检查以提高性能
# 使用 namedtuple 定义一个接口,包含多个字段
# 导入 NumPy 库并调用其 import_array() 方法
from collections import namedtuple # 导入 namedtuple 类
from cpython cimport PyFloat_AsDouble # 导入 CPython 的 PyFloat_AsDouble 函数
import sys # 导入 sys 模块
import numpy as np # 导入 NumPy 库
cimport numpy as np # 在 Cython 中导入 NumPy 库
# 导入 C 库中的数据类型和函数
from libc.stdint cimport uintptr_t # 导入 uintptr_t 类型
from libc.math cimport isnan, signbit # 导入 C 库中的 isnan 和 signbit 函数
# 从 limits.h 头文件中导入 LONG_MAX 常量
cdef extern from "limits.h":
cdef long LONG_MAX # 定义 LONG_MAX 常量,NumPy 应该也有,也许 `__init__.pyd` 应该暴露它
# 定义要导出的模块成员列表
__all__ = ['interface']
# 导入 NumPy C API
np.import_array()
# 使用 namedtuple 定义接口,包含多个字段:state_address, state, next_uint64, next_uint32, next_double, bit_generator
interface = namedtuple('interface', ['state_address', 'state', 'next_uint64',
'next_uint32', 'next_double',
'bit_generator'])
# 定义两个常量,分别是 legacy Poisson 和 Poisson 参数的最大值
cdef double LEGACY_POISSON_LAM_MAX = <double>np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10
cdef double POISSON_LAM_MAX = <double>np.iinfo('int64').max - np.sqrt(np.iinfo('int64').max)*10
# 定义一个常量,表示 Python 中的 sys.maxsize 转换成 uint64_t 类型
cdef uint64_t MAXSIZE = <uint64_t>sys.maxsize
# 定义一个函数 benchmark,用于测试 BitGenerator 的性能
# 方法名为 benchmark
# 参数包括 bitgen: BitGenerator 结构体的地址, lock: BitGenerator 提供的锁, cnt: 计数器, method: 方法名称
cdef object benchmark(bitgen_t *bitgen, object lock, Py_ssize_t cnt, object method):
"""Benchmark command used by BitGenerator"""
cdef Py_ssize_t i # 定义一个 Python ssize_t 类型的变量 i
if method=='uint64': # 如果 method 参数为 'uint64'
with lock, nogil: # 使用锁和 nogil 上下文管理器
for i in range(cnt): # 循环 cnt 次
bitgen.next_uint64(bitgen.state) # 调用 BitGenerator 的 next_uint64 方法
elif method=='double': # 如果 method 参数为 'double'
with lock, nogil: # 使用锁和 nogil 上下文管理器
for i in range(cnt): # 循环 cnt 次
bitgen.next_double(bitgen.state) # 调用 BitGenerator 的 next_double 方法
else:
raise ValueError('Unknown method') # 抛出 ValueError 异常,表示未知的方法
# 定义一个函数 random_raw,用于返回基础 PRNG 生成的随机数
# 方法名为 random_raw
# 参数包括 bitgen: BitGenerator 结构体的地址, lock: BitGenerator 提供的锁, size: 输出形状, output: 是否输出性能测试
cdef object random_raw(bitgen_t *bitgen, object lock, object size, object output):
"""
random_raw(self, size=None)
Return randoms as generated by the underlying PRNG
Parameters
----------
bitgen : BitGenerator
Address of the bit generator struct
lock : Threading.Lock
Lock provided by the bit generator
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
output : bool, optional
Output values. Used for performance testing since the generated
values are not returned.
Returns
-------
out : uint or ndarray
Drawn samples.
Notes
-----
This method directly exposes the raw underlying pseudo-random
number generator. All values are returned as unsigned 64-bit
values irrespective of the number of bits produced by the PRNG.
See the class docstring for the number of bits returned.
"""
cdef np.ndarray randoms # 定义一个 NumPy 数组变量 randoms
cdef uint64_t *randoms_data # 定义一个 uint64_t 类型指针变量 randoms_data
cdef Py_ssize_t i, n # 定义 Python ssize_t 类型变量 i 和 n
if not output: # 如果 output 参数为 False
if size is None: # 如果 size 参数为 None
with lock: # 使用锁
bitgen.next_raw(bitgen.state) # 调用 BitGenerator 的 next_raw 方法
return None # 返回 None
n = np.asarray(size).sum() # 计算 size 参数的总和
with lock, nogil: # 使用锁和 nogil 上下文管理器
for i in range(n): # 循环 n 次
bitgen.next_raw(bitgen.state) # 调用 BitGenerator 的 next_raw 方法
return None # 返回 None
if size is None: # 如果 size 参数为 None
with lock: # 使用锁
return bitgen.next_raw(bitgen.state) # 返回 BitGenerator 的 next_raw 方法的结果
randoms = <np.ndarray>np.empty(size, np.uint64) # 创建一个空的 NumPy 数组 randoms,数据类型为 uint64,形状为 size
# 将 NumPy 数组 `randoms` 的数据指针转换为 uint64_t 类型的指针
randoms_data = <uint64_t*>np.PyArray_DATA(randoms)
# 获取 NumPy 数组 `randoms` 的大小(元素个数)
n = np.PyArray_SIZE(randoms)
# 使用 Cython 的 `with` 语句结合 `lock` 和 `nogil` 上下文管理器,
# 以确保在没有全局解释器锁 (GIL) 的情况下安全地执行以下代码块
with lock, nogil:
# 遍历数组 `randoms` 的每一个元素
for i in range(n):
# 调用 `bitgen.next_raw(bitgen.state)` 方法生成下一个随机数,
# 并将其存储到 `randoms_data[i]` 中
randoms_data[i] = bitgen.next_raw(bitgen.state)
# 返回更新后的 NumPy 数组 `randoms`
return randoms
cdef object prepare_cffi(bitgen_t *bitgen):
"""
使用 cffi 打包与 BitGenerator 的交互接口
Parameters
----------
bitgen : pointer
指向 BitGenerator 实例的指针
Returns
-------
interface : namedtuple
使用 cffi 与 BitGenerator 交互所需的函数接口:
* state_address - 状态结构体的内存地址
* state - 指向状态结构体的指针
* next_uint64 - 生成 64 位整数的函数指针
* next_uint32 - 生成 32 位整数的函数指针
* next_double - 生成双精度浮点数的函数指针
* bit_generator - 指向 BitGenerator 结构体的指针
"""
try:
import cffi
except ImportError as e:
raise ImportError('cffi 无法导入。') from e
ffi = cffi.FFI()
_cffi = interface(<uintptr_t>bitgen.state,
ffi.cast('void *', <uintptr_t>bitgen.state),
ffi.cast('uint64_t (*)(void *)', <uintptr_t>bitgen.next_uint64),
ffi.cast('uint32_t (*)(void *)', <uintptr_t>bitgen.next_uint32),
ffi.cast('double (*)(void *)', <uintptr_t>bitgen.next_double),
ffi.cast('void *', <uintptr_t>bitgen))
return _cffi
cdef object prepare_ctypes(bitgen_t *bitgen):
"""
使用 ctypes 打包与 BitGenerator 的交互接口
Parameters
----------
bitgen : pointer
指向 BitGenerator 实例的指针
Returns
-------
interface : namedtuple
使用 ctypes 与 BitGenerator 交互所需的函数接口:
* state_address - 状态结构体的内存地址
* state - 指向状态结构体的指针
* next_uint64 - 生成 64 位整数的函数指针
* next_uint32 - 生成 32 位整数的函数指针
* next_double - 生成双精度浮点数的函数指针
* bit_generator - 指向 BitGenerator 结构体的指针
"""
import ctypes
_ctypes = interface(<uintptr_t>bitgen.state,
ctypes.c_void_p(<uintptr_t>bitgen.state),
ctypes.cast(<uintptr_t>bitgen.next_uint64,
ctypes.CFUNCTYPE(ctypes.c_uint64,
ctypes.c_void_p)),
ctypes.cast(<uintptr_t>bitgen.next_uint32,
ctypes.CFUNCTYPE(ctypes.c_uint32,
ctypes.c_void_p)),
ctypes.cast(<uintptr_t>bitgen.next_double,
ctypes.CFUNCTYPE(ctypes.c_double,
ctypes.c_void_p)),
ctypes.c_void_p(<uintptr_t>bitgen))
return _ctypes
cdef double kahan_sum(double *darr, np.npy_intp n) noexcept:
"""
Parameters
----------
darr : pointer
指向双精度浮点数数组的指针
n : np.npy_intp
数组的长度
Returns
-------
double
数组元素的累加和,使用 Kahan 算法
Raises
------
"""
# darr : double 数组的引用
# 要求求和的数值地址
# n : intp
# darr 数组的长度
# Returns
# -------
# float
# 总和。如果 n <= 0,则返回 0.0。
"""
# 使用 Cython 声明变量,以提高性能
cdef double c, y, t, sum
cdef np.npy_intp i
# 如果 n 小于等于 0,直接返回 0.0
if n <= 0:
return 0.0
# 初始化 sum 为数组第一个元素的值
sum = darr[0]
# 初始化 c 为 0.0
c = 0.0
# 遍历数组,从第二个元素开始累加到 sum
for i in range(1, n):
# 计算当前元素与 c 的差值
y = darr[i] - c
# 将 sum 与 y 相加得到 t
t = sum + y
# 更新 c 为 (t - sum) - y
c = (t - sum) - y
# 更新 sum 为 t
sum = t
# 返回最终的总和值
return sum
# 将整数包装到区间 [0, 2**bits) 中
cdef object wrap_int(object val, object bits):
mask = ~(~int(0) << bits) # 创建一个掩码,用于限制整数在指定位数范围内
return val & mask # 返回 val 和掩码的按位与操作结果,确保 val 在指定范围内
# 将大整数转换为无符号整数数组
cdef np.ndarray int_to_array(object value, object name, object bits, object uint_size):
len = bits // uint_size # 计算数组长度,根据位数和单个整数大小计算
value = np.asarray(value) # 将 value 转换为 NumPy 数组
if uint_size == 32:
dtype = np.uint32 # 设置数据类型为 uint32
elif uint_size == 64:
dtype = np.uint64 # 设置数据类型为 uint64
else:
raise ValueError('Unknown uint_size') # 抛出异常,未知的 uint_size
if value.shape == (): # 如果 value 是标量
value = int(value) # 转换为整数
upper = int(2)**int(bits) # 计算上限值
if value < 0 or value >= upper:
raise ValueError(f'{name} must be positive and less than 2**{bits}.') # 抛出数值错误异常
out = np.empty(len, dtype=dtype) # 创建一个空数组,用于存储结果
for i in range(len):
out[i] = value % 2**int(uint_size) # 将整数按位拆分存入数组
value >>= int(uint_size) # 右移整数以处理下一部分数据
else:
out = value.astype(dtype) # 如果 value 是数组,则直接转换为指定类型
if out.shape != (len,): # 如果数组形状不符合预期长度
raise ValueError(f'{name} must have {len} elements when using array form') # 抛出数值错误异常
return out # 返回转换后的数组
# 验证输出数组的形状与迭代形状是否一致
cdef validate_output_shape(iter_shape, np.ndarray output):
cdef np.npy_intp *dims # 创建指向整数数组的指针 dims
cdef np.npy_intp ndim, i # 创建整数变量 ndim 和 i
cdef bint error # 创建布尔值变量 error
dims = np.PyArray_DIMS(output) # 获取输出数组的维度信息
ndim = np.PyArray_NDIM(output) # 获取输出数组的维度数量
output_shape = tuple((dims[i] for i in range(ndim))) # 将维度信息转换为元组形式
if iter_shape != output_shape: # 如果迭代形状与输出形状不一致
raise ValueError(
f"Output size {output_shape} is not compatible with broadcast "
f"dimensions of inputs {iter_shape}."
) # 抛出数值错误异常,输出数组大小与输入的广播维度不兼容
# 检查用户提供的输出数组属性和形状
cdef check_output(object out, object dtype, object size, bint require_c_array):
"""
检查用户提供的输出数组属性和形状
Parameters
----------
out : {ndarray, None}
要检查的数组。如果为 None,则立即返回。
dtype : dtype
out 的所需数据类型。
size : {None, int, tuple[int]}
传递的大小。如果 out 是一个 ndarray,则验证其形状是否与 size 匹配。
require_c_array : bool
是否要求 out 必须是 C 数组。如果为 False,则 out 可以是 C 或 F 排序的。
如果为 True,则必须是 C 排序的。在任何情况下,必须是连续的、可写的、对齐的,
并且是本机字节顺序的。
"""
if out is None: # 如果输出数组为 None,则直接返回
return
cdef np.ndarray out_array = <np.ndarray>out # 将 out 强制转换为 NumPy 数组
if not (np.PyArray_ISCARRAY(out_array) or
(np.PyArray_ISFARRAY(out_array) and not require_c_array)):
req = "C-" if require_c_array else "" # 如果要求 C 数组,设置说明字符串为 "C-"
raise ValueError(
f'Supplied output array must be {req}contiguous, writable, '
f'aligned, and in machine byte-order.'
) # 抛出数值错误异常,提供的输出数组必须是指定要求的类型
if out_array.dtype != dtype: # 如果输出数组的数据类型与要求不符
raise TypeError('Supplied output array has the wrong type. '
'Expected {0}, got {1}'.format(np.dtype(dtype), out_array.dtype)) # 抛出类型错误异常,输出数组类型错误
# 如果 size 参数不为 None,则执行以下逻辑
try:
# 尝试将 size 转换为元组类型
tup_size = tuple(size)
except TypeError:
# 如果 size 不能被转换为元组(可能是单个元素),则将其转换为包含该元素的元组
tup_size = tuple([size])
# 如果 tup_size 与 out 的形状不匹配,则抛出数值错误异常
if tup_size != out.shape:
raise ValueError('size must match out.shape when used together')
# 定义 C 扩展函数,用于填充双精度浮点数数组
cdef object double_fill(void *func, bitgen_t *state, object size, object lock, object out):
# 将 void 指针转换为双精度浮点数填充函数类型
cdef random_double_fill random_func = (<random_double_fill>func)
# 声明双精度浮点数输出值
cdef double out_val
# 声明双精度浮点数数组数据指针
cdef double *out_array_data
# 声明 NumPy 数组对象
cdef np.ndarray out_array
# 声明 NumPy 中的整数类型和变量
cdef np.npy_intp i, n
# 如果 size 和 out 均为 None
if size is None and out is None:
# 使用锁,调用随机双精度浮点数填充函数,返回填充后的值
with lock:
random_func(state, 1, &out_val)
return out_val
# 如果 out 不为 None
if out is not None:
# 检查输出数组是否符合要求的 np.float64 类型和指定的大小,不要求 C 连续性
check_output(out, np.float64, size, False)
out_array = <np.ndarray>out
else:
# 创建一个指定大小的空双精度浮点数数组
out_array = <np.ndarray>np.empty(size, np.double)
# 获取输出数组的长度
n = np.PyArray_SIZE(out_array)
# 获取输出数组的数据指针
out_array_data = <double *>np.PyArray_DATA(out_array)
# 使用锁,无 GIL 状态下调用随机双精度浮点数填充函数填充数组
with lock, nogil:
random_func(state, n, out_array_data)
# 返回填充后的数组
return out_array
# 定义 C 扩展函数,用于填充单精度浮点数数组
cdef object float_fill(void *func, bitgen_t *state, object size, object lock, object out):
# 将 void 指针转换为单精度浮点数填充函数类型
cdef random_float_fill random_func = (<random_float_fill>func)
# 声明单精度浮点数输出值
cdef float out_val
# 声明单精度浮点数数组数据指针
cdef float *out_array_data
# 声明 NumPy 数组对象
cdef np.ndarray out_array
# 声明 NumPy 中的整数类型和变量
cdef np.npy_intp i, n
# 如果 size 和 out 均为 None
if size is None and out is None:
# 使用锁,调用随机单精度浮点数填充函数,返回填充后的值
with lock:
random_func(state, 1, &out_val)
return out_val
# 如果 out 不为 None
if out is not None:
# 检查输出数组是否符合要求的 np.float32 类型和指定的大小,不要求 C 连续性
check_output(out, np.float32, size, False)
out_array = <np.ndarray>out
else:
# 创建一个指定大小的空单精度浮点数数组
out_array = <np.ndarray>np.empty(size, np.float32)
# 获取输出数组的长度
n = np.PyArray_SIZE(out_array)
# 获取输出数组的数据指针
out_array_data = <float *>np.PyArray_DATA(out_array)
# 使用锁,无 GIL 状态下调用随机单精度浮点数填充函数填充数组
with lock, nogil:
random_func(state, n, out_array_data)
# 返回填充后的数组
return out_array
# 定义 C 扩展函数,从双精度浮点数填充到单精度浮点数数组
cdef object float_fill_from_double(void *func, bitgen_t *state, object size, object lock, object out):
# 将 void 指针转换为双精度浮点数填充函数类型
cdef random_double_0 random_func = (<random_double_0>func)
# 声明单精度浮点数数组数据指针
cdef float *out_array_data
# 声明 NumPy 数组对象
cdef np.ndarray out_array
# 声明 NumPy 中的整数类型和变量
cdef np.npy_intp i, n
# 如果 size 和 out 均为 None
if size is None and out is None:
# 使用锁,调用随机双精度浮点数填充函数,将结果转换为单精度浮点数并返回
with lock:
return <float>random_func(state)
# 如果 out 不为 None
if out is not None:
# 检查输出数组是否符合要求的 np.float32 类型和指定的大小,不要求 C 连续性
check_output(out, np.float32, size, False)
out_array = <np.ndarray>out
else:
# 创建一个指定大小的空单精度浮点数数组
out_array = <np.ndarray>np.empty(size, np.float32)
# 获取输出数组的长度
n = np.PyArray_SIZE(out_array)
# 获取输出数组的数据指针
out_array_data = <float *>np.PyArray_DATA(out_array)
# 使用锁,无 GIL 状态下循环调用随机双精度浮点数填充函数,将结果转换为单精度浮点数填充数组
with lock, nogil:
for i in range(n):
out_array_data[i] = <float>random_func(state)
# 返回填充后的数组
return out_array
# 定义检查数组元素是否在 [0, 1] 范围内的 C 扩展函数
cdef int _check_array_cons_bounded_0_1(np.ndarray val, object name) except -1:
# 声明双精度浮点数数组数据指针
cdef double *val_data
# 声明 NumPy 中的整数类型和变量
cdef np.npy_intp i
# 声明错误标志变量,默认为 False
cdef bint err = 0
# 如果数组非 C 连续或者不是双精度浮点数类型
if not np.PyArray_ISONESEGMENT(val) or np.PyArray_TYPE(val) != np.NPY_DOUBLE:
# 针对非连续数组或任何非双精度类型,采用慢速路径处理
err = not np.all(np.greater_equal(val, 0)) or not np.all(np.less_equal(val, 1))
else:
# 获取双精度浮点数数组的数据指针
val_data = <double *>np.PyArray_DATA(val)
# 遍历数组元素
for i in range(np.PyArray_SIZE(val)):
# 检查每个元素是否在 [0, 1] 范围内
err = (not (val_data[i] >= 0)) or (not val_data[i] <= 1)
if err:
break
# 如果出现错误,则抛出 ValueError 异常
if err:
raise ValueError(f"{name} < 0, {name} > 1 or {name} contains NaNs")
# 返回 0 表示检查成功
return 0
cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1:
# 检查数组约束条件的函数,返回值为整数,异常为-1
if cons == CONS_NON_NEGATIVE:
# 如果约束条件为非负数
if np.any(np.logical_and(np.logical_not(np.isnan(val)), np.signbit(val))):
# 如果数组中存在非NaN且小于0的元素,则抛出数值错误异常
raise ValueError(name + " < 0")
elif cons == CONS_POSITIVE or cons == CONS_POSITIVE_NOT_NAN:
# 如果约束条件为正数或者非NaN的正数
if cons == CONS_POSITIVE_NOT_NAN and np.any(np.isnan(val)):
# 如果约束条件为非NaN的正数且数组中存在NaN元素,则抛出数值错误异常
raise ValueError(name + " must not be NaN")
elif np.any(np.less_equal(val, 0)):
# 如果数组中存在小于等于0的元素,则抛出数值错误异常
raise ValueError(name + " <= 0")
elif cons == CONS_BOUNDED_0_1:
# 如果约束条件为0到1之间
return _check_array_cons_bounded_0_1(val, name)
elif cons == CONS_BOUNDED_GT_0_1:
# 如果约束条件为大于0小于等于1的区间
if not np.all(np.greater(val, 0)) or not np.all(np.less_equal(val, 1)):
# 如果数组中存在不大于0或不小于等于1的元素,则抛出数值错误异常
raise ValueError("{0} <= 0, {0} > 1 or {0} contains NaNs".format(name))
elif cons == CONS_BOUNDED_LT_0_1:
# 如果约束条件为大于等于0小于1的区间
if not np.all(np.greater_equal(val, 0)) or not np.all(np.less(val, 1)):
# 如果数组中存在不大于等于0或不小于1的元素,则抛出数值错误异常
raise ValueError("{0} < 0, {0} >= 1 or {0} contains NaNs".format(name))
elif cons == CONS_GT_1:
# 如果约束条件为大于1
if not np.all(np.greater(val, 1)):
# 如果数组中存在不大于1的元素,则抛出数值错误异常
raise ValueError("{0} <= 1 or {0} contains NaNs".format(name))
elif cons == CONS_GTE_1:
# 如果约束条件为大于等于1
if not np.all(np.greater_equal(val, 1)):
# 如果数组中存在不大于等于1的元素,则抛出数值错误异常
raise ValueError("{0} < 1 or {0} contains NaNs".format(name))
elif cons == CONS_POISSON:
# 如果约束条件为泊松分布
if not np.all(np.less_equal(val, POISSON_LAM_MAX)):
# 如果数组中有超过泊松分布允许值的元素,则抛出数值错误异常
raise ValueError("{0} value too large".format(name))
elif not np.all(np.greater_equal(val, 0.0)):
# 如果数组中有小于0的元素,则抛出数值错误异常
raise ValueError("{0} < 0 or {0} contains NaNs".format(name))
elif cons == LEGACY_CONS_POISSON:
# 如果约束条件为旧版泊松分布
if not np.all(np.less_equal(val, LEGACY_POISSON_LAM_MAX)):
# 如果数组中有超过旧版泊松分布允许值的元素,则抛出数值错误异常
raise ValueError("{0} value too large".format(name))
elif not np.all(np.greater_equal(val, 0.0)):
# 如果数组中有小于0的元素,则抛出数值错误异常
raise ValueError("{0} < 0 or {0} contains NaNs".format(name))
elif cons == LEGACY_CONS_NON_NEGATIVE_INBOUNDS_LONG:
# 如果约束条件为旧版非负数且在长整型范围内
# 注意,这里假设数组元素为整数:
if not np.all(val >= 0):
# 如果数组中有小于0的元素,则抛出数值错误异常
raise ValueError(name + " < 0")
elif not np.all(val <= int(LONG_MAX)):
# 如果数组中有超过长整型范围的元素,则抛出数值错误异常
raise ValueError(
name + " is out of bounds for long, consider using "
"the new generator API for 64bit integers.")
return 0
cdef int check_constraint(double val, object name, constraint_type cons) except -1:
# 检查单个值约束条件的函数,返回值为整数,异常为-1
cdef bint is_nan
if cons == CONS_NON_NEGATIVE:
# 如果约束条件为非负数
if not isnan(val) and signbit(val):
# 如果值不是NaN且小于0,则抛出数值错误异常
raise ValueError(name + " < 0")
elif cons == CONS_POSITIVE or cons == CONS_POSITIVE_NOT_NAN:
# 如果约束条件为正数或者非NaN的正数
if cons == CONS_POSITIVE_NOT_NAN and isnan(val):
# 如果约束条件为非NaN的正数且值为NaN,则抛出数值错误异常
raise ValueError(name + " must not be NaN")
elif val <= 0:
# 如果值小于等于0,则抛出数值错误异常
raise ValueError(name + " <= 0")
elif cons == CONS_BOUNDED_0_1:
# 如果约束条件为0到1之间
if not (val >= 0) or not (val <= 1):
# 如果值小于0或大于1,则抛出数值错误异常
raise ValueError("{0} < 0, {0} > 1 or {0} is NaN".format(name))
# 如果约束条件为 CONS_BOUNDED_GT_0_1
elif cons == CONS_BOUNDED_GT_0_1:
# 检查值是否不大于0或不小于等于1,如果是,则抛出值错误异常
if not val > 0 or not val <= 1:
raise ValueError("{0} <= 0, {0} > 1 or {0} contains NaNs".format(name))
# 如果约束条件为 CONS_BOUNDED_LT_0_1
elif cons == CONS_BOUNDED_LT_0_1:
# 检查值是否不大于等于0或不小于1,如果是,则抛出值错误异常
if not (val >= 0) or not (val < 1):
raise ValueError("{0} < 0, {0} >= 1 or {0} is NaN".format(name))
# 如果约束条件为 CONS_GT_1
elif cons == CONS_GT_1:
# 检查值是否不大于1,如果是,则抛出值错误异常
if not (val > 1):
raise ValueError("{0} <= 1 or {0} is NaN".format(name))
# 如果约束条件为 CONS_GTE_1
elif cons == CONS_GTE_1:
# 检查值是否不大于等于1,如果是,则抛出值错误异常
if not (val >= 1):
raise ValueError("{0} < 1 or {0} is NaN".format(name))
# 如果约束条件为 CONS_POISSON
elif cons == CONS_POISSON:
# 检查值是否不小于0,如果是,则抛出值错误异常
if not (val >= 0):
raise ValueError("{0} < 0 or {0} is NaN".format(name))
# 检查值是否不大于 POISSON_LAM_MAX,如果是,则抛出值错误异常
elif not (val <= POISSON_LAM_MAX):
raise ValueError(name + " value too large")
# 如果约束条件为 LEGACY_CONS_POISSON
elif cons == LEGACY_CONS_POISSON:
# 检查值是否不小于0,如果是,则抛出值错误异常
if not (val >= 0):
raise ValueError("{0} < 0 or {0} is NaN".format(name))
# 检查值是否不大于 LEGACY_POISSON_LAM_MAX,如果是,则抛出值错误异常
elif not (val <= LEGACY_POISSON_LAM_MAX):
raise ValueError(name + " value too large")
# 如果约束条件为 LEGACY_CONS_NON_NEGATIVE_INBOUNDS_LONG
elif cons == LEGACY_CONS_NON_NEGATIVE_INBOUNDS_LONG:
# 注意:假设值是整数(LONG_MAX 的两倍应该可以处理)
# 检查值是否小于0,如果是,则抛出值错误异常
if val < 0:
raise ValueError(name + " < 0")
# 检查值是否大于 LONG_MAX,如果是,则抛出值错误异常
elif val > LONG_MAX:
raise ValueError(
name + " is out of bounds for long, consider using "
"the new generator API for 64bit integers.")
# 如果以上条件都不满足,则返回0
return 0
# 定义一个 Cython 函数,用于执行广播计算,生成一个包含随机数的 NumPy 数组
cdef object cont_broadcast_1(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
object out):
# 声明变量
cdef np.ndarray randoms # 存储生成的随机数的 NumPy 数组
cdef double a_val # 存储从数组 a_arr 中提取的值
cdef double *randoms_data # 用于访问 randoms 的数据指针
cdef np.broadcast it # NumPy 的广播迭代器
cdef random_double_1 f = (<random_double_1>func) # 函数指针,指向随机数生成函数
cdef np.npy_intp i, n # 用于迭代的整数变量
# 检查是否有约束条件,如果有,则检查数组 a_arr 是否符合约束
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 根据 size 参数决定创建 randoms 的方式
if size is not None and out is None:
randoms = <np.ndarray>np.empty(size, np.double)
elif out is None:
randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_DOUBLE)
else:
randoms = <np.ndarray>out
# 获取 randoms 数组的数据指针
randoms_data = <double *>np.PyArray_DATA(randoms)
# 获取 randoms 数组的大小
n = np.PyArray_SIZE(randoms)
# 创建广播迭代器 it,用于同时迭代 randoms 和 a_arr
it = np.PyArray_MultiIterNew2(randoms, a_arr)
# 验证输出形状是否正确
validate_output_shape(it.shape, randoms)
# 使用锁和 nogil 上下文执行并行化的计算
with lock, nogil:
# 遍历 randoms 数组
for i in range(n):
# 从广播迭代器中获取当前 a_arr 中的值
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
# 使用函数指针 f 调用指定的随机数生成函数,将结果存入 randoms 中
randoms_data[i] = f(state, a_val)
# 移动广播迭代器到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回生成的随机数数组
return randoms
# 定义另一个 Cython 函数,用于执行两个数组的广播计算,生成一个包含随机数的 NumPy 数组
cdef object cont_broadcast_2(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint):
# 声明变量
cdef np.ndarray randoms # 存储生成的随机数的 NumPy 数组
cdef double a_val, b_val # 存储从数组 a_arr 和 b_arr 中提取的值
cdef double *randoms_data # 用于访问 randoms 的数据指针
cdef np.broadcast it # NumPy 的广播迭代器
cdef random_double_2 f = (<random_double_2>func) # 函数指针,指向随机数生成函数
cdef np.npy_intp i, n # 用于迭代的整数变量
# 检查约束条件,如果有,则检查数组 a_arr 和 b_arr 是否符合约束
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 根据 size 参数决定创建 randoms 的方式
if size is not None:
randoms = <np.ndarray>np.empty(size, np.double)
else:
it = np.PyArray_MultiIterNew2(a_arr, b_arr)
randoms = <np.ndarray>np.empty(it.shape, np.double)
# 获取 randoms 数组的数据指针
randoms_data = <double *>np.PyArray_DATA(randoms)
# 获取 randoms 数组的大小
n = np.PyArray_SIZE(randoms)
# 创建广播迭代器 it,用于同时迭代 randoms、a_arr 和 b_arr
it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr)
# 验证输出形状是否正确
validate_output_shape(it.shape, randoms)
# 使用锁和 nogil 上下文执行并行化的计算
with lock, nogil:
# 遍历 randoms 数组
for i in range(n):
# 从广播迭代器中获取当前 a_arr 和 b_arr 中的值
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<double*>np.PyArray_MultiIter_DATA(it, 2))[0]
# 使用函数指针 f 调用指定的随机数生成函数,将结果存入 randoms 中
randoms_data[i] = f(state, a_val, b_val)
# 移动广播迭代器到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回生成的随机数数组
return randoms
# 定义另一个 Cython 函数,用于执行三个数组的广播计算,生成一个包含随机数的 NumPy 数组
cdef object cont_broadcast_3(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint,
np.ndarray c_arr, object c_name, constraint_type c_constraint):
# 声明变量
cdef np.ndarray randoms # 存储生成的随机数的 NumPy 数组
cdef double a_val, b_val, c_val # 存储从数组 a_arr、b_arr 和 c_arr 中提取的值
# 声明一个指向 double 类型的指针变量 randoms_data
cdef double *randoms_data
# 声明一个 numpy 广播对象 it
cdef np.broadcast it
# 将 func 强制转换为 random_double_3 类型,并赋值给 f
cdef random_double_3 f = (<random_double_3>func)
# 声明两个 numpy 的整数类型变量 i 和 n
cdef np.npy_intp i, n
# 如果 a_constraint 不等于 CONS_NONE,则调用 check_array_constraint 检查 a_arr
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 如果 b_constraint 不等于 CONS_NONE,则调用 check_array_constraint 检查 b_arr
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 如果 c_constraint 不等于 CONS_NONE,则调用 check_array_constraint 检查 c_arr
if c_constraint != CONS_NONE:
check_array_constraint(c_arr, c_name, c_constraint)
# 如果 size 不为 None,则创建一个大小为 size 的新的 double 类型的 numpy 数组 randoms
# 否则,使用 np.PyArray_MultiIterNew3 创建一个多迭代器 it,并使用其形状创建 randoms
if size is not None:
randoms = <np.ndarray>np.empty(size, np.double)
else:
it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr)
randoms = <np.ndarray>np.empty(it.shape, np.double)
# 将 randoms 的数据指针赋值给 randoms_data
randoms_data = <double *>np.PyArray_DATA(randoms)
# 获取 randoms 数组的大小,并赋值给 n
n = np.PyArray_SIZE(randoms)
# 使用 np.PyArray_MultiIterNew4 创建一个四维的多迭代器 it,验证其形状与 randoms 是否一致
it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr)
validate_output_shape(it.shape, randoms)
# 使用 lock 和 nogil 上下文,遍历 randoms 的元素个数 n
with lock, nogil:
for i in range(n):
# 分别获取多迭代器 it 中第 1、2、3 个数组的当前元素,并强制转换为 double 指针类型,获取其值
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<double*>np.PyArray_MultiIter_DATA(it, 2))[0]
c_val = (<double*>np.PyArray_MultiIter_DATA(it, 3))[0]
# 调用函数 f,将 state、a_val、b_val、c_val 作为参数,将结果赋值给 randoms_data 的当前索引 i 处
randoms_data[i] = f(state, a_val, b_val, c_val)
# 更新多迭代器 it,使其指向下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回生成的随机数数组 randoms
return randoms
# 定义 C 扩展函数 cont,接收多个参数和约束条件,返回一个对象
cdef object cont(void *func, void *state, object size, object lock, int narg,
object a, object a_name, constraint_type a_constraint,
object b, object b_name, constraint_type b_constraint,
object c, object c_name, constraint_type c_constraint,
object out):
# 定义用于存储参数的 numpy 数组变量
cdef np.ndarray a_arr, b_arr, c_arr
# 定义用于存储参数的 double 类型变量
cdef double _a = 0.0, _b = 0.0, _c = 0.0
# 布尔型变量,表示是否是标量值
cdef bint is_scalar = True
# 检查输出参数的类型和大小,要求是 np.float64 类型
check_output(out, np.float64, size, narg > 0)
# 如果有第一个参数
if narg > 0:
# 将参数 a 转换为 np.ndarray 类型
a_arr = <np.ndarray>np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED)
# 判断是否为标量
is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0
# 如果有第二个参数
if narg > 1:
# 将参数 b 转换为 np.ndarray 类型
b_arr = <np.ndarray>np.PyArray_FROM_OTF(b, np.NPY_DOUBLE, np.NPY_ALIGNED)
# 判断是否为标量
is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0
# 如果有第三个参数
if narg == 3:
# 将参数 c 转换为 np.ndarray 类型
c_arr = <np.ndarray>np.PyArray_FROM_OTF(c, np.NPY_DOUBLE, np.NPY_ALIGNED)
# 判断是否为标量
is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0
# 如果不是标量值
if not is_scalar:
# 根据参数个数调用不同的广播函数
if narg == 1:
return cont_broadcast_1(func, state, size, lock,
a_arr, a_name, a_constraint,
out)
elif narg == 2:
return cont_broadcast_2(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint)
else:
return cont_broadcast_3(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint,
c_arr, c_name, c_constraint)
# 如果参数是标量值
if narg > 0:
# 将参数 a 转换为 double 类型
_a = PyFloat_AsDouble(a)
# 如果有约束条件且是标量,则检查约束
if a_constraint != CONS_NONE and is_scalar:
check_constraint(_a, a_name, a_constraint)
# 如果有第二个参数
if narg > 1:
# 将参数 b 转换为 double 类型
_b = PyFloat_AsDouble(b)
# 如果有约束条件,则检查约束
if b_constraint != CONS_NONE:
check_constraint(_b, b_name, b_constraint)
# 如果有第三个参数
if narg == 3:
# 将参数 c 转换为 double 类型
_c = PyFloat_AsDouble(c)
# 如果有约束条件且是标量,则检查约束
if c_constraint != CONS_NONE and is_scalar:
check_constraint(_c, c_name, c_constraint)
# 如果 size 和 out 都为空
if size is None and out is None:
# 在锁的作用域内执行以下逻辑
with lock:
# 根据参数个数调用不同的随机数生成函数
if narg == 0:
return (<random_double_0>func)(state)
elif narg == 1:
return (<random_double_1>func)(state, _a)
elif narg == 2:
return (<random_double_2>func)(state, _a, _b)
elif narg == 3:
return (<random_double_3>func)(state, _a, _b, _c)
# 定义循环变量和数组大小变量
cdef np.npy_intp i, n
# 定义存储随机数的 numpy 数组变量
cdef np.ndarray randoms
# 如果输出参数为空
if out is None:
# 创建一个指定大小的空数组用于存储随机数
randoms = <np.ndarray>np.empty(size)
else:
# 否则使用传入的输出参数
randoms = <np.ndarray>out
# 获取随机数数组的大小
n = np.PyArray_SIZE(randoms)
# 获取随机数数组的数据指针
cdef double *randoms_data = <double *>np.PyArray_DATA(randoms)
# 定义用于存储随机数生成函数的变量
cdef random_double_0 f0
cdef random_double_1 f1
cdef random_double_2 f2
cdef random_double_3 f3
# 使用给定的锁和无全局解锁(no gil)的上下文执行以下代码块
with lock, nogil:
# 如果参数个数为0,则使用第一个随机函数处理数据
if narg == 0:
# 获取第一个随机函数对象并调用它生成随机数序列
f0 = (<random_double_0>func)
# 循环生成n个随机数并存储到randoms_data数组中
for i in range(n):
randoms_data[i] = f0(state)
# 如果参数个数为1,则使用第二个随机函数处理数据
elif narg == 1:
# 获取第二个随机函数对象并调用它生成随机数序列
f1 = (<random_double_1>func)
# 循环生成n个随机数并存储到randoms_data数组中
for i in range(n):
randoms_data[i] = f1(state, _a)
# 如果参数个数为2,则使用第三个随机函数处理数据
elif narg == 2:
# 获取第三个随机函数对象并调用它生成随机数序列
f2 = (<random_double_2>func)
# 循环生成n个随机数并存储到randoms_data数组中
for i in range(n):
randoms_data[i] = f2(state, _a, _b)
# 如果参数个数为3,则使用第四个随机函数处理数据
elif narg == 3:
# 获取第四个随机函数对象并调用它生成随机数序列
f3 = (<random_double_3>func)
# 循环生成n个随机数并存储到randoms_data数组中
for i in range(n):
randoms_data[i] = f3(state, _a, _b, _c)
# 如果未提供输出对象,则返回生成的随机数数组
if out is None:
return randoms
# 否则返回指定的输出对象
else:
return out
# 定义 C 函数,用于离散广播操作,接受函数指针、状态指针、大小、锁、数组 a_arr、数组名称 a_name、约束类型 a_constraint 作为参数
cdef object discrete_broadcast_d(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint):
# 声明变量
cdef np.ndarray randoms # 存储随机数的数组
cdef int64_t *randoms_data # 指向随机数数组数据的指针
cdef np.broadcast it # 广播迭代器
cdef random_uint_d f = (<random_uint_d>func) # 转换函数指针类型为 random_uint_d
# 如果存在约束条件,检查数组 a_arr 是否符合约束
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 如果指定了大小,创建指定大小的空数组 randoms
if size is not None:
randoms = np.empty(size, np.int64)
else:
# 否则,使用 a_arr 的形状创建空数组 randoms
randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_INT64)
# 获取 randoms 数组的数据指针和大小
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建包含 randoms 和 a_arr 的多重迭代器 it,并验证输出形状
it = np.PyArray_MultiIterNew2(randoms, a_arr)
validate_output_shape(it.shape, randoms)
# 使用锁和 nogil 上下文执行并发操作
with lock, nogil:
for i in range(n):
# 获取 a_arr 中的当前值 a_val
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
# 使用函数指针 f 处理 state 和 a_val,将结果存入 randoms_data[i]
randoms_data[i] = f(state, a_val)
# 将迭代器 it 推进到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回随机数数组 randoms
return randoms
# 定义 C 函数,用于双数组离散广播操作,接受函数指针、状态指针、大小、锁、数组 a_arr、数组名称 a_name、约束类型 a_constraint、数组 b_arr、数组名称 b_name、约束类型 b_constraint 作为参数
cdef object discrete_broadcast_dd(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint):
# 声明变量
cdef np.ndarray randoms # 存储随机数的数组
cdef int64_t *randoms_data # 指向随机数数组数据的指针
cdef np.broadcast it # 广播迭代器
cdef random_uint_dd f = (<random_uint_dd>func) # 转换函数指针类型为 random_uint_dd
# 如果存在约束条件,检查数组 a_arr 和 b_arr 是否符合约束
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 如果指定了大小,创建指定大小的空数组 randoms
if size is not None:
randoms = <np.ndarray>np.empty(size, np.int64)
else:
# 否则,使用 a_arr 和 b_arr 的形状创建空数组 randoms
it = np.PyArray_MultiIterNew2(a_arr, b_arr)
randoms = <np.ndarray>np.empty(it.shape, np.int64)
# randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_INT64)
# 获取 randoms 数组的数据指针和大小
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建包含 randoms、a_arr 和 b_arr 的多重迭代器 it,并验证输出形状
it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr)
validate_output_shape(it.shape, randoms)
# 使用锁和 nogil 上下文执行并发操作
with lock, nogil:
for i in range(n):
# 获取 a_arr 和 b_arr 中的当前值 a_val 和 b_val
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<double*>np.PyArray_MultiIter_DATA(it, 2))[0]
# 使用函数指针 f 处理 state、a_val 和 b_val,将结果存入 randoms_data[i]
randoms_data[i] = f(state, a_val, b_val)
# 将迭代器 it 推进到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回随机数数组 randoms
return randoms
# 定义 C 函数,用于数组与整数离散广播操作,接受函数指针、状态指针、大小、锁、数组 a_arr、数组名称 a_name、约束类型 a_constraint、数组 b_arr、数组名称 b_name、约束类型 b_constraint 作为参数
cdef object discrete_broadcast_di(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint):
# 声明变量
cdef np.ndarray randoms # 存储随机数的数组
cdef int64_t *randoms_data # 指向随机数数组数据的指针
cdef np.broadcast it # 广播迭代器
cdef random_uint_di f = (<random_uint_di>func) # 转换函数指针类型为 random_uint_di
# 如果存在约束条件,检查数组 a_arr 和 b_arr 是否符合约束
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 如果指定了大小,创建指定大小的空数组 randoms
if size is not None:
randoms = np.empty(size, np.int64)
else:
# 否则,使用 a_arr 和 b_arr 的形状创建空数组 randoms
it = np.PyArray_MultiIterNew2(a_arr, b_arr)
randoms = <np.ndarray>np.empty(it.shape, np.int64)
# randoms = np.PyArray_SimpleNew(it.nd, np.PyArray_DIMS(it), np.NPY_INT64)
# 获取 randoms 数组的数据指针和大小
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建包含 randoms、a_arr 和 b_arr 的多重迭代器 it,并验证输出形状
it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr)
validate_output_shape(it.shape, randoms)
# 使用锁和 nogil 上下文执行并发操作
with lock, nogil:
for i in range(n):
# 获取 a_arr 和 b_arr 中的当前值 a_val 和 b_val
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<double*>np.PyArray_MultiIter_DATA(it, 2))[0]
# 使用函数指针 f 处理 state、a_val 和 b_val,将结果存入 randoms_data[i]
randoms_data[i] = f(state, a_val, b_val)
# 将迭代器 it 推进到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回随机数数组 randoms
return randoms
# 如果给定的 a_constraint 不是 CONS_NONE,则检查数组 a_arr 是否符合约束条件,并报告可能的问题
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 如果给定的 b_constraint 不是 CONS_NONE,则检查数组 b_arr 是否符合约束条件,并报告可能的问题
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 如果 size 不是 None,则创建一个指定大小的空的 int64 类型的 numpy 数组 randoms
# 否则,使用 a_arr 和 b_arr 的形状创建一个空的 int64 类型的 numpy 数组 randoms
if size is not None:
randoms = <np.ndarray>np.empty(size, np.int64)
else:
it = np.PyArray_MultiIterNew2(a_arr, b_arr)
randoms = <np.ndarray>np.empty(it.shape, np.int64)
# 获取 randoms 数组的数据指针,以 int64_t* 的形式存储在 randoms_data 中
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
# 获取 randoms 数组的大小
n = np.PyArray_SIZE(randoms)
# 创建一个三数组迭代器,包括 randoms, a_arr, b_arr,并验证其形状是否一致
it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr)
validate_output_shape(it.shape, randoms)
# 使用 lock 和 nogil 保护的上下文,迭代处理 randoms 数组中的每个元素
with lock, nogil:
for i in range(n):
# 获取迭代器 it 中第二个数组 (a_arr) 当前元素的值,以 double* 形式存储在 a_val 中
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
# 获取迭代器 it 中第三个数组 (b_arr) 当前元素的值,以 int64_t* 形式存储在 b_val 中
b_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 2))[0]
# 将调用 f(state, a_val, b_val) 的结果存储在 randoms 数组中当前元素的位置
(<int64_t*>np.PyArray_MultiIter_DATA(it, 0))[0] = f(state, a_val, b_val)
# 将迭代器 it 向前移动到下一个元素
np.PyArray_MultiIter_NEXT(it)
# 返回填充后的 randoms 数组
return randoms
cdef object discrete_broadcast_iii(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
np.ndarray b_arr, object b_name, constraint_type b_constraint,
np.ndarray c_arr, object c_name, constraint_type c_constraint):
# 声明变量
cdef np.ndarray randoms
cdef int64_t *randoms_data
cdef np.broadcast it
cdef random_uint_iii f = (<random_uint_iii>func)
cdef np.npy_intp i, n
# 如果数组a有约束条件,则检查其约束条件
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 如果数组b有约束条件,则检查其约束条件
if b_constraint != CONS_NONE:
check_array_constraint(b_arr, b_name, b_constraint)
# 如果数组c有约束条件,则检查其约束条件
if c_constraint != CONS_NONE:
check_array_constraint(c_arr, c_name, c_constraint)
# 如果size不为None,则创建指定大小的空数组randoms
if size is not None:
randoms = <np.ndarray>np.empty(size, np.int64)
else:
# 否则,创建一个与a_arr、b_arr、c_arr广播形状相同的空数组randoms
it = np.PyArray_MultiIterNew3(a_arr, b_arr, c_arr)
randoms = <np.ndarray>np.empty(it.shape, np.int64)
# 获取randoms数组的数据指针和大小
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建一个四元素多迭代器,包括randoms、a_arr、b_arr、c_arr,并验证其形状
it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr)
validate_output_shape(it.shape, randoms)
# 使用lock和nogil上下文,遍历randoms数组
with lock, nogil:
for i in range(n):
# 获取当前迭代器位置处的a_arr、b_arr、c_arr的值,并调用函数f计算randoms_data[i]
a_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 2))[0]
c_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 3))[0]
randoms_data[i] = f(state, a_val, b_val, c_val)
# 将迭代器移动到下一个位置
np.PyArray_MultiIter_NEXT(it)
# 返回计算得到的randoms数组
return randoms
cdef object discrete_broadcast_i(void *func, void *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint):
# 声明变量
cdef np.ndarray randoms
cdef int64_t *randoms_data
cdef np.broadcast it
cdef random_uint_i f = (<random_uint_i>func)
cdef np.npy_intp i, n
# 如果数组a有约束条件,则检查其约束条件
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 如果size不为None,则创建指定大小的空数组randoms
if size is not None:
randoms = <np.ndarray>np.empty(size, np.int64)
else:
# 否则,创建一个与a_arr广播形状相同的空数组randoms
randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_INT64)
# 获取randoms数组的数据指针和大小
randoms_data = <int64_t *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建一个二元素多迭代器,包括randoms和a_arr,并验证其形状
it = np.PyArray_MultiIterNew2(randoms, a_arr)
validate_output_shape(it.shape, randoms)
# 使用lock和nogil上下文,遍历randoms数组
with lock, nogil:
for i in range(n):
# 获取当前迭代器位置处的a_arr的值,并调用函数f计算randoms_data[i]
a_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 1))[0]
randoms_data[i] = f(state, a_val)
# 将迭代器移动到下一个位置
np.PyArray_MultiIter_NEXT(it)
# 返回计算得到的randoms数组
return randoms
cdef object disc(void *func, void *state, object size, object lock,
int narg_double, int narg_int64,
object a, object a_name, constraint_type a_constraint,
object b, object b_name, constraint_type b_constraint,
object c, object c_name, constraint_type c_constraint):
cdef double _da = 0, _db = 0
cdef int64_t _ia = 0, _ib = 0, _ic = 0
cdef bint is_scalar = True
# 检查是否需要处理浮点数参数
if narg_double > 0:
# 从对象 `a` 中创建双精度浮点数的 NumPy 数组
a_arr = <np.ndarray>np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED)
# 检查是否是标量(0维度)
is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0
if narg_double > 1:
# 从对象 `b` 中创建双精度浮点数的 NumPy 数组
b_arr = <np.ndarray>np.PyArray_FROM_OTF(b, np.NPY_DOUBLE, np.NPY_ALIGNED)
# 继续检查是否是标量
is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0
elif narg_int64 == 1:
# 否则,从对象 `b` 中创建64位整数的 NumPy 数组
b_arr = <np.ndarray>np.PyArray_FROM_OTF(b, np.NPY_INT64, np.NPY_ALIGNED)
# 再次检查是否是标量
is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0
else:
# 处理整数参数的情况
if narg_int64 > 0:
# 从对象 `a` 中创建64位整数的 NumPy 数组
a_arr = <np.ndarray>np.PyArray_FROM_OTF(a, np.NPY_INT64, np.NPY_ALIGNED)
# 检查是否是标量
is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0
if narg_int64 > 1:
# 从对象 `b` 中创建64位整数的 NumPy 数组
b_arr = <np.ndarray>np.PyArray_FROM_OTF(b, np.NPY_INT64, np.NPY_ALIGNED)
# 继续检查是否是标量
is_scalar = is_scalar and np.PyArray_NDIM(b_arr) == 0
if narg_int64 > 2:
# 从对象 `c` 中创建64位整数的 NumPy 数组
c_arr = <np.ndarray>np.PyArray_FROM_OTF(c, np.NPY_INT64, np.NPY_ALIGNED)
# 继续检查是否是标量
is_scalar = is_scalar and np.PyArray_NDIM(c_arr) == 0
# 如果参数不是标量,则执行相应的广播调用
if not is_scalar:
if narg_int64 == 0:
if narg_double == 1:
# 调用专门处理双精度浮点数广播的函数
return discrete_broadcast_d(func, state, size, lock,
a_arr, a_name, a_constraint)
elif narg_double == 2:
# 调用专门处理双精度浮点数广播的函数
return discrete_broadcast_dd(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint)
elif narg_int64 == 1:
if narg_double == 0:
# 调用专门处理64位整数广播的函数
return discrete_broadcast_i(func, state, size, lock,
a_arr, a_name, a_constraint)
elif narg_double == 1:
# 调用专门处理混合参数(浮点数和整数)广播的函数
return discrete_broadcast_di(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint)
else:
# 如果没有相应的向量化路径,则抛出未实现错误
raise NotImplementedError("No vector path available")
# 如果参数 narg_double 大于 0
if narg_double > 0:
# 将变量 a 转换为双精度浮点数 _da
_da = PyFloat_AsDouble(a)
# 如果 a 的约束条件不是 CONS_NONE 并且是标量
if a_constraint != CONS_NONE and is_scalar:
# 检查约束条件
check_constraint(_da, a_name, a_constraint)
# 如果参数个数大于 1
if narg_double > 1:
# 将变量 b 转换为双精度浮点数 _db
_db = PyFloat_AsDouble(b)
# 如果 b 的约束条件不是 CONS_NONE 并且是标量
if b_constraint != CONS_NONE and is_scalar:
# 检查约束条件
check_constraint(_db, b_name, b_constraint)
# 如果参数个数为 1 且为整型
elif narg_int64 == 1:
# 将变量 b 强制转换为 int64_t 类型并赋值给 _ib
_ib = <int64_t>b
# 如果 b 的约束条件不是 CONS_NONE 并且是标量
if b_constraint != CONS_NONE and is_scalar:
# 将 _ib 转换为双精度浮点数后检查约束条件
check_constraint(<double>_ib, b_name, b_constraint)
# 如果参数 narg_double 等于 0
else:
# 如果参数个数大于 0 且为整型
if narg_int64 > 0:
# 将变量 a 强制转换为 int64_t 类型并赋值给 _ia
_ia = <int64_t>a
# 如果 a 的约束条件不是 CONS_NONE 并且是标量
if a_constraint != CONS_NONE and is_scalar:
# 将 _ia 转换为双精度浮点数后检查约束条件
check_constraint(<double>_ia, a_name, a_constraint)
# 如果参数个数大于 1 且为整型
if narg_int64 > 1:
# 将变量 b 强制转换为 int64_t 类型并赋值给 _ib
_ib = <int64_t>b
# 如果 b 的约束条件不是 CONS_NONE 并且是标量
if b_constraint != CONS_NONE and is_scalar:
# 将 _ib 转换为双精度浮点数后检查约束条件
check_constraint(<double>_ib, b_name, b_constraint)
# 如果参数个数大于 2 且为整型
if narg_int64 > 2:
# 将变量 c 强制转换为 int64_t 类型并赋值给 _ic
_ic = <int64_t>c
# 如果 c 的约束条件不是 CONS_NONE 并且是标量
if c_constraint != CONS_NONE and is_scalar:
# 将 _ic 转换为双精度浮点数后检查约束条件
check_constraint(<double>_ic, c_name, c_constraint)
# 如果 size 为 None
if size is None:
# 在锁的保护下
with lock:
# 如果整型参数个数为 0
if narg_int64 == 0:
# 返回使用状态 state 调用 <random_uint_0>func 的结果
return (<random_uint_0>func)(state)
# 如果整型参数个数为 1
elif narg_int64 == 1:
# 如果双精度浮点数参数个数为 0
if narg_double == 0:
# 返回使用状态 state 和 _ia 调用 <random_uint_i>func 的结果
return (<random_uint_i>func)(state, _ia)
# 如果双精度浮点数参数个数为 1
elif narg_double == 1:
# 返回使用状态 state、_da 和 _ib 调用 <random_uint_di>func 的结果
return (<random_uint_di>func)(state, _da, _ib)
# 如果双精度浮点数参数个数为 2
elif narg_double == 2:
# 返回使用状态 state、_da 和 _db 调用 <random_uint_dd>func 的结果
return (<random_uint_dd>func)(state, _da, _db)
# 如果整型参数个数大于 1
else:
# 返回使用状态 state、_ia、_ib 和 _ic 调用 <random_uint_iii>func 的结果
return (<random_uint_iii>func)(state, _ia, _ib, _ic)
# 声明 np.npy_intp 类型的 i 和 n 变量
cdef np.npy_intp i, n
# 声明一个形状为 size、数据类型为 np.int64 的 numpy 数组 randoms
cdef np.ndarray randoms = <np.ndarray>np.empty(size, np.int64)
# 声明一个指向 randoms 数据的指针 randoms_data
cdef np.int64_t *randoms_data
# 声明 random_uint_0 到 random_uint_iii 的函数指针变量
cdef random_uint_0 f0
cdef random_uint_d fd
cdef random_uint_dd fdd
cdef random_uint_di fdi
cdef random_uint_i fi
cdef random_uint_iii fiii
# 获取 randoms 数组的大小
n = np.PyArray_SIZE(randoms)
# 获取 randoms 数组的数据指针
randoms_data = <np.int64_t *>np.PyArray_DATA(randoms)
# 使用 lock 和 nogil 上下文来确保并发安全性
with lock, nogil:
# 根据参数数量选择合适的随机函数进行初始化
if narg_int64 == 0:
if narg_double == 0:
# 初始化使用无浮点参数的随机函数
f0 = (<random_uint_0>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = f0(state)
elif narg_double == 1:
# 初始化使用一个浮点参数的随机函数
fd = (<random_uint_d>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = fd(state, _da)
elif narg_double == 2:
# 初始化使用两个浮点参数的随机函数
fdd = (<random_uint_dd>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = fdd(state, _da, _db)
elif narg_int64 == 1:
if narg_double == 0:
# 初始化使用一个整数参数的随机函数
fi = (<random_uint_i>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = fi(state, _ia)
if narg_double == 1:
# 初始化使用一个整数和一个浮点参数的随机函数
fdi = (<random_uint_di>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = fdi(state, _da, _ib)
else:
# 初始化使用三个整数参数的随机函数
fiii = (<random_uint_iii>func)
# 对于指定数量的数据点,生成随机数并存储到数组中
for i in range(n):
randoms_data[i] = fiii(state, _ia, _ib, _ic)
# 返回生成的随机数数组
return randoms
# 定义一个Cython函数,用于处理连续型随机变量的抽样操作
cdef object cont_broadcast_1_f(void *func, bitgen_t *state, object size, object lock,
np.ndarray a_arr, object a_name, constraint_type a_constraint,
object out):
# 声明变量
cdef np.ndarray randoms # 存储随机数结果的NumPy数组
cdef float a_val # 存储单个随机数值的变量
cdef float *randoms_data # 指向随机数数组数据的指针
cdef np.broadcast it # 广播对象,用于迭代处理数组
cdef random_float_1 f = (<random_float_1>func) # 强制类型转换为特定的随机数生成函数
cdef np.npy_intp i, n # 用于迭代的整数变量
# 检查是否存在约束条件,并根据约束条件检查数组
if a_constraint != CONS_NONE:
check_array_constraint(a_arr, a_name, a_constraint)
# 根据不同情况初始化随机数数组
if size is not None and out is None:
randoms = <np.ndarray>np.empty(size, np.float32)
elif out is None:
randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr),
np.PyArray_DIMS(a_arr),
np.NPY_FLOAT32)
else:
randoms = <np.ndarray>out
# 获取随机数数组的数据指针及其大小
randoms_data = <float *>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)
# 创建一个多迭代器对象,用于同时迭代两个数组
it = np.PyArray_MultiIterNew2(randoms, a_arr)
# 验证输出形状是否符合预期
validate_output_shape(it.shape, randoms)
# 使用锁和无GIL状态,迭代处理数组元素
with lock, nogil:
for i in range(n):
# 获取当前迭代位置的数组元素值,并调用指定的随机数生成函数进行处理
a_val = (<float*>np.PyArray_MultiIter_DATA(it, 1))[0]
randoms_data[i] = f(state, a_val)
# 移动到迭代器的下一个元素位置
np.PyArray_MultiIter_NEXT(it)
# 返回生成的随机数数组
return randoms
# 定义另一个Cython函数,用于处理单个随机变量的抽样操作
cdef object cont_f(void *func, bitgen_t *state, object size, object lock,
object a, object a_name, constraint_type a_constraint,
object out):
# 声明变量
cdef np.ndarray a_arr, b_arr, c_arr # 输入参数的NumPy数组
cdef float _a # 存储单个浮点数值的变量
cdef bint is_scalar = True # 标志变量,指示是否为标量
cdef int requirements = np.NPY_ALIGNED | np.NPY_FORCECAST # 数组要求标志
check_output(out, np.float32, size, True) # 检查输出数组是否符合预期的要求
a_arr = <np.ndarray>np.PyArray_FROMANY(a, np.NPY_FLOAT32, 0, 0, requirements) # 将输入参数a转换为NumPy数组
is_scalar = np.PyArray_NDIM(a_arr) == 0 # 检查a_arr是否为标量
# 如果a_arr不是标量,则调用cont_broadcast_1_f处理
if not is_scalar:
return cont_broadcast_1_f(func, state, size, lock, a_arr, a_name, a_constraint, out)
# 将a转换为浮点数,并根据约束条件检查其值
_a = <float>PyFloat_AsDouble(a)
if a_constraint != CONS_NONE:
check_constraint(_a, a_name, a_constraint)
# 根据size和out的情况初始化随机数数组
if size is None and out is None:
with lock:
return (<random_float_1>func)(state, _a)
cdef np.npy_intp i, n # 迭代器变量
cdef np.ndarray randoms # 存储随机数结果的NumPy数组
# 根据out的情况初始化随机数数组
if out is None:
randoms = <np.ndarray>np.empty(size, np.float32)
else:
randoms = <np.ndarray>out
n = np.PyArray_SIZE(randoms) # 获取随机数数组的大小
cdef float *randoms_data = <float *>np.PyArray_DATA(randoms) # 获取随机数数组的数据指针
cdef random_float_1 f1 = <random_float_1>func # 强制类型转换为特定的随机数生成函数
# 使用锁和无GIL状态,迭代处理数组元素
with lock, nogil:
for i in range(n):
randoms_data[i] = f1(state, _a)
# 根据out的情况返回结果数组
if out is None:
return randoms
else:
return out
.\numpy\numpy\random\_examples\cffi\extending.py
"""
Use cffi to access any of the underlying C functions from distributions.h
"""
# 导入必要的库
import os # 用于操作系统相关功能的标准库
import numpy as np # 导入NumPy库,用于科学计算
import cffi # 导入cffi库,用于调用C语言函数接口
from .parse import parse_distributions_h # 导入自定义函数parse_distributions_h,用于解析distributions.h文件
ffi = cffi.FFI() # 创建一个FFI对象
# 获取NumPy的头文件所在目录
inc_dir = os.path.join(np.get_include(), 'numpy')
# 定义基本的NumPy类型
ffi.cdef('''
typedef intptr_t npy_intp;
typedef unsigned char npy_bool;
''')
# 调用自定义函数,解析distributions.h文件并注册C函数到FFI对象
parse_distributions_h(ffi, inc_dir)
# 使用FFI对象加载NumPy随机模块中的C函数库
lib = ffi.dlopen(np.random._generator.__file__)
# 比较distributions.h中的random_standard_normal_fill函数与Generator.standard_random函数
bit_gen = np.random.PCG64() # 创建PCG64位生成器实例
rng = np.random.Generator(bit_gen) # 创建随机数生成器实例
state = bit_gen.state # 获取生成器当前状态
interface = rng.bit_generator.cffi # 获取随机数生成器的CFFI接口
n = 100 # 设定生成随机数的数量
# 创建一个C类型的double数组,用于存储从C函数中获取的随机数
vals_cffi = ffi.new('double[%d]' % n)
# 调用C函数库中的random_standard_normal_fill函数,生成随机数填充到vals_cffi数组中
lib.random_standard_normal_fill(interface.bit_generator, n, vals_cffi)
# 重置生成器状态
bit_gen.state = state
# 使用Python接口生成相同数量的标准正态分布随机数
vals = rng.standard_normal(n)
# 对比两种方法生成的随机数是否相等
for i in range(n):
assert vals[i] == vals_cffi[i]
.\numpy\numpy\random\_examples\cffi\parse.py
# 导入os模块,用于处理文件路径等操作
import os
# 定义函数parse_distributions_h,接受两个参数ffi和inc_dir
def parse_distributions_h(ffi, inc_dir):
"""
Parse distributions.h located in inc_dir for CFFI, filling in the ffi.cdef
Read the function declarations without the "#define ..." macros that will
be filled in when loading the library.
"""
# 打开random/bitgen.h文件进行读取,并初始化空列表s
with open(os.path.join(inc_dir, 'random', 'bitgen.h')) as fid:
s = []
# 逐行处理文件内容
for line in fid:
# 如果行以'#'开头,则跳过该行(处理注释或预处理指令)
if line.strip().startswith('#'):
continue
# 将不以'#'开头的行加入列表s
s.append(line)
# 将列表s中的内容作为字符串连接起来,传递给ffi.cdef以定义接口
ffi.cdef('\n'.join(s))
# 打开random/distributions.h文件进行读取,并初始化空列表s,以及标记变量和忽略状态
with open(os.path.join(inc_dir, 'random', 'distributions.h')) as fid:
s = []
in_skip = 0
ignoring = False
# 逐行处理文件内容
for line in fid:
# 如果当前处于忽略状态,遇到'#endif'则结束忽略状态
if ignoring:
if line.strip().startswith('#endif'):
ignoring = False
continue
# 如果遇到'#ifdef __cplusplus',则进入忽略状态
if line.strip().startswith('#ifdef __cplusplus'):
ignoring = True
# 如果行以'#'开头,则跳过该行(处理注释或预处理指令)
if line.strip().startswith('#'):
continue
# 如果行以'static inline'开头,表示可能是内联函数定义,需要跳过
if line.strip().startswith('static inline'):
in_skip += line.count('{') # 统计行内'{'的个数,增加忽略深度
continue
elif in_skip > 0:
in_skip += line.count('{') # 继续统计行内'{'的个数
in_skip -= line.count('}') # 减少统计行内'}'的个数,直到忽略深度为0
continue
# 替换行内的宏定义,如将'DECLDIR'替换为空字符串,将'RAND_INT_TYPE'替换为'int64_t'
line = line.replace('DECLDIR', '')
line = line.replace('RAND_INT_TYPE', 'int64_t')
# 将处理后的行加入列表s
s.append(line)
# 将列表s中的内容作为字符串连接起来,传递给ffi.cdef以定义接口
ffi.cdef('\n'.join(s))
.\numpy\numpy\random\_examples\cython\extending.pyx
# 使用 Python3 解释器执行该脚本
#!/usr/bin/env python3
# 设定 Cython 语言级别为 3
#cython: language_level=3
# 从 libc 库中导入 uint32_t 类型
from libc.stdint cimport uint32_t
# 从 cpython.pycapsule 库中导入 PyCapsule_IsValid 和 PyCapsule_GetPointer 函数
from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer
# 导入 NumPy 库,并声明导入的类型和函数
import numpy as np
cimport numpy as np
cimport cython
# 从 numpy.random 库中导入 bitgen_t 类型
from numpy.random cimport bitgen_t
# 导入 PCG64 类型
from numpy.random import PCG64
# 初始化 NumPy 数组支持
np.import_array()
# 使用 Cython 的装饰器声明边界检查关闭和数组溢出检查关闭的函数
@cython.boundscheck(False)
@cython.wraparound(False)
# 定义 uniform_mean 函数,接受一个 Py_ssize_t 类型的参数 n
def uniform_mean(Py_ssize_t n):
# 声明变量 i 和 rng
cdef Py_ssize_t i
cdef bitgen_t *rng
# 声明并初始化字符串常量 capsule_name
cdef const char *capsule_name = "BitGenerator"
# 声明并初始化 double 类型的一维数组 random_values
cdef double[::1] random_values
# 声明 NumPy 的 ndarray 对象 randoms
cdef np.ndarray randoms
# 创建 PCG64 对象 x
x = PCG64()
# 获取 PCG64 对象的胶囊(capsule)
capsule = x.capsule
# 检查胶囊的有效性
if not PyCapsule_IsValid(capsule, capsule_name):
raise ValueError("Invalid pointer to anon_func_state")
# 获取胶囊中的指针,转换为 bitgen_t 指针类型赋值给 rng
rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name)
# 初始化 random_values 数组为长度 n 的空数组
random_values = np.empty(n)
# 使用 with 语句获取锁并释放 GIL,以便多线程安全生成随机数
with x.lock, nogil:
# 循环生成 n 个随机数,并存储到 random_values 数组中
for i in range(n):
random_values[i] = rng.next_double(rng.state)
# 将 random_values 转换为 NumPy ndarray 对象
randoms = np.asarray(random_values)
# 返回随机数的平均值
return randoms.mean()
# 声明 cdef 函数 bounded_uint,接受 lb, ub, rng 三个参数,并声明为 nogil 函数
cdef uint32_t bounded_uint(uint32_t lb, uint32_t ub, bitgen_t *rng) nogil:
# 声明变量 mask, delta, val,并初始化 mask 为 ub - lb
cdef uint32_t mask, delta, val
mask = delta = ub - lb
# 计算 mask 的位掩码
mask |= mask >> 1
mask |= mask >> 2
mask |= mask >> 4
mask |= mask >> 8
mask |= mask >> 16
# 生成一个在指定范围内的随机数并返回
val = rng.next_uint32(rng.state) & mask
while val > delta:
val = rng.next_uint32(rng.state) & mask
return lb + val
# 使用 Cython 的装饰器声明边界检查关闭和数组溢出检查关闭的函数
@cython.boundscheck(False)
@cython.wraparound(False)
# 定义 bounded_uints 函数,接受 lb, ub 和 Py_ssize_t 类型的参数 n
def bounded_uints(uint32_t lb, uint32_t ub, Py_ssize_t n):
# 声明变量 i 和 rng
cdef Py_ssize_t i
cdef bitgen_t *rng
# 声明并初始化 uint32_t 类型的一维数组 out
cdef uint32_t[::1] out
# 声明并初始化字符串常量 capsule_name
cdef const char *capsule_name = "BitGenerator"
# 创建 PCG64 对象 x
x = PCG64()
# 初始化长度为 n 的 uint32_t 类型的空数组 out
out = np.empty(n, dtype=np.uint32)
# 获取 PCG64 对象的胶囊(capsule)
capsule = x.capsule
# 检查胶囊的有效性
if not PyCapsule_IsValid(capsule, capsule_name):
raise ValueError("Invalid pointer to anon_func_state")
# 获取胶囊中的指针,转换为 bitgen_t 指针类型赋值给 rng
rng = <bitgen_t *>PyCapsule_GetPointer(capsule, capsule_name)
# 使用 with 语句获取锁并释放 GIL,以便多线程安全生成随机数
with x.lock, nogil:
# 循环调用 bounded_uint 函数生成 n 个位于 lb 和 ub 之间的随机数,并存储到 out 数组中
for i in range(n):
out[i] = bounded_uint(lb, ub, rng)
# 将 out 数组转换为 NumPy ndarray 对象并返回
return np.asarray(out)
.\numpy\numpy\random\_examples\cython\extending_distributions.pyx
#!/usr/bin/env python3
#cython: language_level=3
"""
This file shows how the to use a BitGenerator to create a distribution.
"""
import numpy as np # 导入 NumPy 库
cimport numpy as np # 从 Cython 中导入 NumPy 库
cimport cython # 导入 Cython 声明
from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer
# 从 CPython 中导入相关函数
from libc.stdint cimport uint16_t, uint64_t
# 从 C 标准库中导入整数类型
from numpy.random cimport bitgen_t # 从 NumPy 中导入 bitgen_t 类型
from numpy.random import PCG64 # 从 NumPy 中导入 PCG64 类型
from numpy.random.c_distributions cimport (
random_standard_uniform_fill, random_standard_uniform_fill_f)
# 从 NumPy 中导入随机分布相关函数
@cython.boundscheck(False)
@cython.wraparound(False)
def uniforms(Py_ssize_t n):
"""
Create an array of `n` uniformly distributed doubles.
A 'real' distribution would want to process the values into
some non-uniform distribution
"""
cdef Py_ssize_t i # 声明一个 C 语言风格的 ssize_t 类型变量 i
cdef bitgen_t *rng # 声明一个指向 bitgen_t 结构体的指针 rng
cdef const char *capsule_name = "BitGenerator"
# 声明一个指向字符串常量的指针 capsule_name
cdef double[::1] random_values # 声明一个连续的内存视图,存储双精度浮点数
x = PCG64() # 创建一个 PCG64 类型的随机数生成器对象 x
capsule = x.capsule # 获取生成器对象的胶囊对象
# Optional check that the capsule if from a BitGenerator
if not PyCapsule_IsValid(capsule, capsule_name):
raise ValueError("Invalid pointer to anon_func_state")
# 检查胶囊对象是否有效,否则抛出异常
# Cast the pointer
rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name)
# 将胶囊对象的指针转换为 bitgen_t 指针
random_values = np.empty(n, dtype='float64')
# 创建一个空的 NumPy 数组,存储双精度浮点数
with x.lock, nogil: # 进入无 GIL 的并行区域
for i in range(n): # 循环 n 次
# Call the function
random_values[i] = rng.next_double(rng.state)
# 调用 rng 的 next_double 方法生成随机数
randoms = np.asarray(random_values) # 将 random_values 转换为 NumPy 数组
return randoms # 返回生成的随机数数组
# cython example 2
@cython.boundscheck(False)
@cython.wraparound(False)
def uint10_uniforms(Py_ssize_t n):
"""Uniform 10 bit integers stored as 16-bit unsigned integers"""
cdef Py_ssize_t i # 声明一个 C 语言风格的 ssize_t 类型变量 i
cdef bitgen_t *rng # 声明一个指向 bitgen_t 结构体的指针 rng
cdef const char *capsule_name = "BitGenerator"
# 声明一个指向字符串常量的指针 capsule_name
cdef uint16_t[::1] random_values # 声明一个连续的内存视图,存储 16 位无符号整数
cdef int bits_remaining # 声明一个整数 bits_remaining
cdef int width = 10 # 声明一个整数 width 并赋值为 10
cdef uint64_t buff, mask = 0x3FF # 声明两个 64 位无符号整数并赋初值
x = PCG64() # 创建一个 PCG64 类型的随机数生成器对象 x
capsule = x.capsule # 获取生成器对象的胶囊对象
if not PyCapsule_IsValid(capsule, capsule_name):
raise ValueError("Invalid pointer to anon_func_state")
# 检查胶囊对象是否有效,否则抛出异常
rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name)
# 将胶囊对象的指针转换为 bitgen_t 指针
random_values = np.empty(n, dtype='uint16')
# 创建一个空的 NumPy 数组,存储 16 位无符号整数
# Best practice is to release GIL and acquire the lock
bits_remaining = 0 # 初始化 bits_remaining 为 0
with x.lock, nogil: # 进入无 GIL 的并行区域
for i in range(n): # 循环 n 次
if bits_remaining < width: # 如果剩余位数小于 width
buff = rng.next_uint64(rng.state)
# 调用 rng 的 next_uint64 方法生成 64 位随机数
random_values[i] = buff & mask
# 将 buff 与 mask 进行按位与操作赋值给 random_values[i]
buff >>= width # 右移 buff width 位
randoms = np.asarray(random_values)
# 将 random_values 转换为 NumPy 数组
return randoms # 返回生成的随机数数组
# cython example 3
def uniforms_ex(bit_generator, Py_ssize_t n, dtype=np.float64):
"""
Create an array of `n` uniformly distributed doubles via a "fill" function.
A 'real' distribution would want to process the values into
some non-uniform distribution
Parameters
----------
bit_generator: BitGenerator instance
n: int
Output vector length
dtype: {str, dtype}, optional
Desired dtype, either 'd' (or 'float64') or 'f' (or 'float32'). The
default dtype value is 'd'
"""
cdef Py_ssize_t i
cdef bitgen_t *rng
cdef const char *capsule_name = "BitGenerator"
cdef np.ndarray randoms
# 获取保存 BitGenerator 的 PyCapsule 对象
capsule = bit_generator.capsule
# 可选:验证该 PyCapsule 对象是否指向一个 BitGenerator
if not PyCapsule_IsValid(capsule, capsule_name):
raise ValueError("Invalid pointer to anon_func_state")
# 将 PyCapsule 指针转换为 bitgen_t 类型的指针
rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name)
# 根据指定的 dtype 创建一个空的 numpy 数组
_dtype = np.dtype(dtype)
randoms = np.empty(n, dtype=_dtype)
# 根据 dtype 类型进行不同的随机数生成操作
if _dtype == np.float32:
# 使用互斥锁保护的情况下,调用 C 函数生成 float32 类型的随机数
with bit_generator.lock:
random_standard_uniform_fill_f(rng, n, <float*>np.PyArray_DATA(randoms))
elif _dtype == np.float64:
# 使用互斥锁保护的情况下,调用 C 函数生成 float64 类型的随机数
with bit_generator.lock:
random_standard_uniform_fill(rng, n, <double*>np.PyArray_DATA(randoms))
else:
# 若不支持的 dtype 类型,则抛出错误
raise TypeError('Unsupported dtype %r for random' % _dtype)
# 返回生成的随机数数组
return randoms
.\numpy\numpy\random\_examples\numba\extending.py
# 导入必要的库:numpy 和 numba
import numpy as np
import numba as nb
# 从 numpy.random 中导入 PCG64 随机数生成器
from numpy.random import PCG64
# 从 timeit 中导入 timeit 函数
from timeit import timeit
# 创建 PCG64 随机数生成器的实例
bit_gen = PCG64()
# 获取 PCG64 随机数生成器的下一个双精度随机数方法
next_d = bit_gen.cffi.next_double
# 获取 PCG64 随机数生成器的状态地址方法
state_addr = bit_gen.cffi.state_address
# 定义生成正态分布随机数的函数,使用 Numba 进行加速编译
def normals(n, state):
out = np.empty(n)
for i in range((n + 1) // 2):
# 生成两个均匀分布随机数,并转换为标准正态分布随机数
x1 = 2.0 * next_d(state) - 1.0
x2 = 2.0 * next_d(state) - 1.0
r2 = x1 * x1 + x2 * x2
# 如果随机数不在单位圆内则重新生成
while r2 >= 1.0 or r2 == 0.0:
x1 = 2.0 * next_d(state) - 1.0
x2 = 2.0 * next_d(state) - 1.0
r2 = x1 * x1 + x2 * x2
f = np.sqrt(-2.0 * np.log(r2) / r2)
out[2 * i] = f * x1
if 2 * i + 1 < n:
out[2 * i + 1] = f * x2
return out
# 使用 Numba 加速编译 normals 函数
normalsj = nb.jit(normals, nopython=True)
# 设定生成随机数的个数
n = 10000
# 定义使用 Numba 加速编译后的生成正态分布随机数的函数
def numbacall():
return normalsj(n, state_addr)
# 创建 NumPy 的 PCG64 随机数生成器实例
rg = np.random.Generator(PCG64())
# 定义使用 NumPy 生成正态分布随机数的函数
def numpycall():
return rg.normal(size=n)
# 检查两种生成随机数的函数输出的形状是否一致
r1 = numbacall()
r2 = numpycall()
assert r1.shape == (n,)
assert r1.shape == r2.shape
# 测试 Numba 加速编译后的生成正态分布随机数函数的性能
t1 = timeit(numbacall, number=1000)
print(f'{t1:.2f} secs for {n} PCG64 (Numba/PCG64) gaussian randoms')
# 测试 NumPy 生成正态分布随机数函数的性能
t2 = timeit(numpycall, number=1000)
print(f'{t2:.2f} secs for {n} PCG64 (NumPy/PCG64) gaussian randoms')
# 示例 2
# 获取 PCG64 随机数生成器的下一个 32 位无符号整数随机数方法
next_u32 = bit_gen.ctypes.next_uint32
# 获取 PCG64 随机数生成器的状态
ctypes_state = bit_gen.ctypes.state
# 使用 Numba 加速编译定义的函数,生成在给定范围内的随机数
@nb.jit(nopython=True)
def bounded_uint(lb, ub, state):
# 计算用于掩码的值
mask = delta = ub - lb
mask |= mask >> 1
mask |= mask >> 2
mask |= mask >> 4
mask |= mask >> 8
mask |= mask >> 16
# 生成随机数,并确保在指定范围内
val = next_u32(state) & mask
while val > delta:
val = next_u32(state) & mask
return lb + val
# 打印在指定范围内生成的随机数
print(bounded_uint(323, 2394691, ctypes_state.value))
# 使用 Numba 加速编译定义的函数,生成多个在给定范围内的随机数
@nb.jit(nopython=True)
def bounded_uints(lb, ub, n, state):
out = np.empty(n, dtype=np.uint32)
for i in range(n):
out[i] = bounded_uint(lb, ub, state)
# 生成一定数量的在指定范围内的随机数
bounded_uints(323, 2394691, 10000000, ctypes_state.value)
.\numpy\numpy\random\_examples\numba\extending_distributions.py
"""
在这个示例中,构建所需的库需要NumPy的源代码分发或NumPy的git存储库的克隆,因为distributions.c没有包含在二进制分发中。
在*nix系统上,在numpy/random/src/distributions目录中执行以下操作:
export ${PYTHON_VERSION}=3.8 # Python版本
export PYTHON_INCLUDE=#Python包含文件夹的路径,通常是 \
${PYTHON_HOME}/include/python${PYTHON_VERSION}m
export NUMPY_INCLUDE=#NumPy包含文件夹的路径,通常是 \
${PYTHON_HOME}/lib/python${PYTHON_VERSION}/site-packages/numpy/_core/include
gcc -shared -o libdistributions.so -fPIC distributions.c \
-I${NUMPY_INCLUDE} -I${PYTHON_INCLUDE}
mv libdistributions.so ../../_examples/numba/
在Windows系统上:
rem PYTHON_HOME和PYTHON_VERSION需要根据具体设置调整,这里是一个示例
set PYTHON_HOME=c:\Anaconda
set PYTHON_VERSION=38
cl.exe /LD .\distributions.c -DDLL_EXPORT \
-I%PYTHON_HOME%\lib\site-packages\numpy\_core\include \
-I%PYTHON_HOME%\include %PYTHON_HOME%\libs\python%PYTHON_VERSION%.lib
move distributions.dll ../../_examples/numba/
"""
import os # 导入操作系统接口模块
import numba as nb # 导入Numba模块
import numpy as np # 导入NumPy模块
from cffi import FFI # 从cffi模块导入FFI类
from numpy.random import PCG64 # 从NumPy的随机模块中导入PCG64随机数生成器
ffi = FFI() # 创建一个FFI对象
if os.path.exists('./distributions.dll'): # 检查当前路径下是否存在'distributions.dll'
lib = ffi.dlopen('./distributions.dll') # 使用FFI加载'distributions.dll'库
elif os.path.exists('./libdistributions.so'): # 如果不存在'distributions.dll',则检查是否存在'libdistributions.so'
lib = ffi.dlopen('./libdistributions.so') # 使用FFI加载'libdistributions.so'库
else:
raise RuntimeError('Required DLL/so file was not found.') # 如果都不存在,则抛出运行时错误
ffi.cdef("""
double random_standard_normal(void *bitgen_state);
""")
# 定义一个C函数原型,声明'read_random_standard_normal'函数,接收一个void*参数并返回double类型
x = PCG64() # 创建一个PCG64随机数生成器对象
xffi = x.cffi # 获取PCG64对象的CFFI接口
bit_generator = xffi.bit_generator # 获取PCG64对象的bit_generator属性
random_standard_normal = lib.random_standard_normal # 将从库中加载的random_standard_normal函数赋值给变量
def normals(n, bit_generator):
# 定义一个函数normals,接收n和bit_generator参数
out = np.empty(n) # 创建一个大小为n的空NumPy数组out
for i in range(n):
out[i] = random_standard_normal(bit_generator) # 使用库中的random_standard_normal函数填充数组out
return out # 返回填充好的数组out
normalsj = nb.jit(normals, nopython=True) # 使用Numba对normals函数进行即时编译,要求nopython模式
# Numba需要一个void*指针的内存地址
# 也可以从x.ctypes.bit_generator.value获取地址
bit_generator_address = int(ffi.cast('uintptr_t', bit_generator)) # 将bit_generator转换为uintptr_t类型的整数地址
norm = normalsj(1000, bit_generator_address) # 调用编译后的normalsj函数,传入参数1000和bit_generator_address
print(norm[:12]) # 打印数组norm的前12个元素
.\numpy\numpy\random\_generator.pyi
# 导入必要的模块和类
from collections.abc import Callable
from typing import Any, overload, TypeVar, Literal
# 导入 NumPy 库及其子模块
import numpy as np
from numpy import (
dtype,
float32,
float64,
int8,
int16,
int32,
int64,
int_,
uint,
uint8,
uint16,
uint32,
uint64,
)
from numpy.random import BitGenerator, SeedSequence
from numpy._typing import (
ArrayLike,
NDArray,
_ArrayLikeFloat_co,
_ArrayLikeInt_co,
_DoubleCodes,
_DTypeLikeBool,
_DTypeLikeInt,
_DTypeLikeUInt,
_Float32Codes,
_Float64Codes,
_FloatLike_co,
_Int8Codes,
_Int16Codes,
_Int32Codes,
_Int64Codes,
_IntCodes,
_ShapeLike,
_SingleCodes,
_SupportsDType,
_UInt8Codes,
_UInt16Codes,
_UInt32Codes,
_UInt64Codes,
_UIntCodes,
)
# 定义一个类型变量用于 NumPy 数组
_ArrayType = TypeVar("_ArrayType", bound=NDArray[Any])
# 定义支持 float32 类型的多种类型
_DTypeLikeFloat32 = (
dtype[float32]
| _SupportsDType[dtype[float32]]
| type[float32]
| _Float32Codes
| _SingleCodes
)
# 定义支持 float64 类型的多种类型
_DTypeLikeFloat64 = (
dtype[float64]
| _SupportsDType[dtype[float64]]
| type[float]
| type[float64]
| _Float64Codes
| _DoubleCodes
)
# 定义 Generator 类,用于生成随机数
class Generator:
# 初始化方法,接受一个比特生成器对象作为参数
def __init__(self, bit_generator: BitGenerator) -> None: ...
# 返回对象的字符串表示形式
def __repr__(self) -> str: ...
# 返回对象的字符串表示形式
def __str__(self) -> str: ...
# 获取对象的序列化状态
def __getstate__(self) -> None: ...
# 设置对象的序列化状态
def __setstate__(self, state: dict[str, Any] | None) -> None: ...
# 用于 pickle 模块序列化和反序列化的特殊方法
def __reduce__(self) -> tuple[
Callable[[BitGenerator], Generator],
tuple[BitGenerator],
None]: ...
# 返回比特生成器对象
@property
def bit_generator(self) -> BitGenerator: ...
# 生成指定数量的 Generator 对象列表
def spawn(self, n_children: int) -> list[Generator]: ...
# 生成指定长度的随机字节串
def bytes(self, length: int) -> bytes: ...
# 生成标准正态分布的随机数,支持多种重载形式
@overload
def standard_normal(
self,
size: None = ...,
dtype: _DTypeLikeFloat32 | _DTypeLikeFloat64 = ...,
out: None = ...,
) -> float: ...
@overload
def standard_normal(
self,
size: _ShapeLike = ...,
) -> NDArray[float64]: ...
@overload
def standard_normal(
self,
*,
out: NDArray[float64] = ...,
) -> NDArray[float64]: ...
@overload
def standard_normal(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat32 = ...,
out: None | NDArray[float32] = ...,
) -> NDArray[float32]: ...
@overload
def standard_normal(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat64 = ...,
out: None | NDArray[float64] = ...,
) -> NDArray[float64]: ...
# 返回数组 x 的随机排列,支持多种重载形式
@overload
def permutation(self, x: int, axis: int = ...) -> NDArray[int64]: ...
@overload
def permutation(self, x: ArrayLike, axis: int = ...) -> NDArray[Any]: ...
# 更多的 permutation 方法重载定义省略
def standard_exponential( # type: ignore[misc]
self,
size: None = ...,
dtype: _DTypeLikeFloat32 | _DTypeLikeFloat64 = ...,
method: Literal["zig", "inv"] = ...,
out: None = ...,
) -> float:
...
@overload
def standard_exponential(
self,
size: _ShapeLike = ...,
) -> NDArray[float64]:
...
@overload
def standard_exponential(
self,
*,
out: NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def standard_exponential(
self,
size: _ShapeLike = ...,
*,
method: Literal["zig", "inv"] = ...,
out: None | NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def standard_exponential(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat32 = ...,
method: Literal["zig", "inv"] = ...,
out: None | NDArray[float32] = ...,
) -> NDArray[float32]:
...
@overload
def standard_exponential(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat64 = ...,
method: Literal["zig", "inv"] = ...,
out: None | NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def random( # type: ignore[misc]
self,
size: None = ...,
dtype: _DTypeLikeFloat32 | _DTypeLikeFloat64 = ...,
out: None = ...,
) -> float:
...
@overload
def random(
self,
*,
out: NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def random(
self,
size: _ShapeLike = ...,
*,
out: None | NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def random(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat32 = ...,
out: None | NDArray[float32] = ...,
) -> NDArray[float32]:
...
@overload
def random(
self,
size: _ShapeLike = ...,
dtype: _DTypeLikeFloat64 = ...,
out: None | NDArray[float64] = ...,
) -> NDArray[float64]:
...
@overload
def beta(
self,
a: _FloatLike_co,
b: _FloatLike_co,
size: None = ...,
) -> float: # type: ignore[misc]
...
@overload
def beta(
self, a: _ArrayLikeFloat_co, b: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]:
...
@overload
def exponential(self, scale: _FloatLike_co = ..., size: None = ...) -> float: # type: ignore[misc]
...
@overload
def exponential(
self, scale: _ArrayLikeFloat_co = ..., size: None | _ShapeLike = ...
) -> NDArray[float64]:
...
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
) -> int:
...
@overload
# 注释:
定义了一系列重载函数 `standard_exponential`, `random`, `beta`, `exponential`, `integers`,用于生成不同分布(指数分布、随机分布、贝塔分布、指数分布和整数)的随机数或随机数组。每个函数支持多个参数组合,返回不同的类型和形状的随机数或数组。
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: type[bool] = ...,
endpoint: bool = ...,
) -> bool: ...
# 定义 `integers` 方法,用于生成整数序列
# - `low`:最低值,生成的整数序列的下限
# - `high`:最高值,生成的整数序列的上限(可选)
# - `size`:生成整数序列的大小(可选)
# - `dtype`:生成整数序列的数据类型,默认为布尔类型(可选)
# - `endpoint`:如果为 True,生成的整数序列包括 `high` 值;如果为 False,则不包括 `high` 值(可选)
# - 返回类型为布尔类型的整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: type[np.bool] = ...,
endpoint: bool = ...,
) -> np.bool: ...
# 定义 `integers` 方法的重载,用于生成布尔类型的整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `np.bool`
# - 返回类型为 NumPy 中的布尔类型的整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: type[int] = ...,
endpoint: bool = ...,
) -> int: ...
# 定义 `integers` 方法的重载,用于生成普通整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为整数类型
# - 返回类型为普通整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[uint8] | type[uint8] | _UInt8Codes | _SupportsDType[dtype[uint8]] = ...,
endpoint: bool = ...,
) -> uint8: ...
# 定义 `integers` 方法的重载,用于生成无符号8位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `uint8`
# - 返回类型为无符号8位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[uint16] | type[uint16] | _UInt16Codes | _SupportsDType[dtype[uint16]] = ...,
endpoint: bool = ...,
) -> uint16: ...
# 定义 `integers` 方法的重载,用于生成无符号16位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `uint16`
# - 返回类型为无符号16位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[uint32] | type[uint32] | _UInt32Codes | _SupportsDType[dtype[uint32]] = ...,
endpoint: bool = ...,
) -> uint32: ...
# 定义 `integers` 方法的重载,用于生成无符号32位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `uint32`
# - 返回类型为无符号32位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[uint] | type[uint] | _UIntCodes | _SupportsDType[dtype[uint]] = ...,
endpoint: bool = ...,
) -> uint: ...
# 定义 `integers` 方法的重载,用于生成无符号整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `uint`
# - 返回类型为无符号整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[uint64] | type[uint64] | _UInt64Codes | _SupportsDType[dtype[uint64]] = ...,
endpoint: bool = ...,
) -> uint64: ...
# 定义 `integers` 方法的重载,用于生成无符号64位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `uint64`
# - 返回类型为无符号64位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int8] | type[int8] | _Int8Codes | _SupportsDType[dtype[int8]] = ...,
endpoint: bool = ...,
) -> int8: ...
# 定义 `integers` 方法的重载,用于生成有符号8位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `int8`
# - 返回类型为有符号8位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int16] | type[int16] | _Int16Codes | _SupportsDType[dtype[int16]] = ...,
endpoint: bool = ...,
) -> int16: ...
# 定义 `integers` 方法的重载,用于生成有符号16位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `int16`
# - 返回类型为有符号16位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int32] | type[int32] | _Int32Codes | _SupportsDType[dtype[int32]] = ...,
endpoint: bool = ...,
) -> int32: ...
# 定义 `integers` 方法的重载,用于生成有符号32位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `int32`
# - 返回类型为有符号32位整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int] | type[int] | _IntCodes | _SupportsDType[dtype[int]] = ...,
endpoint: bool = ...,
) -> int: ...
# 定义 `integers` 方法的重载,用于生成普通有符号整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为普通整数类型
# - 返回类型为普通有符号整数序列
@overload
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int64] | type[int64] | _Int64Codes | _SupportsDType[dtype[int64]] = ...,
endpoint: bool = ...,
) -> int64: ...
# 定义 `integers` 方法的重载,用于生成有符号64位整数序列
# - 参数与前述方法相同,只是 `dtype` 指定为 `int64`
# - 返回类型为有符
def integers( # type: ignore[misc]
self,
low: int,
high: None | int = ...,
size: None = ...,
dtype: dtype[int_] | type[int] | type[int_] | _IntCodes | _SupportsDType[dtype[int_]] = ...,
endpoint: bool = ...,
) -> int_: ...
# 生成一个方法 integers 的重载声明,返回一个 uint16 类型的 NumPy 数组
def integers(
self,
low: _ArrayLikeInt_co,
high: None | _ArrayLikeInt_co = ...,
size: None | _ShapeLike = ...,
dtype: dtype[uint16] | type[uint16] | _UInt16Codes | _SupportsDType[dtype[uint16]] = ...,
endpoint: bool = ...,
) -> NDArray[uint16]: ...
# 生成一个方法 integers 的重载声明,返回一个 uint32 类型的 NumPy 数组
@overload
def integers(
self,
low: _ArrayLikeInt_co,
high: None | _ArrayLikeInt_co = ...,
size: None | _ShapeLike = ...,
dtype: dtype[uint32] | type[uint32] | _UInt32Codes | _SupportsDType[dtype[uint32]] = ...,
endpoint: bool = ...,
) -> NDArray[uint32]: ...
# 生成一个方法 integers 的重载声明,返回一个 uint64 类型的 NumPy 数组
@overload
def integers(
self,
low: _ArrayLikeInt_co,
high: None | _ArrayLikeInt_co = ...,
size: None | _ShapeLike = ...,
dtype: dtype[uint64] | type[uint64] | _UInt64Codes | _SupportsDType[dtype[uint64]] = ...,
endpoint: bool = ...,
) -> NDArray[uint64]: ...
# 生成一个方法 integers 的重载声明,返回一个 int 类型的 NumPy 数组
@overload
def integers(
self,
low: _ArrayLikeInt_co,
high: None | _ArrayLikeInt_co = ...,
size: None | _ShapeLike = ...,
dtype: dtype[int_] | type[int] | type[int_] | _IntCodes | _SupportsDType[dtype[int_]] = ...,
endpoint: bool = ...,
) -> NDArray[int_]: ...
# 生成一个方法 integers 的重载声明,返回一个 uint 类型的 NumPy 数组
@overload
def integers(
self,
low: _ArrayLikeInt_co,
high: None | _ArrayLikeInt_co = ...,
size: None | _ShapeLike = ...,
dtype: dtype[uint] | type[uint] | _UIntCodes | _SupportsDType[dtype[uint]] = ...,
endpoint: bool = ...,
) -> NDArray[uint]: ...
# TODO: 使用一个 TypeVar _T 来避免返回任何类型的结果?应该是 int -> NDArray[int64],ArrayLike[_T] -> _T | NDArray[Any]
# 生成一个方法 choice 的重载声明,返回一个 int 类型的值
@overload
def choice(
self,
a: int,
size: None = ...,
replace: bool = ...,
p: None | _ArrayLikeFloat_co = ...,
axis: int = ...,
shuffle: bool = ...,
) -> int: ...
# 生成一个方法 choice 的重载声明,返回一个 int64 类型的 NumPy 数组
@overload
def choice(
self,
a: int,
size: _ShapeLike = ...,
replace: bool = ...,
p: None | _ArrayLikeFloat_co = ...,
axis: int = ...,
shuffle: bool = ...,
) -> NDArray[int64]: ...
# 生成一个方法 choice 的重载声明,返回一个任意类型的结果
@overload
def choice(
self,
a: ArrayLike,
size: None = ...,
replace: bool = ...,
p: None | _ArrayLikeFloat_co = ...,
axis: int = ...,
shuffle: bool = ...,
) -> Any: ...
# 生成一个方法 choice 的重载声明,返回一个任意类型的 NumPy 数组
@overload
def choice(
self,
a: ArrayLike,
size: _ShapeLike = ...,
replace: bool = ...,
p: None | _ArrayLikeFloat_co = ...,
axis: int = ...,
shuffle: bool = ...,
) -> NDArray[Any]: ...
# 生成一个方法 uniform 的重载声明,返回一个浮点数类型的值
@overload
def uniform(
self,
low: _FloatLike_co = ...,
high: _FloatLike_co = ...,
size: None = ...,
) -> float: ...
@overload
def uniform(
self,
low: _ArrayLikeFloat_co = ...,
high: _ArrayLikeFloat_co = ...,
size: None | _ShapeLike = ...,
) -> NDArray[float64]:
"""定义一个方法重载,用于生成均匀分布的随机数。
Parameters:
- low: 最小值,可以是单个浮点数或浮点数数组
- high: 最大值,可以是单个浮点数或浮点数数组
- size: 数组形状,可以是 None 或者形状描述
Returns:
- NDArray[float64]: 生成的均匀分布的随机数数组
"""
@overload
def normal(
self,
loc: _FloatLike_co = ...,
scale: _FloatLike_co = ...,
size: None = ...,
) -> float: # type: ignore[misc]
"""定义一个方法重载,用于生成正态分布的随机数(返回单个浮点数)。
Parameters:
- loc: 正态分布的均值,可以是单个浮点数
- scale: 正态分布的标准差,可以是单个浮点数
- size: 数组形状,可以是 None
Returns:
- float: 生成的正态分布的随机数
"""
@overload
def normal(
self,
loc: _ArrayLikeFloat_co = ...,
scale: _ArrayLikeFloat_co = ...,
size: None | _ShapeLike = ...,
) -> NDArray[float64]:
"""定义一个方法重载,用于生成正态分布的随机数(返回浮点数数组)。
Parameters:
- loc: 正态分布的均值,可以是单个浮点数或浮点数数组
- scale: 正态分布的标准差,可以是单个浮点数或浮点数数组
- size: 数组形状,可以是 None 或者形状描述
Returns:
- NDArray[float64]: 生成的正态分布的随机数数组
"""
(以下类似地注释其他函数重载的定义,保留格式一致性和详细解释)
@overload
def noncentral_chisquare(
self, df: _ArrayLikeFloat_co, nonc: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:noncentral_chisquare 方法的类型签名
# 接受 df 和 nonc 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def standard_t(self, df: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:standard_t 方法的类型签名
# 接受 df 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def standard_t(
self, df: _ArrayLikeFloat_co, size: None = ...
) -> NDArray[float64]: ...
# 方法重载定义:standard_t 方法的类型签名
# 接受 df 参数作为数组或类似数组的浮点数,size 参数可以是 None,返回一个浮点数数组
@overload
def standard_t(
self, df: _ArrayLikeFloat_co, size: _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:standard_t 方法的类型签名
# 接受 df 参数作为数组或类似数组的浮点数,size 参数可以是形状对象或 None,返回一个浮点数数组
@overload
def vonmises(self, mu: _FloatLike_co, kappa: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:vonmises 方法的类型签名
# 接受 mu 和 kappa 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def vonmises(
self, mu: _ArrayLikeFloat_co, kappa: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:vonmises 方法的类型签名
# 接受 mu 和 kappa 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def pareto(self, a: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:pareto 方法的类型签名
# 接受 a 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def pareto(
self, a: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:pareto 方法的类型签名
# 接受 a 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def weibull(self, a: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:weibull 方法的类型签名
# 接受 a 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def weibull(
self, a: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:weibull 方法的类型签名
# 接受 a 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def power(self, a: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:power 方法的类型签名
# 接受 a 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def power(
self, a: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载定义:power 方法的类型签名
# 接受 a 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def standard_cauchy(self, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载定义:standard_cauchy 方法的类型签名
# 接受 size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def standard_cauchy(self, size: _ShapeLike = ...) -> NDArray[float64]: ...
# 方法重载定义:standard_cauchy 方法的类型签名
# 接受 size 参数可以是形状对象或 None,返回一个浮点数数组
@overload
def laplace(
self,
loc: _FloatLike_co = ...,
scale: _FloatLike_co = ...,
size: None = ...,
) -> float: ... # type: ignore[misc]
# 方法重载定义:laplace 方法的类型签名
# 接受 loc 和 scale 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def laplace(
self,
loc: _ArrayLikeFloat_co = ...,
scale: _ArrayLikeFloat_co = ...,
size: None | _ShapeLike = ...,
) -> NDArray[float64]: ...
# 方法重载定义:laplace 方法的类型签名
# 接受 loc 和 scale 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def gumbel(
self,
loc: _FloatLike_co = ...,
scale: _FloatLike_co = ...,
size: None = ...,
) -> float: ... # type: ignore[misc]
# 方法重载定义:gumbel 方法的类型签名
# 接受 loc 和 scale 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某些杂项警告
@overload
def gumbel(
self,
loc: _ArrayLikeFloat_co = ...,
scale: _ArrayLikeFloat_co = ...,
size: None | _ShapeLike = ...,
) -> NDArray[float64]: ...
# 方法重载定义:gumbel 方法的类型签名
# 接受 loc 和 scale 参数作为数组或类似数组的浮点数,size 参数可以是 None 或者形状对象,返回一个浮点数数组
@overload
def logistic(
self,
loc: _FloatLike_co = ...,
scale: _FloatLike_co = ...,
size: None = ...,
) -> float: ... # type: ignore[misc]
# 方法重载定义:logistic 方法的类型签名
# 接受 loc 和 scale 参数作为浮点数,size 参数可以是 None,返回一个浮点数
# 标注类型忽略某
) -> float: ... # type: ignore[misc]
# 声明一个方法签名,该方法返回一个浮点数,忽略类型检查警告
@overload
def lognormal(
self,
mean: _ArrayLikeFloat_co = ...,
sigma: _ArrayLikeFloat_co = ...,
size: None | _ShapeLike = ...,
) -> NDArray[float64]: ...
# 方法重载注解,定义了 lognormal 方法的不同参数组合及其返回类型
@overload
def rayleigh(self, scale: _FloatLike_co = ..., size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载注解,定义了 rayleigh 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def rayleigh(
self, scale: _ArrayLikeFloat_co = ..., size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载注解,定义了 rayleigh 方法的不同参数组合及其返回类型
@overload
def wald(self, mean: _FloatLike_co, scale: _FloatLike_co, size: None = ...) -> float: ... # type: ignore[misc]
# 方法重载注解,定义了 wald 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def wald(
self, mean: _ArrayLikeFloat_co, scale: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 方法重载注解,定义了 wald 方法的不同参数组合及其返回类型
@overload
def triangular(
self,
left: _FloatLike_co,
mode: _FloatLike_co,
right: _FloatLike_co,
size: None = ...,
) -> float: ...
# 方法重载注解,定义了 triangular 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def triangular(
self,
left: _ArrayLikeFloat_co,
mode: _ArrayLikeFloat_co,
right: _ArrayLikeFloat_co,
size: None | _ShapeLike = ...,
) -> NDArray[float64]: ...
# 方法重载注解,定义了 triangular 方法的不同参数组合及其返回类型
@overload
def binomial(self, n: int, p: _FloatLike_co, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 binomial 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def binomial(
self, n: _ArrayLikeInt_co, p: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 方法重载注解,定义了 binomial 方法的不同参数组合及其返回类型
@overload
def negative_binomial(self, n: _FloatLike_co, p: _FloatLike_co, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 negative_binomial 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def negative_binomial(
self, n: _ArrayLikeFloat_co, p: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 方法重载注解,定义了 negative_binomial 方法的不同参数组合及其返回类型
@overload
def poisson(self, lam: _FloatLike_co = ..., size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 poisson 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def poisson(
self, lam: _ArrayLikeFloat_co = ..., size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 方法重载注解,定义了 poisson 方法的不同参数组合及其返回类型
@overload
def zipf(self, a: _FloatLike_co, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 zipf 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def zipf(
self, a: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 方法重载注解,定义了 zipf 方法的不同参数组合及其返回类型
@overload
def geometric(self, p: _FloatLike_co, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 geometric 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def geometric(
self, p: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 方法重载注解,定义了 geometric 方法的不同参数组合及其返回类型
@overload
def hypergeometric(self, ngood: int, nbad: int, nsample: int, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 hypergeometric 方法的不同参数组合及其返回类型,忽略类型检查警告
@overload
def hypergeometric(
self,
ngood: _ArrayLikeInt_co,
nbad: _ArrayLikeInt_co,
nsample: _ArrayLikeInt_co,
size: None | _ShapeLike = ...,
) -> NDArray[int64]: ...
# 方法重载注解,定义了 hypergeometric 方法的不同参数组合及其返回类型
@overload
def logseries(self, p: _FloatLike_co, size: None = ...) -> int: ... # type: ignore[misc]
# 方法重载注解,定义了 logseries 方法的不同参数组合及其返回类型,忽略类型检查警告
# 定义 logseries 方法,生成服从对数级数分布的随机整数数组
def logseries(
self, p: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 定义 multivariate_normal 方法,生成多变量正态分布的随机数数组
def multivariate_normal(
self,
mean: _ArrayLikeFloat_co,
cov: _ArrayLikeFloat_co,
size: None | _ShapeLike = ...,
check_valid: Literal["warn", "raise", "ignore"] = ...,
tol: float = ...,
*,
method: Literal["svd", "eigh", "cholesky"] = ...,
) -> NDArray[float64]: ...
# 定义 multinomial 方法,生成多项分布的随机整数数组
def multinomial(
self, n: _ArrayLikeInt_co,
pvals: _ArrayLikeFloat_co,
size: None | _ShapeLike = ...
) -> NDArray[int64]: ...
# 定义 multivariate_hypergeometric 方法,生成多元超几何分布的随机整数数组
def multivariate_hypergeometric(
self,
colors: _ArrayLikeInt_co,
nsample: int,
size: None | _ShapeLike = ...,
method: Literal["marginals", "count"] = ...,
) -> NDArray[int64]: ...
# 定义 dirichlet 方法,生成 Dirichlet 分布的随机数数组
def dirichlet(
self, alpha: _ArrayLikeFloat_co, size: None | _ShapeLike = ...
) -> NDArray[float64]: ...
# 定义 permuted 方法,对数组进行轴向排列,并返回排列后的新数组
def permuted(
self, x: ArrayLike, *, axis: None | int = ..., out: None | NDArray[Any] = ...
) -> NDArray[Any]: ...
# 定义 shuffle 方法,对数组进行原地乱序操作
def shuffle(self, x: ArrayLike, axis: int = ...) -> None: ...
# 定义一个函数 default_rng,用于创建一个随机数生成器对象
def default_rng(
# 函数参数 seed 可以接受以下类型的值:
seed: None | _ArrayLikeInt_co | SeedSequence | BitGenerator | Generator = ...
) -> Generator:
# 函数返回一个 Generator 对象,用于生成随机数
...