#random #python #interop #behavior

nightly pyrand

纯Rust实现Python的random模块,具有兼容的PRNG行为:使用等效值进行播种将产生相同的PRNG输出

2个版本

0.1.1 2024年2月4日
0.1.0 2024年2月4日

#1242 in 算法

每月21次下载

MIT/Apache

31KB
562

pyrand

纯Rust实现Python的random模块(部分)的PRNG行为兼容:使用等效值进行播种将产生相同的PRNG输出。因此运行

import random
rng = random.Random("Pizza")
rng.choices(range(20), k=5)

将产生 [3, 3, 15, 2, 16] 和运行等效的

use pyrand::{PyMt19937, PySeedable, RandomChoiceIterator};
let rng = &mut PyMt19937::py_seed("Pizza");
assert_eq!((0..20).choose(rng).take(5).collect::<Vec<_>>(), vec![3, 3, 15, 2, 16]);

也将产生 [3, 3, 15, 2, 16]

这看起来很酷。为什么这必须是一个东西?

假设您已经编写了一些使用(伪)随机数的Python代码,例如

import random
random.seed(input("Enter seed: "))
# run some computations using random numbers
...
result = random.random()

print(f"Your result is: {result}")

并且您的用户以某种方式依赖于该结果。那么,如果用户提供了相同的输入,您的应用程序必须始终返回相同的确切值。这意味着您与Python及其当前的 random 实现紧密耦合。

我确实遇到了一些Python代码中存在这种情况的不幸情况。我想重写这段代码,但在没有同时引入Python来处理PRNG部分的情况下(或者静态链接CPython的部分等)根本无法实现 - 这会杀死整个重写。所以长话短说:我在Rust中重新实现了Python随机数生成代码的核心功能,确保两个实现之间保持一致的输出。

如果您确实需要为我尚未实现的一些函数提供此类兼容性,请随意实现它们并提交一个拉取请求 - 或者提交GitHub仓库的一个问题。

rand支持

有一些(可选)对rand特质的实现,但它们可能在基本内部生成器之上重新实现了某些“本地”可用的生成器,并且以与Python中实现不同的方式实现。这意味着如果您使用生成器的rand接口,则必须验证您实际上是否获得了特定情况的匹配输出。

实现细节

实现基于 _randommodule.crandom.py,我尽量保留了大部分函数和变量名等。基本算法是 32位梅森旋转算法(MT19937)

依赖项

约1MB
约25K SLoC